数据结构之常用算法

1 快速排序

            1)指定枢纽的值

            2)经过一次比较,找到枢纽值的位置,使得其左边的每一个值都比它小,右边的值都比它大

            3)使用递归的方法对其左边和右边的子数组重复2的操作

实现代码:

 /**
	 * @description:快速排序
	 * @param source
	 * @param left
	 * @param right
	 */
	public static void quickSort(int source[], int left, int right) {      
		if (left >= right) {
			return;
		}
		// 将中间的这个数和第一个数交换 参见注1
		int i = left;
		int j = right;
		int povit = source[left];  
		while (i < j) {
			// 从右向左找第一个小于povit的数
			while (i < j && source[j] >= povit) {
				j--;
			}
			if (i < j) {
				source[i++] = source[j];
			}
			// 从左向右找第一个大于等于povit的数
			while (i < j && source[i] < povit) {
				i++;
			}
			if (i < j) {
				source[j--] = source[i];  
			}
		}
		source[i] = povit;
		quickSort(source, left, i - 1); // 递归调用
		quickSort(source, i + 1, right);
	}

2 冒泡排序

     1 ) 每执行一次循环,相对“最大值”就要就会"冒泡"到未排序部分的末位。

实现代码:

 /**
	 * @description:冒泡排序
	 * @param source
	 */
	public static void bubbleSort(int[] source){
		if(null == source || source.length < 2){
			return;
		}
		int temp ;
		for(int i = source.length - 2 ; i >= 0 ; i--){
			for(int j = 0 ; j <= i ; j++){
				if(source[j] > source[j + 1]){ 
					temp = source[j];   
					source[j] = source[j + 1];
					source[j + 1] = temp;  
				}
			}
		}
	}

3 选择排序:

    1)外层控制循环次数

    2)记下最小值索引

    3)遍历以后的每一个元素,如果发现有比当前最小值小的元素,修改最小值的索引

    4)比较当前最小值索引与原始最小值的索引,不相等则元素交换

实现代码:

 /**
	 * @description:选择排序
	 * @param source
	 */
	public static void selectSort(int[] source){
		if(null == source || source.length < 2){
			return;
		}
		int min = 0;
		int temp ;
		for(int i = 0 ; i < source.length - 1 ; i++){
			min = i;  
			for(int j = i + 1 ; j < source.length ; j++){  
				if(source[min] > source[j]){ 
					min = j;
				}
			}    
			if(min != i){ 
				temp = source[min];
				source[min] = source[i];
				source[i] = temp;
			}
		}
	}

4 插入排序

    1)标记要插入的元素

    2)插入元素左边的元素都是有序的

    3)从插入元素前一个元素开始,依次和比较标记元素比较,如果比标记元素大,右移,否则找到插入元素的位置

    4)把标记元素插入到找到的插入位置

实现代码:

 /**
	 * @description:插入排序
	 * @param source
	 */
	public static void insertSort(int[] source){
		if(null == source || source.length < 2){
			return ;
		}
		int markElement ;
		for(int i = 1 ; i < source.length ; i++){
			markElement = source[i];
			int in = i;
			while (in >= 0 && source[in - 1] > markElement){
				source[in] = source[in - 1];
				in--;
			}
			source[in] = markElement;
		}
	}

5 归并排序

    1)归并排序是对两个已经有序的数组的排序

实现代码:

 /**
	 * 归并排序
	 * @param a
	 * @param b
	 * @return
	 */
	public static int[] merge(int[] a , int[] b){  
		if(a == null || a.length == 0){
			return b ;
		}
		if(b == null || b.length == 0){
			return a;
		}
		int aPos = 0;//a数据当前归并位置
		int bPos = 0;//b数据当前归并位置
		int resultPos = 0;//result数据当前归并位置
		int[] result = new int[a.length + b.length];  
		while(aPos < a.length && bPos < b.length){
			if(a[aPos] < b[bPos]){
				result[resultPos] = a[aPos];
				aPos++;
			} else {
				result[resultPos] = b[bPos]; 
				bPos++;  
			}
			resultPos++ ;
		}
		//复制a剩余的元素
		while(aPos < a.length){
			result[resultPos] = a[aPos];
			resultPos++;
			aPos++;
		}
		//复制b剩余的元素   
		while(bPos < b.length){
			result[resultPos] = b[bPos]; 
			resultPos++;
			bPos++;
		}
		return result;  
	}


6 希尔排序

    1)希尔排序是插入排序的加强版

    2)knuth提出间隔序列的概念,通常从1开始,4,13。。。计算公式h = 3 * h + 1(h小于数组的长度的1/3);

    3)通过插入排序算法排序以h,2h,3h。。。为下标组成的子数组

    4)缩小h的值,直到h=1,排序完毕

实现代码:

 /**
	 * 希尔排序
	 * @param source
	 */
	public static void shellSort(int[] source){  
	    if(null == source || source.length < 2){  
	        return ;  
	    }  
	    int h = 1;  
	    while(h <= source.length / 3){  
	        h = 3 * h + 1;  
	    }  
	    int markElement ;  
	    while(h > 0){  
	        for(int i = h ; i < source.length ; i++){  
	            markElement = source[i];  
	            int in = i;  
	            while (in >= h - 1 && source[in - h] > markElement){  
	                source[in] = source[in - h];  
	                in = in - h;  
	            }  
	            source[in] = markElement;  
	        }  
	        h = (h - 1) / 3;  
	    }  
	} 

7 hash表:由数组实现

1)当一个key做hash运算后和另一个key做hash运算得到数组下标相同成为冲突

2)开放地址法:当发生冲突时,通过系统的方法找到数组的一个空位置,并把单词填入,而不是由hash函数得到数组下标。

3)链地址法:当发生冲突时,新的数据项直接存到数组下标所指向的链表中。

4)开放地址法包含线性探测,二次探测,再hash法

5)线性探测:如果5421是要插入数据的位置,他已经被占用了,那么就使用5422,然后是5423,数组下标一直递增,直到找到空的位置。

6)聚集:当hash变得越来越满时,聚集变得越来越严重。这导致非常长的探测长度,意味着存取序列最后的单元会非常的耗时。设计hash表的关键是确保他不会超过整个数组容量的一半,最多到三分之二。

7)已填入hash表的数据项和表长的比率叫做装填因子。

8)二次探测:步数的平方。如果hash函数计算的原始下标是x,线性探测是x + 1 , x + 2 , x + 3...而在二次探测中是探测的过程是x + 1 , x + 4 , x + 9...

9)线性探测产生的聚集问题叫原始聚集。二次探测时多个数字映射到同一个位置,第二个数字产生以1为步长的探测,第三个数字产生以4为步长的探测,第四个数字产生以9为步长 的探测..这种现象叫二次聚集。

10)再hash法:为了消除原始聚集和二次聚集,可以使用再hash法。

11)第二个函数具备的特点:1)和第一个hash函数不同     2)不能输出0

12)工作很好的第二个hash函数:stepSize = constant - (key % constant);第一个hash函数:key % arraySize

13)链地址法:在每一个单元中设置链表。桶:在链表的每一个单元中使用数组,而不是链表。

8 堆:堆是有如下特点的二叉树:

1)它是完全二叉树:除了树的最后一层不需要是满的,其他的每一层从左到右都是满的。

2)它常常用一个数组来实现。

3)每一个节点的关键字都大于(等于)这个节点的子节点关键字。



你可能感兴趣的:(数据结构之常用算法)