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)每一个节点的关键字都大于(等于)这个节点的子节点关键字。