在前面复习了三个简单排序Java数据结构和算法(三)--三大排序--冒泡、选择、插入排序,属于算法的基础,但是效率是偏低的,所以现在学习高级排序

插入排序存在的问题:

插入排序在逻辑把数据分为两部分,左边:数据是有序的,右边:数据是无序的

  上图中的元素2,是最小的数据,但是在最右边,我们需要和之前的元素进行比较,然后每个元素都要后移,直到找到应该插入的位置,这里

对于元素2来说,所有的元素都要后移一位

  这个过程将近存在N次复制,移位的次数平均N/2,所以执行效率是O(N^2)

  所以如果能以某种方式不需要一个个移动所有的中间项,就能把较小的数据项移动到左边,那么执行效率会很大的改进

希尔排序:

  希尔排序因为计算机科学家Donald L. Shell而闻名,在插入排序的基础上,增加了一个特性,大大提高插入排序的执行效率

  通过加大插入排序元素之间的间隔,且在这些有间隔的元素中进行插入排序,从而使数据项大幅度的移动。这样经过一轮排序后,然后减小

数据项的间隔再进行排序,依次进行。进行排序时数据项之间的间隔被称为增量,习惯上用h表示

在完成上面的一轮排序之后,数组中的元素已经"基本有序",我们知道插入排序对于"基本有序"的数组排序效率是很高的

如果每次插入只需要移动一到两次,算法的效率是O(N)

减小间隔:

  对于更大的数组来说,刚开始的间隔应该更大,再逐渐缩小,直到间隔变成1

  一般采用2.2来整除得到增量间隔,例如100,间隔分别是45,20,9,4,1,事实证明了这样比用2会整除会显著的改善排序效果

  还有一种很常用的间隔序列:knuth 间隔序列 3h+1

图例:

就这样可以完成排序

代码示例:

  1. public class ShellSort {
  2. private long[] elementArray;
  3. private int nItems;
  4. public ShellSort(int max) {
  5. elementArray = new long[max];
  6. nItems = 0;
  7. }
  8.  
  9. public void insert(long value) {
  10. elementArray[nItems++] = value;
  11. }
  12. public void display() {
  13. for (int i = 0; i < nItems; i++) {
  14. System.out.print(elementArray[i] + " ");
  15. }
  16. System.out.println("");
  17. }
  18.  
  19. public void sort() {  //基于knuth容量间隔的希尔排序
  20. int i, j;
  21. long temp;
  22. int h = 1;
  23. while (h <= nItems/3)  //确定容量间隔
  24. h = h*3+1;
  25.  
  26. while (h > 0) {  //保证缩小间隔最终为1
  27. for (i = h; i < nItems; i++) {
  28. temp = elementArray[i];
  29. j = i;
  30. while (j > h-1 && temp < elementArray[j-h]) {  //这里就是插入排序的逻辑了,每个间隔分组进行排序
  31. elementArray[j] = elementArray[j-h];
  32. j -= h;
  33. }
  34. elementArray[j] = temp;
  35. }
  36. h = (h-1) / 3;
  37. }
  38. }
  39. }
  40. public static void main(String[] args) {
  41. ShellSort shellSort = new ShellSort(10);
  42. shellSort.insert(7);
  43. shellSort.insert(10);
  44. shellSort.insert(1);
  45. shellSort.insert(9);
  46. shellSort.insert(2);
  47. shellSort.insert(5);
  48. shellSort.insert(8);
  49. shellSort.insert(6);
  50. shellSort.insert(4);
  51. shellSort.insert(3);
  52. shellSort.display();
  53. shellSort.sort();
  54. shellSort.display();
  55. }
  1. 输出结果:
  2. 7 10 1 9 2 5 8 6 4 3
  3. 1 2 3 4 5 6 7 8 9 10

分组间隔为2的希尔排序:

  1. public void sort1() {
  2. int i, j;
  3. long temp;
  4. int h;
  5. for (h = nItems/2; h > 0; h /= 2) {
  6. for (i = h; i < nItems; i++) {
  7. temp = elementArray[i];
  8. j = i;
  9. while (j > h-1 && temp < elementArray[j-h]) {
  10. elementArray[j] = elementArray[j-h];
  11. j -= h;
  12. }
  13. elementArray[j] = temp;
  14. }
  15. }
  16. }

相对插入排序,希尔排序稍微复杂一点,如果不能直接理解,可以参考上图,对照代码,一步步理解

希尔排序的效率:

  除非在特殊情况,否则无法从理论分析希尔排序的效率,基于各种实验,时间级从O(N^(3/2))-O(N^(7/6))

下图是速度较慢的插入排序和速度较快的快速排序、希尔排序的评估值

快速排序:

  毫无疑问,快速排序是最流行的排序算法。因为大多数情况下,快速排序的速度都是最快的,执行时间为O(N*logN)级

  快速排序本质上是把一个数组划分为两个子数组,然后递归调用为每个子数组进行快速排序而实现的

  左标记i向右移动,直到遇到比pivot大的元素停止,右标记往左移动,直到遇到比pivot小的元素的元素停止,直到i>=j

