排序算法
来源:互联网 发布:正规淘宝刷客平台 编辑:程序博客网 时间:2024/06/05 20:16
package com.h.sort;import java.util.Arrays;/** * Created by John on 2017/8/31. */public class Sort { /** * 冒泡排序 * 依次比较并按规则交换相邻的数值,若有N个数要比较,则一共要比较(N-1)轮. * 假如按升序排列,则第一轮比较后最大的数值跑到了最后,重复上述步骤 * O(n^2) * 最有排序算法的时间复杂度:O(nlogn) * @param nums */ public static int[] bubbleSort(int[] nums){ for (int i=0;i<nums.length-1;i++){ for (int j=0;j<nums.length-i-1;j++){ if (nums[j] > nums[j+1]){ swap(nums,j,j+1); } } } return nums; } /** * 选择排序 * 假如升序排序,从第一个元素开始到倒数第二个元素, * 依次将其后面的每个数与当前外层的选定的数值比较,若小于外层的数,则交换 * 即每次从无序数组中选出较小的数放到前面 * @param nums * @return */ public static int[] selectionSort(int[] nums){ int size = nums.length; for (int i=0;i<size-1;i++){ for (int j=i+1;j<size;j++){ if (nums[j] < nums[i]){ swap(nums,j,i); } } } return nums; } /** * 选择排序的小优化 * 当内层循环比较中 需要交换数值时,不要直接马上交换两个位置的数值, * 而是记录较小数值的索引,当内层循环结束时,较小数值的索引也就出来了, * 此时再交换数值,这样可以减少中间临时的交换次数,提高速度 * @param nums * @return */ public static int[] selectionSort2(int[] nums){ int size = nums.length; int minIndex;//记录每次内层循环比较完后的较小数值的索引 for (int i=0;i<size-1;i++){ minIndex = i; for (int j=i+1;j<size;j++){ if (nums[j] < nums[minIndex]){//nums[minIndex]总是存储较小值,用作被比较的基准 minIndex = j; } } if (minIndex != i){ swap(nums,minIndex,i); } } return nums; } public static void swap(int[] nums,int i,int j){ nums[i] ^= nums[j]; nums[j] ^= nums[i]; nums[i] ^= nums[j]; } /** * 两个int整数交换的方式 * @param a * @param b */ public static void swap1(int a,int b){ int temp = a; a = b; b = temp; } public static void swap2(int a,int b){ a^=b; b^=a; a^=b; } public static void swap3(int a,int b){ a = a + b; b = a - b; a = a - b; } public static void main(String[] args) { int[] nums = {1,6,2,7,3,8,5,9,4,12,5,3}; // nums = bubbleSort(nums); nums = selectionSort2(nums); System.out.println(Arrays.toString(nums)); }}
一.选择排序
package com.h.sort;/** * Created by John on 2017/8/31. */public class SelectionSort { // 我们的算法类不允许产生任何实例 private SelectionSort(){} public static void sort(Comparable[] arr){ int n = arr.length; for( int i = 0 ; i < n ; i ++ ){ // 寻找[i, n)区间里的最小值的索引 int minIndex = i; for( int j = i + 1 ; j < n ; j ++ ) // 使用compareTo方法比较两个Comparable对象的大小 if( arr[j].compareTo( arr[minIndex] ) < 0 ) minIndex = j; swap( arr , i , minIndex); } } public static void sort2(Comparable[] arr){ int n = arr.length; for( int i = 0 ; i < n ; i ++ ){ // 寻找[i, n)区间里的最小值的索引 int minIndex = i; for( int j = i + 1 ; j < n ; j ++ ){ // 使用compareTo方法比较两个Comparable对象的大小 if( arr[j].compareTo( arr[minIndex] ) < 0 ) minIndex = j; } if (i != minIndex){ swap( arr , i , minIndex); } } } private static void swap(Object[] arr, int i, int j) { Object t = arr[i]; arr[i] = arr[j]; arr[j] = t; } public static void main(String[] args) { // 测试Integer Integer[] a = {10,9,8,7,6,5,4,3,2,1}; SelectionSort.sort2(a); for( int i = 0 ; i < a.length ; i ++ ){ System.out.print(a[i]); System.out.print(' '); } System.out.println(); // 测试Double Double[] b = {4.4, 3.3, 2.2, 1.1}; SelectionSort.sort2(b); for( int i = 0 ; i < b.length ; i ++ ){ System.out.print(b[i]); System.out.print(' '); } System.out.println(); // 测试String String[] c = {"D", "C", "B", "A"}; SelectionSort.sort2(c); for( int i = 0 ; i < c.length ; i ++ ){ System.out.print(c[i]); System.out.print(' '); } System.out.println(); // 测试自定义的类 Student Student[] d = new Student[4]; d[0] = new Student("D",90); d[1] = new Student("C",100); d[2] = new Student("B",95); d[3] = new Student("A",95); SelectionSort.sort2(d); for( int i = 0 ; i < d.length ; i ++ ) System.out.println(d[i]); }}package com.h.sort;/** * Created by John on 2017/8/31. */public class Student implements Comparable<Student> { private String name; private int score; public Student(String name, int score){ this.name = name; this.score = score; } // 定义Student的compareTo函数 // 如果分数相等,则按照名字的字母序排序 // 如果分数不等,则分数高的靠前 @Override public int compareTo(Student that) { if( this.score == that.score ) return this.name.compareTo(that.name); if( this.score < that.score ) return 1; else if( this.score > that.score ) return -1; else // this.score == that.score return 0; } // 定义Student实例的打印输出方式 @Override public String toString() { return "Student: " + this.name + " " + Integer.toString( this.score ); }}
package com.h.sort;/** * Created by John on 2017/8/31. */public class SelectionSort { // 我们的算法类不允许产生任何实例 private SelectionSort(){} public static <T extends Comparable<T>> void sort(T[] arr){ int n = arr.length; for( int i = 0 ; i < n ; i ++ ){ for( int j = i + 1 ; j < n ; j ++ ){ // 使用compareTo方法比较两个Comparable对象的大小 if( arr[j].compareTo( arr[i] ) < 0 ){ swap( arr , i , j); } } } } public static <T extends Comparable<T>> void sort2(T[] arr){ int n = arr.length; for( int i = 0 ; i < n ; i ++ ){ // 寻找[i, n)区间里的最小值的索引 int minIndex = i; for( int j = i + 1 ; j < n ; j ++ ){ // 使用compareTo方法比较两个Comparable对象的大小 if( arr[j].compareTo( arr[minIndex] ) < 0 ){ minIndex = j; } } if (minIndex != i){ swap( arr , i , minIndex); } } } private static void swap(Object[] arr, int i, int j) { Object t = arr[i]; arr[i] = arr[j]; arr[j] = t; } public static void main(String[] args) { // 测试排序算法辅助函数 int N = 20000; Integer[] arr = SortTestHelper.generateRandomArray(N, 0, 100000); long begin = System.currentTimeMillis(); SelectionSort.sort( arr ); //SelectionSort.sort2( arr ); System.out.println("耗时:" + (System.currentTimeMillis() - begin) + "ms"); SortTestHelper.printArray(arr); }}package com.h.sort;/** * Created by John on 2017/8/31. */public class SortTestHelper { // SortTestHelper不允许产生任何实例 private SortTestHelper(){} // 生成有n个元素的随机数组,每个元素的随机范围为[rangeL, rangeR] public static Integer[] generateRandomArray(int n, int rangeL, int rangeR) { assert rangeL <= rangeR; Integer[] arr = new Integer[n]; for (int i = 0; i < n; i++) arr[i] = new Integer((int)(Math.random() * (rangeR - rangeL + 1) + rangeL)); return arr; } // 打印arr数组的所有内容 public static void printArray(Object arr[]) { for (int i = 0; i < arr.length; i++){ System.out.print( arr[i] ); System.out.print( ' ' ); } System.out.println(); return; }}
package com.h.sort;/** * Created by John on 2017/8/31. */public class SelectionSort{ // 我们的算法类不允许产生任何实例 private SelectionSort(){} public static void sort(Comparable[] arr){ int n = arr.length; for( int i = 0 ; i < n ; i ++ ){ // 寻找[i, n)区间里的最小值的索引 int minIndex = i; for( int j = i + 1 ; j < n ; j ++ ){ // 使用compareTo方法比较两个Comparable对象的大小 if( arr[j].compareTo( arr[minIndex] ) < 0 ) minIndex = j; } if (minIndex != i){ swap( arr , i , minIndex); } } } private static void swap(Object[] arr, int i, int j) { Object t = arr[i]; arr[i] = arr[j]; arr[j] = t; } public static void main(String[] args) { // 测试排序算法辅助函数 int N = 20000; Integer[] arr = SortTestHelper.generateRandomArray(N, 0, 100000); SortTestHelper.testSort("com.h.sort.SelectionSort", arr); }}package com.h.sort;import java.lang.reflect.Method;import java.lang.Class;/** * Created by John on 2017/8/31. */public class SortTestHelper { // SortTestHelper不允许产生任何实例 private SortTestHelper(){} // 生成有n个元素的随机数组,每个元素的随机范围为[rangeL, rangeR] public static Integer[] generateRandomArray(int n, int rangeL, int rangeR) { assert rangeL <= rangeR; Integer[] arr = new Integer[n]; for (int i = 0; i < n; i++) arr[i] = new Integer((int)(Math.random() * (rangeR - rangeL + 1) + rangeL)); return arr; } // 打印arr数组的所有内容 public static void printArray(Object arr[]) { for (int i = 0; i < arr.length; i++){ System.out.print( arr[i] ); System.out.print( ' ' ); } System.out.println(); } // 判断arr数组是否有序 public static boolean isSorted(Comparable[] arr){ for( int i = 0 ; i < arr.length - 1 ; i ++ ) if( arr[i].compareTo(arr[i+1]) > 0 ) return false; return true; } // 测试sortClassName所对应的排序算法排序arr数组所得到结果的正确性和算法运行时间 public static void testSort(String sortClassName, Comparable[] arr){ // 通过Java的反射机制,通过排序的类名,运行排序函数 // * 依然是,使用反射机制并不是这个课程的重点, 大家也完全可以使用自己的方式书写代码, 最终只要能够测试出自己书写的算法的效率即可 // * 推荐大家阅读我在问答区向大家分享的一个学习心得: 【学习心得分享】请大家抓大放小,不要纠结于C++语言的语法细节 // * 链接: http://coding.imooc.com/learn/questiondetail/4100.html try{ // 通过sortClassName获得排序函数的Class对象 Class sortClass = Class.forName(sortClassName); // 通过排序函数的Class对象获得排序方法 Method sortMethod = sortClass.getMethod("sort",new Class[]{Comparable[].class}); // 排序参数只有一个,是可比较数组arr Object[] params = new Object[]{arr}; long startTime = System.currentTimeMillis(); // 调用排序函数 sortMethod.invoke(null,params); long endTime = System.currentTimeMillis(); assert isSorted( arr ); System.out.println( sortClass.getSimpleName()+ " : " + (endTime-startTime) + "ms" ); } catch(Exception e){ e.printStackTrace(); } }}
二.插入排序
/** * 插入排序 * 将当前元素插入到它前面的已经排好序的序列的合适位置 * @param nums */ public static int[] insertionSort(int[] nums){ int size = nums.length; for (int i=0;i<size;i++){//当前需要排序的元素的索引 for (int j=i;j>0;j--){//当前需要排序的元素的前面的元素列表 if (nums[j] < nums[j-1]){ swap(nums,j,j-1); } } } return nums; }
package com.h.sort;import java.util.Arrays;/** * Created by John on 2017/8/31. */public class InsertionSort{ // 我们的算法类不允许产生任何实例 private InsertionSort(){} public static void sort(Comparable[] arr) { int n = arr.length; for (int i = 0; i < n; i++) { // 寻找元素arr[i]合适的插入位置 for (int j = i; j > 0; j--) { if (arr[j].compareTo(arr[j - 1]) < 0){ swap(arr, j, j - 1); } else { break; } } } } public static void sort2(Comparable[] arr){ int n = arr.length; for (int i = 0; i < n; i++) { // 寻找元素arr[i]合适的插入位置 for( int j = i; j > 0 && arr[j].compareTo(arr[j-1]) < 0 ; j--){ swap(arr, j, j-1); } } } /** * 插入排序优化 * 之前的做法都是在遍历的时候符合条件就交换,而交换的操作是比简单的赋值操作更耗时 * 改进的思路:在将当前元素与他之前的元素列表比较之前,先保存一份当前元素的副本, * 如果当前元素的前一个元素>当前元素,就将当前位置的内容覆盖为前一个元素, * 这样可以减少交换的次数 * @param arr */ public static void sort3(Comparable[] arr){ int n = arr.length; Comparable temp = null; for (int i = 0; i < n; i++) { //拷贝当前元素的副本 temp = arr[i]; int j = i;//记录当前元素(外层循环的i)应该插入的位置 for( ; j > 0 && temp.compareTo(arr[j-1]) < 0 ; j--){ arr[j] = arr[j-1]; } if (i != j){ arr[j] = temp; } } } private static void swap(Object[] arr, int i, int j) { Object t = arr[i]; arr[i] = arr[j]; arr[j] = t; } // 测试InsertionSort public static void main(String[] args) { int N = 20000; Integer[] arr = SortTestHelper.generateRandomArray(N, 0, 100000); SortTestHelper.testSort("com.h.sort.InsertionSort", arr); System.out.println(Arrays.toString(arr)); }}
package com.h.sort;import java.lang.reflect.Method;/** * Created by John on 2017/8/31. */public class SortTestHelper { // SortTestHelper不允许产生任何实例 private SortTestHelper(){} // 生成有n个元素的随机数组,每个元素的随机范围为[rangeL, rangeR] public static Integer[] generateRandomArray(int n, int rangeL, int rangeR) { assert rangeL <= rangeR; Integer[] arr = new Integer[n]; for (int i = 0; i < n; i++) arr[i] = new Integer((int)(Math.random() * (rangeR - rangeL + 1) + rangeL)); return arr; } // 生成一个近乎有序的数组 // 首先生成一个含有[0...n-1]的完全有序数组, 之后随机交换swapTimes对数据 // swapTimes定义了数组的无序程度: // swapTimes == 0 时, 数组完全有序 // swapTimes 越大, 数组越趋向于无序 public static Integer[] generateNearlyOrderedArray(int n, int swapTimes){ Integer[] arr = new Integer[n]; for( int i = 0 ; i < n ; i ++ ) arr[i] = new Integer(i); for( int i = 0 ; i < swapTimes ; i ++ ){ int a = (int)(Math.random() * n); int b = (int)(Math.random() * n); int t = arr[a]; arr[a] = arr[b]; arr[b] = t; } return arr; } // 打印arr数组的所有内容 public static void printArray(Object[] arr) { for (int i = 0; i < arr.length; i++){ System.out.print( arr[i] ); System.out.print( ' ' ); } System.out.println(); return; } // 判断arr数组是否有序 public static boolean isSorted(Comparable[] arr){ for( int i = 0 ; i < arr.length - 1 ; i ++ ) if( arr[i].compareTo(arr[i+1]) > 0 ) return false; return true; } // 测试sortClassName所对应的排序算法排序arr数组所得到结果的正确性和算法运行时间 public static void testSort(String sortClassName, Comparable[] arr){ // 通过Java的反射机制,通过排序的类名,运行排序函数 try{ // 通过sortClassName获得排序函数的Class对象 Class sortClass = Class.forName(sortClassName); // 通过排序函数的Class对象获得排序方法 Method sortMethod = sortClass.getMethod("sort",new Class[]{Comparable[].class}); // 排序参数只有一个,是可比较数组arr Object[] params = new Object[]{arr}; long startTime = System.currentTimeMillis(); // 调用排序函数 sortMethod.invoke(null,params); long endTime = System.currentTimeMillis(); assert isSorted( arr ); System.out.println(isSorted( arr ) + " " + sortClass.getSimpleName()); System.out.println( sortClass.getSimpleName()+ " : " + (endTime-startTime) + "ms" ); } catch(Exception e){ e.printStackTrace(); } }}
冒泡排序
package com.h.sort;/** * Created by John on 2017/9/2. */public class BubbleSort { // 我们的算法类不允许产生任何实例 private BubbleSort(){} public static void sort(Comparable[] arr){ int n = arr.length; boolean swapped = false; //int newn; // 理论上,可以使用newn进行优化,但实际优化效果较差 do{ swapped = false; //newn = 0; for( int i = 0 ; i < n-1 ; i ++ ){ if( arr[i].compareTo(arr[i+1]) > 0 ){ swap( arr , i , i+1 ); swapped = true; // 可以记录最后一次的交换位置,在此之后的元素在下一轮扫描中均不考虑 // 实际优化效果较差,因为引入了newn这个新的变量 //newn = n; } //n = newn; // 优化, 每一趟Bubble Sort都将最大的元素放在了最后的位置 // 所以下一次排序, 最后的元素可以不再考虑 // 理论上, newn的优化是这个优化的复杂版本,应该更有效 // 实测, 使用这种简单优化, 时间性能更好 } n --; }while(swapped);//一旦swap=false,说明没有交换发生,即整个序列已经是有序的了 } private static void swap(Object[] arr, int i, int j) { Object t = arr[i]; arr[i] = arr[j]; arr[j] = t; }}
public static int[] bubbleSort2(int[] nums){ boolean swaped = false; int n = nums.length; do { swaped = false; for (int i=0;i<n-1;i++){ if (nums[i] > nums[i+1]){ swap(nums,i,i+1); swaped = true; } } n--; }while (swaped); return nums; }
希尔排序
/** * 希尔排序 * 缩小增量排序 * http://blog.csdn.net/jianyuerensheng/article/details/51258460 * @param nums * @return */ public static int[] shellSort(int[] nums){ int size = nums.length; int increment = size/2; while (increment >=1){ if (increment == 1){//当步长=1时候,说明整个序列已经是基本有序了,需要对整个序列进行插入排序 insertionSort2(nums); return nums; } //下面的循环是为了让整个序列基本有序 for (int i=0;i<increment;i++){ //增量比较 if (nums[i] > nums[i+increment]){ swap(nums,i,i+increment); } } increment = increment/2; } return nums; } public static void shellSortSmallToBig(int[] data) { int j = 0; int temp = 0; for (int increment = data.length / 2; increment > 0; increment /= 2) { System.out.println("increment:" + increment); for (int i = increment; i < data.length; i++) { temp = data[i]; for (j = i - increment; j >= 0; j -= increment) { if (temp < data[j]) { data[j + increment] = data[j]; } else { break; } } data[j + increment] = temp; } for (int i = 0; i < data.length; i++) System.out.print(data[i] + " "); } } public static int[] shellSort2(int[] arr){ int n = arr.length; // 计算步长序列 increment sequence: 1, 4, 13, 40, 121, 364, 1093... int h = 1; while (h < n/3) h = 3*h + 1; while (h >= 1) { // h-sort the array for (int i = h; i < n; i++) { // 对 arr[i], arr[i-h], arr[i-2*h], arr[i-3*h]... 使用插入排序 int e = arr[i]; int j = i; for ( ; j >= h && (e < (arr[j-h])); j -= h) arr[j] = arr[j-h]; arr[j] = e; } h /= 3; } return arr; }
package com.h.sort;/** * Created by John on 2017/9/3. */public class ShellSort { // 我们的算法类不允许产生任何实例 private ShellSort(){} public static void sort(Comparable[] arr){ int n = arr.length; // 计算步长序列 increment sequence: 1, 4, 13, 40, 121, 364, 1093... int h = 1; while (h < n/3) h = 3*h + 1; while (h >= 1) { // h-sort the array for (int i = h; i < n; i++) { // 对 arr[i], arr[i-h], arr[i-2*h], arr[i-3*h]... 使用插入排序 Comparable e = arr[i]; int j = i; for ( ; j >= h && e.compareTo(arr[j-h]) < 0 ; j -= h) arr[j] = arr[j-h]; arr[j] = e; } h /= 3; } }}
package com.h.sort;import java.util.Arrays;/** * Created by John on 2017/8/31. */public class Main { // 比较SelectionSort, InsertionSort和BubbleSort和ShellSort四种排序算法的性能效率 // ShellSort是这四种排序算法中性能最优的排序算法 public static void main(String[] args) { int N = 20000; // 测试1 一般测试 System.out.println("Test for random array, size = " + N + " , random range [0, " + N + "]"); Integer[] arr1 = SortTestHelper.generateRandomArray(N, 0, N); Integer[] arr2 = Arrays.copyOf(arr1, arr1.length); Integer[] arr3 = Arrays.copyOf(arr1, arr1.length); Integer[] arr4 = Arrays.copyOf(arr1, arr1.length); SortTestHelper.testSort("com.h.sort.SelectionSort", arr1); SortTestHelper.testSort("com.h.sort.InsertionSort", arr2); SortTestHelper.testSort("com.h.sort.BubbleSort", arr3); SortTestHelper.testSort("com.h.sort.ShellSort", arr4); System.out.println(); // 测试2 测试近乎有序的数组 int swapTimes = 100; System.out.println("Test for nearly ordered array, size = " + N + " , swap time = " + swapTimes); arr1 = SortTestHelper.generateNearlyOrderedArray(N, swapTimes); arr2 = Arrays.copyOf(arr1, arr1.length); arr3 = Arrays.copyOf(arr1, arr1.length); arr4 = Arrays.copyOf(arr1, arr1.length); SortTestHelper.testSort("com.h.sort.SelectionSort", arr1); SortTestHelper.testSort("com.h.sort.InsertionSort", arr2); SortTestHelper.testSort("com.h.sort.BubbleSort", arr3); SortTestHelper.testSort("com.h.sort.ShellSort", arr4); return; }}
归并排序
package com.h.sort;import java.util.Arrays;/** * Created by John on 2017/9/3. */public class MergeSort{ // 我们的算法类不允许产生任何实例 private MergeSort(){} // 将arr[l...mid]和arr[mid+1...r]两部分进行归并 private static void merge(Comparable[] arr, int l, int mid, int r) { Comparable[] aux = Arrays.copyOfRange(arr, l, r+1); // 初始化,i指向左半部分的起始索引位置l;j指向右半部分起始索引位置mid+1 int i = l, j = mid+1; for( int k = l ; k <= r; k ++ ){ if( i > mid ){ // 如果左半部分元素已经全部处理完毕 arr[k] = aux[j-l]; j ++; } else if( j > r ){ // 如果右半部分元素已经全部处理完毕 arr[k] = aux[i-l]; i ++; } else if( aux[i-l].compareTo(aux[j-l]) < 0 ){ // 左半部分所指元素 < 右半部分所指元素 arr[k] = aux[i-l]; i ++; } else{ // 左半部分所指元素 >= 右半部分所指元素 arr[k] = aux[j-l]; j ++; } } } // 递归使用归并排序,对arr[l...r]的范围进行排序 private static void sort(Comparable[] arr, int l, int r) { if (l >= r) return; int mid = (l+r)/2; sort(arr, l, mid); sort(arr, mid + 1, r); merge(arr, l, mid, r); } public static void sort(Comparable[] arr){ int n = arr.length; sort(arr, 0, n-1); } // 测试MergeSort public static void main(String[] args) { // Merge Sort是我们学习的第一个O(nlogn)复杂度的算法 // 可以在1秒之内轻松处理100万数量级的数据 // 注意:不要轻易尝试使用SelectionSort, InsertionSort或者BubbleSort处理100万级的数据 // 否则,你就见识了O(n^2)的算法和O(nlogn)算法的本质差异:) int N = 1000000; Integer[] arr = SortTestHelper.generateRandomArray(N, 0, 100000); SortTestHelper.testSort("com.h.sort.MergeSort", arr); return; }}
归并排序的优化
package com.h.sort;import java.util.Arrays;/** * Created by John on 2017/9/3. * 优化的Merge Sort算法 * 自顶向下 */public class MergeSort{ // 我们的算法类不允许产生任何实例 private MergeSort(){} // 将arr[l...mid]和arr[mid+1...r]两部分进行归并 private static void merge(Comparable[] arr, int l, int mid, int r) { Comparable[] aux = Arrays.copyOfRange(arr, l, r+1); // 初始化,i指向左半部分的起始索引位置l;j指向右半部分起始索引位置mid+1 int i = l, j = mid+1; for( int k = l ; k <= r; k ++ ){ if( i > mid ){ // 如果左半部分元素已经全部处理完毕 arr[k] = aux[j-l]; j ++; } else if( j > r ){ // 如果右半部分元素已经全部处理完毕 arr[k] = aux[i-l]; i ++; } else if( aux[i-l].compareTo(aux[j-l]) < 0 ){ // 左半部分所指元素 < 右半部分所指元素 arr[k] = aux[i-l]; i ++; } else{ // 左半部分所指元素 >= 右半部分所指元素 arr[k] = aux[j-l]; j ++; } } } // 递归使用归并排序,对arr[l...r]的范围进行排序 private static void sort(Comparable[] arr, int l, int r) { // 优化2: 对于小规模数组, 使用插入排序 if( r - l <= 15 ){ InsertionSort.sort(arr, l, r); return; } int mid = (l+r)/2; sort(arr, l, mid); sort(arr, mid + 1, r); // 优化1: 对于arr[mid] <= arr[mid+1]的情况,不进行merge // 对于近乎有序的数组非常有效,但是对于一般情况,有一定的性能损失 if( arr[mid].compareTo(arr[mid+1]) > 0 ) merge(arr, l, mid, r); } public static void sort(Comparable[] arr){ int n = arr.length; sort(arr, 0, n-1); } // 测试MergeSort2 public static void main(String[] args) { // Merge Sort是我们学习的第一个O(nlogn)复杂度的算法 // 可以在1秒之内轻松处理100万数量级的数据 // 注意:不要轻易尝试使用SelectionSort, InsertionSort或者BubbleSort处理100万级的数据 // 否则,你就见识了O(n^2)的算法和O(nlogn)算法的本质差异:) int N = 1000000; Integer[] arr = SortTestHelper.generateRandomArray(N, 0, 100000); SortTestHelper.testSort("com.h.sort.MergeSort", arr); return; }}
InsertionSort.sort()
// 对arr[l...r]的区间使用InsertionSort排序 public static void sort(Comparable[] arr, int l, int r){ assert l >= 0 && l <= r && r < arr.length; for( int i = l + 1 ; i <= r ; i ++ ){ Comparable e = arr[i]; int j = i; for( ; j > l && arr[j-1].compareTo(e) > 0 ; j--) arr[j] = arr[j-1]; arr[j] = e; } }
采用自底向上的归并排序
package com.h.sort;import java.util.Arrays;/** * Created by John on 2017/9/3. */public class MergeSortBU{ // 我们的算法类不允许产生任何实例 private MergeSortBU(){} // 将arr[l...mid]和arr[mid+1...r]两部分进行归并 private static void merge(Comparable[] arr, int l, int mid, int r) { Comparable[] aux = Arrays.copyOfRange(arr, l, r+1); // 初始化,i指向左半部分的起始索引位置l;j指向右半部分起始索引位置mid+1 int i = l, j = mid+1; for( int k = l ; k <= r; k ++ ){ if( i > mid ){ // 如果左半部分元素已经全部处理完毕 arr[k] = aux[j-l]; j ++; } else if( j > r ){ // 如果右半部分元素已经全部处理完毕 arr[k] = aux[i-l]; i ++; } else if( aux[i-l].compareTo(aux[j-l]) < 0 ){ // 左半部分所指元素 < 右半部分所指元素 arr[k] = aux[i-l]; i ++; } else{ // 左半部分所指元素 >= 右半部分所指元素 arr[k] = aux[j-l]; j ++; } } } public static void sort(Comparable[] arr){ int n = arr.length; // Merge Sort Bottom Up 无优化版本// for (int sz = 1; sz < n; sz *= 2)// for (int i = 0; i < n - sz; i += sz+sz)// // 对 arr[i...i+sz-1] 和 arr[i+sz...i+2*sz-1] 进行归并// merge(arr, i, i+sz-1, Math.min(i+sz+sz-1,n-1)); // Merge Sort Bottom Up 优化 // 对于小数组, 使用插入排序优化 for( int i = 0 ; i < n ; i += 16 ) InsertionSort.sort(arr, i, Math.min(i+15, n-1) ); /** * 自底向上的排序方法针对链表的排序 */ for( int sz = 16; sz < n ; sz += sz ) for( int i = 0 ; i < n - sz ; i += sz+sz ) // 对于arr[mid] <= arr[mid+1]的情况,不进行merge if( arr[i+sz-1].compareTo(arr[i+sz]) > 0 ) merge(arr, i, i+sz-1, Math.min(i+sz+sz-1,n-1) ); } // 测试 MergeSort BU public static void main(String[] args) { // Merge Sort BU 也是一个O(nlogn)复杂度的算法,虽然只使用两重for循环 // 所以,Merge Sort BU也可以在1秒之内轻松处理100万数量级的数据 // 注意:不要轻易根据循环层数来判断算法的复杂度,Merge Sort BU就是一个反例 // 关于这部分陷阱,推荐看我的《玩转算法面试》课程,第二章:《面试中的复杂度分析》:) int N = 1000000; Integer[] arr = SortTestHelper.generateRandomArray(N, 0, 100000); SortTestHelper.testSort("com.h.sort.MergeSortBU", arr); return; }}
阅读全文
0 0
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- 排序算法
- combox的change事件触发另一个combox下拉框显示数据清空
- ACM随笔 17.8.31
- www服务器
- C语言实现插入排序
- openstack中API调用源码分析
- 排序算法
- Windows下编译tensorflow-gpu教程
- 面向服务的体系架构(SOA)
- 利用warpPerspective进行图像缩放
- 正态分布的前世今生
- java中静态内部类和非静态内部类的区别
- 设计模式之迪米特法则
- 拜访-动态规划
- 欢迎使用CSDN-markdown编辑器