offer直通车(二)之数据结构和算法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013234928/article/details/89416844

算法

一、排序

排序算法参考

排序算法参考

排序的稳定性和复杂度

稳定:
​ 冒泡排序(bubble sort) — O(n2)
​ 插入排序(insertion sort)— O(n2)
​ 归并排序 (merge sort)— O(n log n); 需要 O(n) 额外存储空间
​ 二叉树排序(Binary tree sort) — O(nlogn); 需要 O(n) 额外存储空间
​ 计数排序 (counting sort) — O(n+k); 需要 O(n+k) 额外存储空间,k为序列中Max-Min+1
​ 桶排序 (bucket sort)— O(n); 需要 O(k) 额外存储空间

不稳定:
​ 选择排序(selection sort)— O(n2)
​ 快速排序(quicksort)— O(nlogn) 平均时间, O(n2) 最坏情况; 对于大的、乱序串列一般认为是最快的已知排序
​ 堆排序 (heapsort)— O(nlogn)
​ 希尔排序 (shell sort)— O(nlogn)
​ 基数排序(radix sort)— O(n·k); 需要 O(n) 额外存储空间 (K为特征个数)

  • 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面;
  • 不稳定:如果a原本在b的前面,而a=b,排序之后a可能会出现在b的后面;

冒泡排序

依次比较相邻的两个数,将小数放在前面,大数放在后面

