• 数据结构——快速排序的优化


     作者:敲代码の流川枫

    博客主页:流川枫的博客

    专栏:和我一起学java

    语录:Stay hungry stay foolih

    Apifox = Postman + Swagger + Mock + JMeter。集接口文档工具、接口Mock工具、接口自动化测试工具、接口调试工具于一体,提升 10 倍研发效率。

    文章目录

    1.快速排序的特性

    2.寻找基准的方法

    2.1 Hoare法

    2.2挖坑法

    2.3前后指针法

    3.快速排序优化

    3.1划分不均匀

    3.2 对后几层使用插入排序


    1.快速排序的特性

    时间复杂度:O(N*log(N))
    空间复杂度:O(log(N))
    稳定性:不稳定 当数据有序时,时间复杂度O(N^2)空间复杂度O(N)


    2.寻找基准的方法

    2.1 Hoare法

    1. public static void quickSort(int[] array){
    2. sort(array,0, array.length-1);
    3. }
    4. private static void sort(int[] array,int start,int end){
    5. //防止只有左子树或者右子树的情况
    6. if(start >= end){
    7. return;
    8. }
    9. int povit = partion(array,start,end);
    10. sort(array,start,povit-1);
    11. sort(array,povit+1,end);
    12. }
    13. private static int partion(int[] array,int left,int right){
    14. //记录原始位置下标,方便后面和povit位置交换
    15. int i = left;
    16. //寻找参考值
    17. int povit = array[i];
    18. while(left<right){
    19. while(left < right && array[left] <= povit){ //单独的循环,防止循环内一直到left>right,要加条件
    20. right--;
    21. }
    22. while(left < right && array[left] >= povit){
    23. left++;
    24. }
    25. //交换
    26. swap(array,left,right);
    27. }
    28. //交换povit到相遇的位置
    29. swap(array,left,i);
    30. return left;
    31. }


                 * 问题1:为什么先从right 向左找?
                 * 从右边开始找基准位置,是因为从左边开始找,左边先找到一个比array[left]大的数,然后右边
                 * 向左找,左右肯定相遇,这时候交换,会把比基准值大的数交换到基准位置左边,达不到二分的目的了
                 *
                 * 问题2:为什么左右数组值比较时要带等于号?
                 * 如果出现两边开始时值相同的情况,即左值不小于也不大于右值,两个循环都不会进去
                 * 只会完成左右值一直交换,死循环了

    2.2挖坑法

    1. private static int paration1(int[] array,int left,int right){
    2. int povit = array[left];
    3. while(left<right){
    4. while (left < right && array[right] >= povit) {
    5. right--;
    6. }
    7. array[left] = array[right];
    8. while(left < right && array[left] <= povit){
    9. left++;
    10. }
    11. array[right] = array[left];
    12. }
    13. array[left] = povit;
    14. return left;
    15. }

    2.3前后指针法

    1. private static int paration2(int[] array,int left,int right){
    2. int prev = left;
    3. int cur = left+1;
    4. while(cur <= right){
    5. if(array[cur] < array[left] && array[++prev] != array[cur]){
    6. swap(array,prev,cur);
    7. }
    8. cur++;
    9. }
    10. swap(array,prev,left);
    11. return prev;
    12. }

    3.快速排序优化

    3.1划分不均匀

    当遇到单分支树的情况,会出现划分不均匀的问题,就会导致递归次数太多

    三数取中法

    1. private static void sort1(int[] array,int start,int end){
    2. //防止只有左子树或者右子树的情况
    3. if(start >= end){
    4. return;
    5. }
    6. //在找基准之前,解决划分不均匀的问题,将关键值改变为中间大小的值后,能解决单分支的情况
    7. int index = findMidValOfIndex(array,start,end);
    8. swap(array,start,index);
    9. int povit = partion(array,start,end);
    10. sort(array,start,povit-1);
    11. sort(array,povit+1,end);
    12. }
    13. /*
    14. 找到中位数
    15. */
    16. private static int findMidValOfIndex(int[] array,int start,int end){
    17. int midIndex = (start+end)/2;
    18. if(array[start] < array[end]){
    19. if(array[midIndex] < array[start]) {
    20. return start;
    21. } else if (array[end] < array[midIndex]) {
    22. return end;
    23. }
    24. else {
    25. return midIndex;
    26. }
    27. }
    28. else {
    29. if (array[midIndex] > array[start]){
    30. return start;
    31. } else if (array[midIndex] < array[end]) {
    32. return end;
    33. }
    34. else {
    35. return midIndex;
    36. }
    37. }
    38. }

    3.2 对后几层使用插入排序

    当递归的区间很小的时候我们可以用插入排序,二叉树后几层节点数占总体节点数的大部分,
    递归次数最多也发生在后几层,往后也越来越有序,就不递归了。用插入排序

    1. private static void sort2(int[] array,int start,int end){
    2. //防止只有左子树或者右子树的情况
    3. if(start >= end){
    4. return;
    5. }
    6. if(( end-start+1) <= 15){
    7. //插入排序减少后几层 的递归
    8. insertSort1(array,start,end);
    9. }
    10. //在找基准之前,解决划分不均匀的问题,将关键值改变为中间大小的值后,能解决单分支的情况
    11. int index = findMidValOfIndex(array,start,end);
    12. swap(array,start,index);
    13. int povit = partion(array,start,end);
    14. sort(array,start,povit-1);
    15. sort(array,povit+1,end);
    16. }
    17. public static void insertSort1(int[] array,int left,int right){
    18. for (int i = left+1; i <= right ; i++) {
    19. int j = i-1;
    20. int tmp = array[i];
    21. for (; j >= left ; j--) {
    22. if(array[j] > array[i]){
    23. array[j+1] = array[j];
    24. }
    25. else{
    26. break;
    27. }
    28. }
    29. array[j+1] = tmp;
    30. }
    31. }

  • 相关阅读:
    字节一面:说说TCP的三次握手
    JSON 和 XML 的区别
    IDEA日志输出格式控制、文件记录日志
    LeetCode 1189. “气球” 的最大数量---unordered_map和字符串计数
    开发 Chrome 扩展程序的利弊
    应用分类算法,预测泰坦尼克号乘客幸存结果
    基础练习 圆的面积
    电脑硬件——硬盘
    哎,又跟HR在小群吵了一架!
    听力检测为什么要在标准化的隔声屏蔽系统中进行?
  • 原文地址:https://blog.csdn.net/chenchenchencl/article/details/127609553