package test.arithmetic; public class SortMethod { public static void printArray(int[] array) { System.out.print("{"); for (int i = 0; i < array.length; i++) { System.out.print(array[i]); if (i < array.length - 1) { System.out.print(", "); } } System.out.println("}"); } /** * 1.冒泡排序 * 优势:稳定,比较次数已知; * 缺点:慢,每次只能移动相邻两个数据,移动数据的次数多。 * 初始关键字 [49 38 65 97 76 13 27 49] * 第一趟排序后 [38 49 65 76 13 27 49] 97 * 第二趟排序后 [38 49 65 13 27 49] 76 97 * 第三趟排序后 [38 49 13 27 49] 65 76 97 * 第四趟排序后 [38 13 27 49] 49 65 76 97 * 第五趟排序后 [38 13 27] 49 49 65 76 97 * 第六趟排序后 [13 27]38 49 49 65 76 97 * 第七趟排序后 [13] 27 38 49 49 65 76 97 * 最后排序结果 13 27 38 49 49 76 76 97 */ public static void bubbleSort() { int a[] = { 49, 38, 65, 97, 76, 13, 27, 49 }; for (int i = a.length - 1; i >= 0; i--) { for (int j = 0; j < i; j++) { if (a[j] > a[j + 1]) { int k = a[j]; a[j] = a[j + 1]; a[j + 1] = k; } } } for (int i = 0; i < a.length; i++) { System.out.print(a[i] + ", "); } } /** * 2.选择排序 * ①初始状态:无序区为R[1..n],有序区为空。 * ②第1趟排序 * 在无序区R[1..n]中选出关键字最小的记录R[k],将它与无序区的第1个记录R[1]交换,使R[1..1]和R[2..n]分别变为记录个数增长1个的新有序区和记录个数减小1个的新无序区。 * …… * ③第i趟排序 * 第i趟排序开始时,当前有序区和无序区分别为R[1..i-1]和R[i..n](1≤i≤n-1)。该趟排序从当前无序区中选出关键字最小的记录R[k],将它与无序区的第1个记录R交换,使R[1..i]和R[i+1..n]分别变为记录个数增长1个的新有序区和记录个数减小1个的新无序区.这样,n个记录的文件的直接选择排序可通过n-1趟直接选择排序获得有序结果。 * 优势:稳定,比较次数与冒泡排序同样; * 缺点:相对之下仍是慢。 * 初始关键字 [49 38 65 97 76 13 27 49] * 第一趟排序后 13 [38 65 97 76 49 27 49] * 第二趟排序后 13 27 [65 97 76 49 38 49] * 第三趟排序后 13 27 38 [97 76 49 65 49] * 第四趟排序后 13 27 38 49 [49 97 65 76] * 第五趟排序后 13 27 38 49 49 [97 76 76] * 第六趟排序后 13 27 38 49 49 76 [76 97] * 第七趟排序后 13 27 38 49 49 76 76 [ 97] * 最后排序结果 13 27 38 49 49 76 76 97 */ public static void selectionSort() { int a[] = { 49, 38, 65, 97, 76, 13, 27, 49 }; int k = 0; for (int i = 0; i < a.length - 1; i++) { k = i; for(int j=i+1; j<a.length; j++){ if(a[k] > a[j]){ k = j; } } if(k != i){ int temp = a[k]; a[k] = a[i]; a[i] = temp; } System.out.println("\n" + (i + 1) + ": "); for (int m = 0; m < a.length; m++) { System.out.print(a[m] + ", "); } } } /** * 3.插入排序 * 已知一组,一组无序数据b[1]、b[2]、……b[m],需将其变成一个升序数列。先建立一个变量a。首先将不b[1]与b[2],若是b[1]大于b[2]则交换位置,不然不变; * 再比较b[2]与b[3], 若是b[3]小于b[2],则将b[3]赋值给a,再将a与b[1]比较,若是a小于b[1];则将b[2],b[1]依次后移;在将a放在b[1]处以此类推,直到排序结束。 * 初始关键字 [49 38 65 97 76 13 27 59] * a b[1] b[2]? b[3]? b[4] b[5]? b[6]? b[7] b[8] * 1—–49? 49 >? 38 65 97 ? 76? 13 ? 27 59 * 38 49 49 ………. * 38 38 49 ………. * 2—–38? 38 ? 49 < 65? 97 ? 76 13 27 59 * 3—–38? 38 ? 49? 65 <97 ? 76 13 27 59 * 4—-38? 38 49? 65 97> 76 13 27 59 * 76 38 49 65 97 97…….. * 76 38 49 65 76 97…….. */ public static void straightInsertionSort(){ int[] array = { 3, -1, 0, -8, 2, 1 }; int sentinel , j; for (int i = 1; i < array.length; i++) { j = i - 1; sentinel = array[i];//哨兵位 while (j >= 0 && sentinel < array[j]) { array[j+1] = array[j];//将大于sentinel的值总体后移一个单位 j--; } array[j+1] = sentinel; } printArray(array); } /** * 4.缩小增量排序(希尔排序) * 由希尔在1959年提出,又称希尔排序。 * 已知一组无序数据a[1]、a[2]、……a[n],需将其按升序排列。发现当n不大时,插入排序的效果很好。 * 首先取一增量d(d<n),将a[1]、a[1+d]、a[1+2d]……列为第一组,a[2]、a[2+d]、a[2+2d]……列为第二组……,a[d]、a[2d]、a[3d]……列为最后一组以次类推, * 在各组内用插入排序,而后取d’<d,重复上述操做,直到d=1。增量d(1, 3, 7,15, 31, …, 2^k-1)是使用最普遍的增量序列之一. * 优势:快,数据移动少; * 缺点:不稳定,d的取值是多少,应取多少个不一样的值,都没法确切知道,只能凭经验来取。 * 初始:d=5 * 49 38 65? 97 76 13? 27 49 55? 44 * 一趟结果 * 13 27 49 55 44 49? 38 65 97 76 * d=3 |———————-|———————-|———————| * 二趟结果 * 13 44 49 38 27 49? 55 65 97? 76 * d=1 * 三趟结果 * 13 27 38 44 49? 49 55 65 76? 97 * 希尔排序的原理:根据需求,若是你想要结果从大到小排列,它会首先将数组进行分组,而后将较大值移到前面,较小值 * 移到后面,最后将整个数组进行插入排序,这样比起一开始就用插入排序减小了数据交换和移动的次数,能够说希尔排序是增强 * 版的插入排序 * 拿数组5, 2, 8, 9, 1, 3,4来讲,数组长度为7,当increment为3时,数组分为两个序列 * 5,2,8和9,1,3,4,第一次排序,9和5比较,1和2比较,3和8比较,4和比其下标值小increment的数组值相比较 * 此例子是按照从大到小排列,因此大的会排在前面,第一次排序后数组为9, 2, 8, 5, 1, 3,4 * 第一次后increment的值变为3/2=1,此时对数组进行插入排序, */ public static void shellSort(){ int j = 0; int temp = 0; int[] data = new int[] { 5, 2, 8, 9, 1, 3, 4 }; for (int increment = data.length / 2; increment > 0; increment /= 2) { for (int i = increment; i < data.length; i++) { temp = data[i]; for (j = i; j >= increment; j -= increment) { if (temp > data[j - increment]) { data[j] = data[j - increment]; } else { break; } } data[j] = temp; } } } /** * 5.快速排序 * 快速排序是冒泡排序的改进版,是目前已知的最快的排序方法。 * 已知一组无序数据a[1]、a[2]、……a[n],需将其按升序排列。 * 首先任取数据a[x]做为基准。比较a[x]与其它数据并排序,使a[x]排在数据的第k位,而且使a[1]~a[k-1]中的每个数据<a[x],a[k+1]~a[n]中的每个数据>a[x], * 而后采用分治的策略分别对a[1]~a[k-1]和a[k+1]~a[n] * 两组数据进行快速排序。 * 优势:极快,数据移动少; * 缺点:不稳定。 * 分段插入排序 * @param args */ public static void quicksort(int n[], int left, int right) { int dp; if (left < right) { dp = partition(n, left, right); quicksort(n, left, dp - 1); quicksort(n, dp + 1, right); } } public static int partition(int[] n, int left, int right) { int pivotkey = n[left]; // 枢轴选定后永远不变,最终在中间,前小后大 while (left < right) { while (left < right && n[right] >= pivotkey) --right; // 将比枢轴小的元素移到低端,此时right位至关于空,等待低位比pivotkey大的数补上 n[left] = n[right]; while (left < right && n[left] <= pivotkey) ++left; // 将比枢轴大的元素移到高端,此时left位至关于空,等待高位比pivotkey小的数补上 n[right] = n[left]; } // 当left == right,完成一趟快速排序,此时left位至关于空,等待pivotkey补上 n[left] = pivotkey; return left; } public static void quicksortMain(){ int array[] = { 9, 5, 4, 8, 7, 3, 2, 10 }; quicksort(array, 0, array.length-1); printArray(array); } /** * 6.归并排序算法 * 合并排序(MERGESORT)是又一类不一样的排序方法,合并的含义就是将两个或两个以上的有序数据序列合并成一个新的有序数据序列,所以它又叫归并算法。 * 它的基本思想就是假设数组A有N个元素,那么能够当作数组A是又N个有序的子序列组成,每一个子序列的长度为1,而后再两两合并,获得了一个 N/2? 个长度为2或1的有序子序列,再两两合并,如此重复,值得获得一个长度为N的有序数据序列为止,这种排序方法称为2—路合并排序。 * 例如数组A有7个数据,分别是: 49 38 65 97 76 13? 27,那么采用归并排序算法的操做过程如图7所示: * 初始值 [49] [38]? [65] [97] [76]? [13] [27] * 第一次合并以后 [38 ? 49] ? [65 ? 97]? [13 76] [27] * 第二次合并以后 [38 ? 49 ? 65 ? 97]? [13 27 76] * 第三次合并以后 [13 ? 27 ? 38 ? 49 ? 65 ? 76 ? 97] * 合并算法的核心操做就是将一维数组中先后相邻的两个两个有序序列合并成一个有序序列。合并算法也能够采用递归算法来实现,形式上较为简单,但实用性不好。 * 合并算法的合并次数是一个很是重要的量,根据计算当数组中有3到4个元素时,合并次数是2次,当有5到8个元素时,合并次数是3次,当有9到16个元素时,合并次数是4次,按照这一规律,当有N个子序列时能够推断出合并的次数是X(2? >=N,符合此条件的最小那个X)。 * 其时间复杂度为:O(nlogn).所需辅助存储空间为:O(n) */ public static void merge(int a[], int low, int poi, int high) { int l1 = poi - low + 1; int l2 = high - poi; int[] array1 = new int[l1 + 1]; int[] array2 = new int[l2 + 1]; for (int i = 0; i < l1; i++) { array1[i] = a[low + i]; } for (int i = 0; i < l2; i++) { array2[i] = a[poi + 1 + i]; } // 将数组中的最后一个元素设置为最大值,这样就没必要担忧会有数据元素剩余, // 同时k的取值范围决定了无穷值不会被添加到原数据中 array1[l1] = Integer.MAX_VALUE; array2[l2] = Integer.MAX_VALUE; int i = 0; int j = 0; for (int k = low; k <= high; k++) { if (array1[i] <= array2[j]) { a[low++] = array1[i]; i++; } else { a[low++] = array2[j]; j++; } } } public static void mergeSort(int a[], int low, int high) { if (low == high) { return; } else { int poi = (low + high) / 2; mergeSort(a, low, poi); mergeSort(a, poi + 1, high); merge(a, low, poi, high); } } public static void mergeSortTest() { int[] array = { 1, 3, 6, 4, 13, 14, 8, 12, 9, 7, 0}; mergeSort(array, 0, array.length - 1); printArray(array); } /** * 7. 堆排序 * 根结点(亦称为堆顶)的关键字是堆里全部结点关键字中最小者的堆称为小根堆。 * 根结点(亦称为堆顶)的关键字是堆里全部结点关键字中最大者,称为大根堆。 * n个关键字序列Kl,K2,…,Kn称为堆,当且仅当该序列知足以下性质(简称为堆性质): * (1) ki≤K2i且ki≤K2i+1 或(2)Ki≥K2i且ki≥K2i+1(1≤i≤ ) * 堆排序利用了大根堆(或小根堆)堆顶记录的关键字最大(或最小)这一特征,使得在当前无序区中选取最大(或最小)关键字的记录变得简单。 * (1)用大根堆排序的基本思想 * ① 先将初始文件R[1..n]建成一个大根堆,此堆为初始的无序区 * ② 再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,由此获得新的无序区R[1..n-1]和有序区R[n],且知足R[1..n-1].keys≤R[n].key * ③ 因为交换后新的根R[1]可能违反堆性质,故应将当前无序区R[1..n-1]调整为堆。而后再次将R[1..n-1]中关键字最大的记录R[1]和该区间的最后一个记录R[n-1]交换,由此获得新的无序区R[1..n-2]和有序区R[n-1..n],且仍知足关系R[1..n-2].keys≤R[n-1..n].keys,一样要将R[1..n-2]调整为堆。 * 直到无序区只有一个元素为止。 * (2)大根堆排序算法的基本操做: * ① 初始化操做:将R[1..n]构造为初始堆; * ② 每一趟排序的基本操做:将当前无序区的堆顶记录R[1]和该区间的最后一个记录交换,而后将新的无序区调整为堆(亦称重建堆)。 * 注意: * ①只需作n-1趟排序,选出较大的n-1个关键字便可以使得文件递增有序。 * ②用小根堆排序与利用大根堆相似,只不过其排序结果是递减有序的。堆排序和直接选择排序相反:在任什么时候刻,堆排序中无序区老是在有序区以前,且有序区是在原向量的尾部由后往前逐步扩大至整个向量为止。 */ public static void heapSort(int[] array) { buildHeap(array);// 构建堆 int n = array.length; int i = 0; for (i = n - 1; i >= 1; i--) { swap(array, 0, i); heapify(array, 0, i); } } public static void buildHeap(int[] array) { int n = array.length;// 数组中元素的个数 for (int i = n / 2 - 1; i >= 0; i--) heapify(array, i, n); } public static void heapify(int[] A, int idx, int max) { int left = 2 * idx + 1;// 左孩子的下标(若是存在的话) int right = 2 * idx + 2;// 左孩子的下标(若是存在的话) int largest = 0;// 寻找3个节点中最大值节点的下标 if (left < max && A[left] > A[idx]) largest = left; else largest = idx; if (right < max && A[right] > A[largest]) largest = right; if (largest != idx) { swap(A, largest, idx); heapify(A, largest, max); } } public static void swap(int[] array, int i, int j) { int temp = 0; temp = array[i]; array[i] = array[j]; array[j] = temp; } //--------------------------------- public static void main(String[] args) { int array[] = {11,2,3,14,5,6,1,8,9}; heapSort(array); printArray(array); } }