public void function sortArray(int[] arr) {
    for (int i = 0; i < arr.length-1;i++) {
        for(int j = 0 ; j < arr.length-1;j++){
            if(arr[j] > arr[j+1]){
                int temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
}

插入排序

将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据

 private static void insertSort(int[] sort) {   
      for (int i = 1; i < sort.length; i++) {   
          int index = i - 1;   
          int temp = sort[i];   
   		  while (index >= 0 && sort[index] > temp) {   
    		 sort[index + 1] = sort[index];   
     		 index--;   
   		  }   
   		  sort[index + 1] = temp;   
	  }
 }

快速排序

  1. 首先区间采用以找到第一个数为基准数base,
  2. 从左向右,找到比base值大的值,从右至左,找到比base基准值小的值;替换这两个数,循环直到基准数base左边小右边大为止,返回最后一步索引;
  3. 以索引划分区间,递归;重复 第二步
private static void quickSort(int[] array ,int start, int end) {
    if (start < end) {
        int baseIndex = partition(array,start, end);// 分区操作,找到基准值,返回索引
        if(start<baseIndex) {
            quickSort(array,start, baseIndex);// 再次递归
        }
        if(baseIndex<end) {
            quickSort(array,baseIndex + 1, end);// 再次递归
        }


    }
}
private static int partition(int[] array,int start, int end) {
    int pivot = array[start];// 假设start位置的数是基准值
    int i = start;
    int j = end;
    while (i < j) {
        //从左向右,找到比base基准值大的值
        while (array[i] < pivot) {
            i++;
        }
        //从右至左,找到比base基准值小的值
        while (array[j] > pivot) {
            j--;
        }
        if (i < j) {
            swap(array,i, j);
            i++;j--;
        }
    }
    return j;
}
//交换
private static void swap(int[] array,int i,int j){
    int temp=array[i];
    array[i]=array[j];
    array[j]=temp;
}


二、查找算法

1、顺序查找

2、二分查找

//二分查找,递归版本
public class BinarySearch2{
    //递归查找
    public static int binarysearch(int[] a,int value,int low,int high){
        int mid = (low + high)/2;
        if(value == a[mid]){
            return mid;
        }else if(value < a[mid])
            return binarysearch(a,value,low,mid - 1);
        }else if(value > a[mid])
            return binarysearch(a,value,mid + 1,high);	
        }
        return -1;
    }
	//循环查找
    public static int binarysearch(int[] a,int value){
		int left=0;
		int right=a.length-1;
		int middle=0;
		while(left<=right) {
			middle=(left+right)/2;
			if(value == a[middle]){
	            return middle;
	        }else if(value < a[middle]) {
	        	left=middle - 1;
	        }else if(value > a[middle]) {
	        	right=middle + 1;	
	        }
		}
		return middle;
    }
	public static void main(String[] args) {
		//int[] a = {1,4,2,9,8,6,7,0,3,5}
		int[] a = {0,1,2,3,4,5,6,7,8,9};
		System.out.println(binarysearch(a,4,0,a.length-1));
	} 
}

3、插值查找

4、斐波那契查找

5、树表查找

6、分块查找

7、哈希查找

三、常见算法题型

1、求阶乘

//求取n的阶乘
public  int factorial(int n) {
	if(n==1){ 
        return 1;
 	}else{ 
        return n*factorial(n-1); 
    }
}

2、斐波那契数列

//求取斐波那契数列1、1、2、3、5、8、13
private int print(int n) {
	if(n==1||n==2){
		return 1;
	}else{
		return print(n-1)+print(n-2);
	}
}

3、验证回文数

//判断字符串从索引i 到 j 位置的字符串是否是回文数
private boolean print2(String s,int i,int j){
	if(j<=i){
		return true;
	}else if(s.charAt(i)!=s.charAt(j)){
		return false;
	}else{
		return print2(s,i+1,j-1);
	}
}

四、树

树的度:树节点的子树的数量为结点的度

1、遍历树

遍历树四种基本的遍历思想为:

扫描二维码关注公众号,回复: 5962706 查看本文章

前序遍历:根结点 —> 左子树 —> 右子树
中序遍历:左子树—> 根结点 —> 右子树
后序遍历:左子树 —> 右子树 —> 根结点
层次遍历:仅仅需按层次遍历就可以

img

前序遍历:1 2 4 5 7 8 3 6
中序遍历:4 2 7 5 8 1 3 6
后序遍历:4 7 8 5 2 6 3 1
层次遍历:1 2 3 4 5 6 7 8

//采用递归方式:---->>>>>>>>>>>>>
//前序遍历
public void preOrderTraverse1(TreeNode root) {  
        if (root != null) {  
            System.out.print(root.val+"  ");  
            preOrderTraverse1(root.left);  
            preOrderTraverse1(root.right);  
        }  
}

//中序遍历
public void inOrderTraverse1(TreeNode root) {  
        if (root != null) {  
            inOrderTraverse1(root.left);  
            System.out.print(root.val+"  ");  
            inOrderTraverse1(root.right);  
        }  
} 
//后续遍历
public void postOrderTraverse1(TreeNode root) {  
        if (root != null) {  
            postOrderTraverse1(root.left);  
            postOrderTraverse1(root.right);  
            System.out.print(root.val+"  ");  
        }  
} 


//层次遍历
public void levelTraverse(TreeNode root) {  
        if (root == null) {  
            return;  
        }  
        LinkedList<TreeNode> queue = new LinkedList<>();  
        queue.offer(root);  
        while (!queue.isEmpty()) {  
            TreeNode node = queue.poll();  
            System.out.print(node.val+"  ");  
            if (node.left != null) {  
                queue.offer(node.left);  
            }  
            if (node.right != null) {  
                queue.offer(node.right);  
            }  
        }  
} 

五、队列

1、循环队列

import java.io.*;
public class QueueArray {   
    Object[] a; //对象数组,队列最多存储a.length-1个对象   
    int front;  //队首下标   
    int rear;   //队尾下标   
    public QueueArray(){   
        this(10); //调用其他构造方法   
    }   
    public QueueArray(int size){   
        a = new Object[size];   
        front = 0;   
        rear =0;   
    }   
    /**  
     * 将一个对象追加到队列尾部  
     * @param obj 对象   
     * @return 队列满时返回false,否则返回true  
     */  
    public boolean enqueue(Object obj){   
        if((rear+1)%a.length==front){   
            return false;   
        }   
        a[rear]=obj;   
        rear = (rear+1)%a.length;   
        return true;   
    }   
    /**  
     * 队列头部的第一个对象出队  
     * @return 出队的对象,队列空时返回null  
     */  
    public Object dequeue(){   
        if(rear==front){   
            return null;   
        }   
        Object obj = a[front];   
        front = (front+1)%a.length;   
        return obj;   
    }   
    public static void main(String[] args) {   
        QueueArray q = new QueueArray(4);   
        System.out.println(q.enqueue("张三"));   
        System.out.println(q.enqueue("李斯"));   
        System.out.println(q.enqueue("赵五"));   
        System.out.println(q.enqueue("王一"));//无法入队列,队列满   
        for(int i=0;i<4;i++){   
            System.out.println(q.dequeue());   
        }   
    }   
} 

六、加密算法

加密算法介绍

DES加密算法

AES加密算法

RSA加密算法:非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。RSA

Base64加密算法

MD5加密算法:消息摘要算法,不可逆

SHA1加密算法

摘要算法:MD5(128位)、SHA1(160位),是一种不可逆的过程,无论多大的数据,经过摘要算法后都生成相同长度的数据。只能通过字典进行破解。

对称加密算法:DES、AES,加密解密时使用相同的秘钥。

非对称加密算法:RSA,加密解密时使用不同的秘钥,对接支付宝使用RSA2。

猜你喜欢

转载自blog.csdn.net/u013234928/article/details/89416844