图例:

代码实现:

  1. public class QuickSort{
  2.  
  3. public void sort(int[] arr) {
  4. sort(arr, 0, arr.length - 1);
  5. }
  6.  
  7. private void sort(int[] arr, int left, int right) {
  8. if (right <= left) {
  9. return;
  10. }
  11. //切分
  12. int pivotIndex = partition(arr, left, right);
  13. sort(arr, left, pivotIndex-1);
  14. sort(arr, pivotIndex+1, right);
  15. }
  16.  
  17. private int partition(int[] arr, int left, int right) {
  18. int i = left;
  19. int j = right+1;
  20. int pivot = arr[left]; //pivot为基准元素,这里选择头文件
  21. while(true){
  22.  
  23. while(i<right && arr[++i] < pivot){} //左标记往右移动,直到遇到比pivot大的元素,或者到最右边,停止
  24.  
  25. while(j > 0 && arr[--j] > pivot){} //右标记往左移动,直到遇到比pivot小的元素,或者到最左边,停止
  26.  
  27. if(i >= j){ //如果左右标记相遇时候停止,说明没有符合的元素,跳出循环
  28. break;
  29. }else{
  30. swap(arr, i, j);//左右标记在相遇前停止,交换元素,然后继续移动
  31. }
  32. }
  33. swap(arr, left, j);//基准元素和游标相遇时所指元素交换,为最后一次交换
  34. return j;// 一趟排序完成, 返回基准元素位置(注意这里基准元素已经交换位置了)
  35. }
  36.  
  37. private void swap(int[] arr, int i, int j){
  38. int temp = arr[i];
  39. arr[i] = arr[j];
  40. arr[j] = temp;
  41. }
  42. }
  1. public static void main(String[] args) {
  2. int []arr = new int[]{7, 10, 1, 9, 2, 5, 8, 6, 4, 3 };
  3. for (int i = 0; i < arr.length; i++) {
  4. System.out.print(arr[i] + " ");
  5. }
  6. System.out.println("");
  7. QuickSort quickSort = new QuickSort();
  8. quickSort.sort(arr);
  9. for (int i = 0; i < arr.length; i++) {
  10. System.out.print(arr[i] + " ");
  11. }
  12. }
  1. 输出结果:
  2. 7 10 1 9 2 5 8 6 4 3
  3. 1 2 3 4 5 6 7 8 9 10

  个人感觉快速排序思想很好理解,但是有的代码实现方式,看的真的很头疼,以下代码来自:公众号< 五分钟学算法>,相对于上面代码,不利于理解

  1. public class QuickSort{
  2.  
  3. public static void sort(int[] arr) {
  4. sort(arr, 0, arr.length - 1);
  5. }
  6.  
  7. private static void sort(int[] arr, int startIndex, int endIndex) {
  8. if (endIndex <= startIndex) {
  9. return;
  10. }
  11. //切分
  12. int pivotIndex = partition(arr, startIndex, endIndex);
  13. sort(arr, startIndex, pivotIndex-1);
  14. sort(arr, pivotIndex+1, endIndex);
  15. }
  16.  
  17. private static int partition(int[] arr, int startIndex, int endIndex) {
  18. int pivot = startIndex;//取基准值
  19. int index = pivot + 1;//Mark初始化为起始下标
  20.  
  21. for(int i = index; i <= endIndex; i++){
  22. if(arr[i] < arr[pivot]){
  23. //小于基准值 则mark+1,并交换位置。
  24. swap(arr, i, index);
  25. index ++;
  26. }
  27. }
  28. //基准值与mark对应元素调换位置
  29. swap(arr, pivot, index - 1);
  30. return index - 1;
  31. }
  32.  
  33. private static void swap(int[] arr, int i, int j) {
  34. int temp = arr[i];
  35. arr[i] = arr[j];
  36. arr[j] = temp;
  37. }
  38. }

  这里代码实现只是左标记从左向右移动,都没有右标记的概念,和他的图解都不一样,理解难度很大

PS:算法理解思想不难,但是手写就有难度了,特别是过了一段时间,很难完全写正确,可以隔段时间写一次,加深记忆,也可以在letcode上刷题

内容参考:<Java数据结构和算法>

Java数据结构和算法(九)——高级排序

