七大排序算法的研究与总结
来源:互联网 发布:阿里妈妈淘宝联盟客服 编辑:程序博客网 时间:2024/06/05 09:21
本文章描述了7大排序算法内容与实现,使用语言为java,代码贴在最后,可根据需要快速定位。由于笔者水平有限,有错误之处请指出,不足之处请包涵。
1.七大算法基本内容
2.算法比较与选择
3.代码实现与结果
1.七大算法基本内容
七大排序算法:冒泡排序,选择排序,直接插入排序,希尔排序,快速排序,堆排序,归并排序。
由于升序和降序逻辑一样,这里只讨论升序。
1.1. 冒泡排序:
算法简述:将元素中最大的元素依次移动到最后。
算法详细:
- 从开始到结尾依次比较相邻的元素,如果第一个比第二个大,就交换他们两个。(一趟过后,最大的元素移动到了最后。)
- 将最后的元素排除在下面操作之外。(最后元素已经是最大,无需重复比较)
- 重复1,2,直到没有任何一对元素需要比较。
1.2. 选择排序:
算法简述:将待排序的元素中最大的元素选出放到最后。
算法详细:
- 将待排序元素中第一个元素视为最小值,依次与后面元素做比较,若被比较元素小,则更新最小值。(一趟过后,选出最小值)
- 比较最小值与待排序元素的第一个元素,若相同则跳过,若不同,则交换最小元素与待排序元素的第一元素位置。(前面的元素慢慢有序化)
- 重复1,2,直到没有待排序元素。
1.3. 直接插入排序:
算法简述:每次从无序表中取出第一个元素,把它插入到有序表的合适位置,使有序表仍然有序。
算法详细:
- 起初将第一个元素视为有续,将无序表中第一个数与有序表作比较,插入到合适位置。
- 重复1,直到无序表没有元素。
1.4. 希尔排序:
算法简述:希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。
算法详细:
- 先取一个小于前一增量或小于n的整数作为增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。
- 对每一组中元素进行直接插入排序。
- 重复1,2直到增量等于0为止。
1.5. 快速排序:
算法简述:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
算法详细:
- 设置两个变量 i、j,排序开始的时候:i=0,j=N-1;以第一个数组元素作为关键数据,赋值给key,即key=A[0];
- 从 j 开始向前搜索,即由后开始向前搜索( j--),找到第一个小于key的值A[ j ],将A[ j ]和A[ i ]互换;
- 从 i 开始向后搜索,即由前开始向后搜索( i++),找到第一个大于key的A[ i ],将A[ i ]和A[ j ]互换;
- 重复2,3直到 i = j 为止。
- 将数组以 i 分为两部分,递归执行1,2,3,4,5.直到数组不能再分为止。
1.6. 堆排序:
算法简述:堆排序(Heapsort)是指利用堆积树(每个节点的值不大于其根节点的完全二叉树)这种数据结构所设计的一种排序,它是选择排序的一种,当数据很多时极大的减少了比较次数;数据量少时不适用。
算法详细:
- 建立大根堆。
- 将顶端元素与无序区最后元素交换,然后调整无序区堆为大根堆(调整堆)。
- 重复2,直到无序区元素为空。
建立大根堆算法:
- 从数组的 length / 2 处节点调整堆,依次到第一个节点。
调整堆算法:
- 将节点与其左右孩子比较,选出最大值。
- 若最大值为自己则结束,最大值为其孩子,则节点与孩子交换,并对其孩子进行1,2.直到结束。
1.7. 归并排序:
算法简述:将序列分为若干序列,对序列排序,然后将已有序序列两两合并并调整,直到没有序列可合并,得到完全有序的序列。
算法详细:
- 将序列依次中分为两序列,直到不能再分为止。
- 申请空间,使其大小为两个已排序序列之和,该空间用来存放合并后的序列。
- 将两序列中最小者依次放入1所申请空间类。
- 重复2,3,直到所有序列合并完成。
- (注意)分割与合并是相对的,即分割成的两序列会排序后会合并在一起。
2.算法比较与选择
2.1. 算法比较
2.2. 选择
笔者测试数据容量范围为:10-100000,结论如下:
数据量较小(笔者的程序n<80)时,直接插入排序最佳(稳定且快速)。
通常情况下(100<n<100000),快速排序最优。
数据量超大时(至少n>100000吧),选择堆排序,归并排序。(其它网友总结)
以下是其它网友关于排序的测试结果与选择总结。
http://www.360doc.com/content/14/0813/19/16948208_401618179.shtml
3. 代码实现与结果
由于笔者偷懒,把所有排序算法写到一个文件中了,后面测试时发现使用策略模式代码更清晰直观,有兴趣的网友可以试试。
3.1. 排序代码:
public class SortBase2 { /** * 冒泡排序. * @param nums ( 需要排序的数组) * @return */ public void bubbleSort(int[] nums){ int temp; for (int i = 0; i < nums.length - 1; i++){ for (int j = 0; j < nums.length - 1 - i; j++){ if(nums[j] > nums[j+1]){ temp = nums[j]; nums[j] = nums[j+1]; nums[j+1] = temp; } } } } /** * 选择排序. * ( 每一次从待排序的数据元素中选出最小(或最大)的一个元素, * 存放在序列的起始位置,直到全部待排序的数据元素排完. ) * @param nums */ public void selectSort(int[] nums){ int temp; int minIndex; for (int i = 0; i < nums.length; i++){ minIndex = i; for(int j = i + 1; j < nums.length; j++ ){ if(nums[minIndex] > nums[j]){ minIndex = j; } } if(minIndex != i){ temp = nums[i]; nums[i] = nums[minIndex]; nums[minIndex] = temp; } } } /** * 直接插入排序. * 描述:每次从无序表中取出第一个元素,把它插入到有序表的合适位置,使有序表仍然有序。 * @param nums ( 需要排序的数组) */ public void insertSort(int[] nums){ int temp; for (int i = 1; i < nums.length; i++){ for (int j = 0; j < i; j++){ if(nums[i] < nums[j]){ temp = nums[i]; for(int k = i; k > j; k--){ nums[k] = nums[k-1]; } nums[j] = temp; break; } } } } /** * 直接插入排序2. * 改进:从后面开始比较,并同时后移。较少了比较次数。 * @param nums */ public void insertSort2(int[] nums){ int temp; for (int i = 0; i < nums.length; i++){ for (int j = i - 1; j >= 0; j--){ if (nums[j+1] < nums[j]){ temp = nums[j]; nums[j] = nums[j+1]; nums[j+1] = temp; } else { break; } } } } /** * 直接插入排序3. * 改进:从后面开始比较,并同时后移,和2相比减少交换次数。 * @param nums */ public void insertSort3(int[] nums){ int temp; for (int i = 1; i < nums.length; i++){ if(nums[i] < nums[i-1]){ temp = nums[i]; int j = i - 1; for (; j >= 0 && temp < nums[j]; j--){ nums[j+1] = nums[j]; } nums[j+1] = temp; } } } /** * 希尔排序. * @param nums ( 需要排序的数组) * @return */ public void shellSort(int[] nums){ int temp; int increment = nums.length; while (increment > 1){ increment /= 2; for (int i = increment; i < nums.length; i++){ if (nums[i] < nums[i - increment]){ temp = nums[i]; int j = i - increment; for(; j >= 0 && nums[j] > temp; j -= increment){ nums[j + increment] = nums[j]; } nums[j + increment] = temp; } } } } /** * 快速排序. * @param nums * @param low * @param high */ public void quicklySort(int[] nums) { int low = 0; int high = nums.length - 1; quicklySort(nums, low, high); } public void quicklySort(int[] nums, int low, int high) { int mid; if (low < high) { mid = partition(nums, low, high); quicklySort(nums, low, mid - 1); quicklySort(nums, mid + 1, high); } } // 快排辅助程序 private int partition(int[] nums, int low, int high) { int key = nums[low]; while(low < high){ while(low < high && nums[high] >= key){ high--; } if (low < high){ nums[low] = nums[high]; } while(low < high && nums[low] <= key){ low++; } if (low < high){ nums[high] = nums[low]; } } nums[low] = key; return low; } /** * 快速排序2. * @param nums * @param low * @param high */ public void quicklySort2(int[] nums) { int low = 0; int high = nums.length - 1; quicklySort2(nums, low, high); } public void quicklySort2(int[] nums, int low, int high) { int mid; if(low < high){ mid = partition2(nums, low, high); quicklySort2(nums, low, mid - 1); quicklySort2(nums, mid + 1, high); } } private int partition2(int[] nums, int low, int high){ int key = nums[low]; while(low < high){ while(low < high && key <= nums[high]){ high -- ; } nums[low] = nums[high];// 差别之处,虽然可能会出现nums[10]=nums[10]这样没有意义的赋值,但减少if的比较与判断时间。 while(low < high && key >= nums[low]){ low ++ ; } nums[high] = nums[low]; // 差别之处 } nums[low] = key; return low; } /** * 堆排序. * @param nums * @return */ public void heapSort(int[] nums){ int temp; // 构建堆 for (int i = nums.length / 2; i >= 0 ; i--){ heapAdjust(nums, nums.length, i); } // 最大的放在后面并重构堆 for(int i = nums.length - 1; i > 0; i--){ temp = nums[0]; nums[0] = nums[i]; nums[i] = temp; heapAdjust(nums, i, 0); } } /** * 调整堆. * @param nums * @param size * @param index */ private void heapAdjust(int[] nums, int size, int index){ int left = (index << 1) + 1; int right = (index << 1) + 2; int largest = index; if(left < size && nums[left] > nums[largest]){ largest = left; } if(right < size && nums[right] > nums[largest]){ largest = right; } if(largest != index){ int temp = nums[index]; nums[index] = nums[largest]; nums[largest] = temp; heapAdjust(nums, size, largest); } } /** * 并归排序 * @param nums * @return */ public void mergingSort(int[] nums){ int tail = nums.length - 1; sortSplit(nums, 0, tail); } /** * 分割数组. * @param nums * @param head * @param tail */ public void sortSplit(int[] nums, int head, int tail){ if(head >= tail){ return; } int mid = (head + tail) / 2; sortSplit(nums, head, mid); sortSplit(nums, mid + 1, tail); merging(nums, head, mid + 1, tail); } /** * 合并数组 * @param nums * @param start1 第一个有序表的起始下标 * @param start2 第二个有序表的起始下标 * @param tail 第二个有序表的结束小标 * @return */ public void merging(int[] nums, int s1, int s2, int tail){ if(s1 >= tail){ return; } int[] tempArray = new int[tail - s1 + 1]; int index1 = s1; int index2 = s2; int i = 0; while(index1 < s2 && index2 <= tail){ if(nums[index1] < nums[index2]){ tempArray[i] = nums[index1++]; }else{ tempArray[i] = nums[index2++]; } i++; } // 剩下的补齐 while(index1 < s2){ tempArray[i++] = nums[index1++]; } while(index2 <= tail){ tempArray[i++] = nums[index2++]; } // 放入原数组 for(int j = 0; j < tempArray.length; j++){ nums[s1++] = tempArray[j]; } }}
3.2. 测试辅助代码
public class ProduceArray { /** * 产生0-999的随机数组. * @param amount (数组容量) * @return */ public int[] produceArray(int amount){ int[] array = new int[amount] ; for (int i = 0; i < amount; i++){ array[i] = (int) (Math.random()*1000); } return array; } /** * 打印数组。 * @param array */ public void printArray(int[] array){ for (int i:array){ System.out.print(i + " "); } System.out.println(); }}
3.3. 测试程序代码:
import java.util.Arrays;public class Test2 { int times = 10; // 测试次数 int count = 10000; // 数组容量 /** * @param args */ public static void main(String[] args) { System.out.println("start"); Test2 mytest = new Test2(); ProduceArray pa = new ProduceArray(); int[][] array = new int[mytest.times][]; for(int i = 0; i < array.length; i++){ array[i] = pa.produceArray(mytest.count); // 生成随机数组。// pa.printArray(array[i]); } mytest.bubbleSortTest(array);// 冒泡排序 mytest.selectSortTest(array);// 选择排序 mytest.insertSortTest(array);// 插入排序 mytest.insertSortTest2(array); mytest.insertSortTest3(array); mytest.shellSortTest(array); mytest.quicklySort(array); mytest.quicklySort2(array); mytest.heapSort(array); mytest.mergingSort(array); } public void bubbleSortTest(int[][] a){ ProduceArray pa = new ProduceArray(); SortBase mybbSort = new SortBase(); int[][] array = Arrays.copyOf(a, a.length);// 复制a的二维结构 int[] arrayTemp;// 零时数组 long start;// 记录排序运行开始时间 long end;// 记录排序运行结束时间 long[] times = new long[a.length];// 记录排序运行时间 long time = 0;// 第time次测试 for(int i = 0; i < a.length; i++){ arrayTemp = Arrays.copyOf(array[i], array[i].length); start = System.nanoTime();// 纳秒级时间,基本能够满足测试精度需要 mybbSort.bubbleSort(arrayTemp);// 调用排序 end = System.nanoTime(); times[i] = end - start; array[i] = arrayTemp; } for(long t : times){ time += t; } time /= times.length;// 算出平均运行时间 System.out.println("冒泡排序结果:"); if(array[0].length < 20){// 数组容量小于20时打印数组,大于20打印平均运行时间。 for(int[] temp : array){ pa.printArray(temp); } }else{ System.out.println("平均运行时间: " + (time)); } } // 与前面冒泡排序的测试相同,只是调用的排序方法不同,更清晰直观的写法是使用策略模式来写,这里笔者先写的排序算法文件,所以偷懒了,下同。 public void selectSortTest(int[][] a){ ProduceArray pa = new ProduceArray(); SortBase mybbSort = new SortBase(); int[][] array = Arrays.copyOf(a, a.length); int[] arrayTemp; long start; long end; long[] times = new long[a.length]; long time = 0; for(int i = 0; i < a.length; i++){ arrayTemp = Arrays.copyOf(array[i], array[i].length); start = System.nanoTime(); mybbSort.selectSort(arrayTemp);// 这里是不同 end = System.nanoTime(); times[i] = end - start; array[i] = arrayTemp; } for(long t : times){ time += t; } time /= times.length; System.out.println("选择排序结果:"); if(array[0].length < 20){ for(int[] temp : array){ pa.printArray(temp); } }else{ System.out.println("平均运行时间: " + (time)); } } public void insertSortTest(int[][] a){ ProduceArray pa = new ProduceArray(); SortBase mybbSort = new SortBase(); int[][] array = Arrays.copyOf(a, a.length); int[] arrayTemp; long start; long end; long[] times = new long[a.length]; long time = 0; for(int i = 0; i < a.length; i++){ arrayTemp = Arrays.copyOf(array[i], array[i].length); start = System.nanoTime(); mybbSort.insertSort(arrayTemp); end = System.nanoTime(); times[i] = end - start; array[i] = arrayTemp; } for(long t : times){ time += t; } time /= times.length; System.out.println("直接插入排序结果:"); if(array[0].length < 20){ for(int[] temp : array){ pa.printArray(temp); } }else{ System.out.println("平均运行时间: " + (time)); } } public void insertSortTest2(int[][] a){ ProduceArray pa = new ProduceArray(); SortBase mybbSort = new SortBase(); int[][] array = Arrays.copyOf(a, a.length); int[] arrayTemp; long start; long end; long[] times = new long[a.length]; long time = 0; for(int i = 0; i < a.length; i++){ arrayTemp = Arrays.copyOf(array[i], array[i].length); start = System.nanoTime(); mybbSort.insertSort2(arrayTemp); end = System.nanoTime(); times[i] = end - start; array[i] = arrayTemp; } for(long t : times){ time += t; } time /= times.length; System.out.println("直接插入排序2结果:"); if(array[0].length < 20){ for(int[] temp : array){ pa.printArray(temp); } }else{ System.out.println("平均运行时间: " + (time)); } } public void insertSortTest3(int[][] a){ ProduceArray pa = new ProduceArray(); SortBase mybbSort = new SortBase(); int[][] array = Arrays.copyOf(a, a.length); int[] arrayTemp; long start; long end; long[] times = new long[a.length]; long time = 0; for(int i = 0; i < a.length; i++){ arrayTemp = Arrays.copyOf(array[i], array[i].length); start = System.nanoTime(); mybbSort.insertSort3(arrayTemp); end = System.nanoTime(); times[i] = end - start; array[i] = arrayTemp; } for(long t : times){ time += t; } time /= times.length; System.out.println("直接插入排序3结果:"); if(array[0].length < 20){ for(int[] temp : array){ pa.printArray(temp); } }else{ System.out.println("平均运行时间: " + (time)); } } public void shellSortTest(int[][] a){ ProduceArray pa = new ProduceArray(); SortBase mybbSort = new SortBase(); int[][] array = Arrays.copyOf(a, a.length); int[] arrayTemp; long start; long end; long[] times = new long[a.length]; long time = 0; for(int i = 0; i < a.length; i++){ arrayTemp = Arrays.copyOf(array[i], array[i].length); start = System.nanoTime(); mybbSort.shellSort(arrayTemp); end = System.nanoTime(); times[i] = end - start; array[i] = arrayTemp; } for(long t : times){ time += t; } time /= times.length; System.out.println("希尔排序结果:"); if(array[0].length < 20){ for(int[] temp : array){ pa.printArray(temp); } }else{ System.out.println("平均运行时间: " + (time)); } } public void quicklySort(int[][] a){ ProduceArray pa = new ProduceArray(); SortBase mybbSort = new SortBase(); int[][] array = Arrays.copyOf(a, a.length); int[] arrayTemp; long start; long end; long[] times = new long[a.length]; long time = 0; for(int i = 0; i < a.length; i++){ arrayTemp = Arrays.copyOf(array[i], array[i].length); start = System.nanoTime(); mybbSort.quicklySort(arrayTemp); end = System.nanoTime(); times[i] = end - start; array[i] = arrayTemp; } for(long t : times){ time += t; } time /= times.length; System.out.println("快速排序结果:"); if(array[0].length < 20){ for(int[] temp : array){ pa.printArray(temp); } }else{ System.out.println("平均运行时间: " + (time)); } } public void quicklySort2(int[][] a){ ProduceArray pa = new ProduceArray(); SortBase mybbSort = new SortBase(); int[][] array = Arrays.copyOf(a, a.length); int[] arrayTemp; long start; long end; long[] times = new long[a.length]; long time = 0; for(int i = 0; i < a.length; i++){ arrayTemp = Arrays.copyOf(array[i], array[i].length); start = System.nanoTime(); mybbSort.quicklySort2(arrayTemp); end = System.nanoTime(); times[i] = end - start; array[i] = arrayTemp; } for(long t : times){ time += t; } time /= times.length; System.out.println("快速排序2结果:"); if(array[0].length < 20){ for(int[] temp : array){ pa.printArray(temp); } }else{ System.out.println("平均运行时间: " + (time)); } } public void heapSort(int[][] a){ ProduceArray pa = new ProduceArray(); SortBase mybbSort = new SortBase(); int[][] array = Arrays.copyOf(a, a.length); int[] arrayTemp; long start; long end; long[] times = new long[a.length]; long time = 0; for(int i = 0; i < a.length; i++){ arrayTemp = Arrays.copyOf(array[i], array[i].length); start = System.nanoTime(); mybbSort.heapSort(arrayTemp); end = System.nanoTime(); times[i] = end - start; array[i] = arrayTemp; } for(long t : times){ time += t; } time /= times.length; System.out.println("堆排序结果:"); if(array[0].length < 20){ for(int[] temp : array){ pa.printArray(temp); } }else{ System.out.println("平均运行时间: " + (time)); } } public void mergingSort(int[][] a){ ProduceArray pa = new ProduceArray(); SortBase mybbSort = new SortBase(); int[][] array = Arrays.copyOf(a, a.length); int[] arrayTemp; long start; long end; long[] times = new long[a.length]; long time = 0; for(int i = 0; i < a.length; i++){ arrayTemp = Arrays.copyOf(array[i], array[i].length); start = System.nanoTime(); mybbSort.mergingSort(arrayTemp); end = System.nanoTime(); times[i] = end - start; array[i] = arrayTemp; } for(long t : times){ time += t; } time /= times.length; System.out.println("并归排序结果:"); if(array[0].length < 20){ for(int[] temp : array){ pa.printArray(temp); } }else{ System.out.println("平均运行时间: " + (time)); } }}
3.4. 测试结果:
测试次数:10
数组容量:10000
时间单位:纳秒
start
冒泡排序结果:
平均运行时间: 236966562
选择排序结果:
平均运行时间: 82126896
直接插入排序结果:
平均运行时间: 68611189
直接插入排序2结果:
平均运行时间: 59882902
直接插入排序3结果:
平均运行时间: 41153782
希尔排序结果:
平均运行时间: 1392813
快速排序结果:
平均运行时间: 969936
快速排序2结果:
平均运行时间: 849098
堆排序结果:
平均运行时间: 2131108
并归排序结果:
平均运行时间: 1727959
测试次数:10000
数组容量:80
start
冒泡排序结果:
平均运行时间: 15689
选择排序结果:
平均运行时间: 8874
直接插入排序结果:
平均运行时间: 6209
直接插入排序2结果:
平均运行时间: 4893
直接插入排序3结果:
平均运行时间: 3590
希尔排序结果:
平均运行时间: 5127
快速排序结果:
平均运行时间: 3776
快速排序2结果:
平均运行时间: 3737
堆排序结果:
平均运行时间: 7203
并归排序结果:
平均运行时间: 8613
- 七大排序算法的研究与总结
- 数据结构与算法之七大排序总结
- 七大排序算法总结
- 七大排序算法总结
- 七大排序算法总结
- 七大常见排序算法总结
- 数据结构--七大排序算法总结
- 七大常见排序算法总结
- 排序算法之七大排序算法总结
- 常用的七大排序算法
- 常用的七大排序算法
- 经典算法之七大排序总结篇
- 经典算法之七大排序总结篇
- 七大排序算法总结(含优化)
- 经典算法之七大排序总结篇
- 七大排序算法之间的比较
- 七大排序算法性能的分析
- 排序算法的研究
- HttpServletRequest 各种方法总结
- java实现rabbitmq消息的发送接受
- 手写的qsort快速排序
- 广东省赛B题 Base64
- 第三章第40题 Sn=1+1/1!+1/2!+···+1/n!
- 七大排序算法的研究与总结
- Python使用QRCode模块生成二维码
- MFC学习(一)——ADO数据库编程
- 怎样去曹妃甸最深处的海边?(曹妃甸灯塔,十八家)
- 文章标题
- RabbitMQ(二)队列与消息的持久化
- Android Studio如何Format代码
- hibernate连接oracle 12c pdb
- linux 常见问题