Java数据结构和算法(五)--希尔排序和快速排序的更多相关文章

  1. Java数据结构和算法(三)--三大排序--冒泡、选择、插入排序

    三大排序在我们刚开始学习编程的时候就接触过,也是刚开始工作笔试会遇到的,后续也会学习希尔.快速排序,这里顺便复习一下 冒泡排序: 步骤: 1.从首位开始,比较首位和右边的索引 2.如果当前位置比右边的 ...

  2. Java数据结构和算法(五)——队列

    队列.queue,就是现实生活中的排队. 1.简单队列: public class Queqe { private int array[]; private int front; private in ...

  3. Java数据结构与算法(2) - ch03排序(冒泡、插入和选择排序)

    排序需要掌握的有冒泡排序,插入排序和选择排序.时间为O(N*N). 冒泡排序: 外层循环从后往前,内存循环从前往后到外层循环,相邻数组项两两比较,将较大的值后移. 插入排序: 从排序过程的中间开始(程 ...

  4. JAVA数据结构和算法 3-简单排序

    排序中的两种基本操作是比较和交换.在插入排序中还有移动. 冒泡排序:两两比较相邻元素,如果较大数位于较小数前面,则交换: 每一趟遍历将一个最大的数移到序列末尾,共遍历N-1趟. 如果执行完一趟之后没有 ...

  5. 【Java数据结构与算法】简单排序、二分查找和异或运算

    简单排序 选择排序 概念 首先,找到数组中最小的那个元素,其次,把它和数组的第一个元素交换位置(如果第一个元素就是最小的元素那么它就和自己交换).再次,在剩下的元素中找到最小的元素,将它与数组的第二个 ...

  6. Java数据结构和算法(九)——高级排序

    春晚好看吗?不存在的!!! 在Java数据结构和算法(三)——冒泡.选择.插入排序算法中我们介绍了三种简单的排序算法,它们的时间复杂度大O表示法都是O(N2),如果数据量少,我们还能忍受,但是数据量大 ...

  7. Java数据结构和算法(二)--队列

    上一篇文章写了栈的相关知识,而本文会讲一下队列 队列是一种特殊的线性表,在尾部插入(入队Enqueue),从头部删除(出队Dequeue),和栈的特性相反,存取数据特点是:FIFO Java中queu ...

  8. Java数据结构和算法 - 高级排序

    希尔排序 Q: 什么是希尔排序? A: 希尔排序因计算机科学家Donald L.Shell而得名,他在1959年发现了希尔排序算法. A: 希尔排序基于插入排序,但是增加了一个新的特性,大大地提高了插 ...

  9. Java数据结构和算法 - 简单排序

    Q: 冒泡排序? A: 1) 比较相邻的元素.如果第一个比第二个大,就交换它们两个; 2) 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对.在这一点,最后的元素应该会是最大的数; 3) 针 ...

随机推荐

  1. FileWriter 写文件

    FileWriter fw = new FileWriter("C://Users//pc//Desktop//aaa.txt",true); fw.write("201 ...

  2. HDU - 6016 Count the Sheep 二分图+思维

    Count the Sheep 题意: 问题描述 开学翘课固然快乐,然而也有让呃喵抓狂的事,那当然就是考试了!这可急坏了既要翘课又想要打BC还要准备考试的呃喵. 呃喵为了准备考试没有时间刷题,想打BC ...

  3. Django - 导出项目依赖库到 requirements.txt

    两种方法: 虚拟环境: 使用 pip freeze pip freeze > requirements.txt # 这种方式推荐配合 virtualenv ,否则会把整个环境中的包都列出来. 只 ...

  4. 51nod 1099【贪心】

    思路: 我们可以思考对于仅仅两个元素来说,A,B; 先选A的话是会  A.b+B.a; 先选B的话是会 B.b+A.a; 所以哪个小哪个就放前面; #include <cstdio> #i ...

  5. jpa使用原生SQL查询数据库like的用法

    jpa使用like查询,需要拼接字符串,如下 oracle用法: //dao层代码 @Query(value = "SELECT * FROM TABLENAME WHERE USER_NA ...

  6. ugui batches

    先渲染非重叠,然后渲染重叠 如果两个图不是同一个图集,并且都不重叠,那么按节点挂载顺序渲染   节点挂接多复杂没关系,关键是节点在Canvas下的顺序,绑在同一节点或者全部绑在根节点Canvas下渲染 ...

  7. bzoj 4464: [Jsoi2013]旅行时的困惑【贪心】

    据说正解是有上下界最小流,但是这种1e5的玩意问什么要跑网络流啊-- 贪心即可,注意一点是可以有多条路径经过一条边-- 以1为根,设d[u][0/1]为u到父亲的边是向下/向上,g记录这个点儿子中不能 ...

  8. hoj2798 Globulous Gumdrops

    Globulous Gumdrops My Tags   (Edit)   Source : 2008 Stanford Programming Contest   Time limit : 1 se ...

  9. 【POJ - 3040】Allowance(贪心)

    Allowance 原文是English,这里就放Chinese了 Descriptions: 作为创纪录的牛奶生产的奖励,农场主约翰决定开始给Bessie奶牛一个小的每周津贴.FJ有一套硬币N种(1 ...

  10. C#递归得到特定文件夹下问件

    List<String> listFile = new List<String>(); public void director(string path) { //绑定到指定的 ...