zoukankan      html  css  js  c++  java
  • Java算法-快速排序

      快速排序也是用归并方法实现的一个“分而治之”的排序算法,它的魅力之处在于它能在每次partition(排序算法的核心所在)都能为一个数组元素确定其排序最终正确位置(一次就定位准,下次循环就不考虑这个元素了)。

      快速排序的partition操作按以下逻辑进行,假定本次排序的数组为arr:

    1) 选择一个元素(为了简单起见,就选择本次partition的第一个元素,即arr[0])作为基准元素,接下来的步骤会为其确定排序完成后最终的位置;

    2) 1)  接下来需要遍历[1…n-1]对应的数组元素以帮助找到arr[0]值(以v替代)对应的位置,定义i为当前访问数组的索引,lt为值小于v的最大索引,gt为值大于v的最小索引,那么在遍历过程中,如果发现i指向的值与v相等,则将i值加1,继续下一次比较;如果i指向的值比v小,则将i和lt对应的元素进行交换,然后分别将两个索引加1;如果i指向的值比v大,则将i与gt对应的元素进行交换,然后i自增,gt自减。循环遍历完成(i > gt时结束)之后可以保证[0…lt-1]对应的值都是比v小的,[lt..gt]之间的值都是与v相等的,[gt+1…n-1]对应的值都是比v大的。

    3) 分别对[0…lt-1]和[gt+1…n-1]两个子数组进行排序,如此递归,直至子子子数组的长度为0。

      下面举个partition的具体实例:

    初始(i = 1, lt = 0, gt = 8):
    
           [41, 59, 43, 26, 63, 30, 29, 26, 42](需要确定位置的为0th[41])
    
    第一趟(i = 1, lt = 0, gt = 8):
    
           [41, 42, 43, 26, 63, 30, 29, 26, 59](1st[59] > 41,1st[59]<->8th[42],gt--)
    
    第二趟(i = 1, lt = 0, gt = 7):
    
           [41, 26, 43, 26, 63, 30, 29, 42, 59](1st[42] > 41,1st[42]<->7th[26],gt--)
    
    第三趟(i = 1, lt = 0, gt = 6):
    
           [26, 41, 43, 26, 63, 30, 29, 42, 59](1st[26] < 41, 1st[26]<->0st[41],i++, lt++)
    
    第四趟(i = 2, lt = 1, gt = 6):
    
           [26, 41, 29, 26, 63, 30, 43, 42, 59](2nd[43] > 41,2nd[43]<->6th[29],gt--)
    
    第五趟(i = 2, lt = 1, gt = 5):
    
           [26, 29, 41, 26, 63, 30, 43, 42, 59](2nd[29] < 41, 2nd[29]<->1st[41],i++,lt++)
    
    第六趟(i = 3, lt = 2, gt = 5):    
    
           [26, 29, 26, 41, 63, 30, 43, 42, 59](3rd[26] < 41,3rd[26]<->2nd[41],i++,lt++)
    
    第七趟(i = 4, lt = 3, gt = 5):
    
           [26, 29, 26, 41, 30, 63, 43, 42, 59] (4th[63] > 41,4th[63]<->5th[30],gt--)
    
    第八趟(i = 4, lt = 3, gt = 4):    
    
           [26, 29, 26, 30, 41, 63, 43, 42, 59](4th[30] < 41,4th[30]<->3rd[41],i++,lt++)

    可以看出,在一次partition之后,以41为分割线,41左侧皆为比它小的元素,41右侧皆为比它大或相等的元素(当然这个实例比较特殊,没有出现和41相等的元素)。快速排序顾名思义就是排序速度非常快,后面我会放在我机器上跑各个排序方法的时间对比图。值得一提的是JDK中在Arrays工具内中内置的sort方法就是接合插入排序和三路快速排序实现的,有兴趣的同学可以看看JDK的源码。

    快速排序使用分治法策略来把一个序列分为两个子序列。

    把整个序列看做一个数组,把第零个位置看做中轴,和最后一个比,如果比它小交换,比它大不做任何处理;交换了以后再和小的那端比,比它小不交换,比他大交换。这样循环往复,一趟排序完成,左边就是比中轴小的,右边就是比中轴大的,然后再用分治法,分别对这两个独立的数组进行排序。

    实现代码:

    /**  
     * 快速排序<br/>  
     * <ul>  
     * <li>从数列中挑出一个元素,称为“基准”</li>  
     * <li>重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分割之后,  
     * 该基准是它的最后位置。这个称为分割(partition)操作。</li>  
     * <li>递归地把小于基准值元素的子数列和大于基准值元素的子数列排序。</li>  
     * </ul>  
     *   
     * @param numbers  
     * @param start  
     * @param end  
     */  
    public static void quickSort(int[] numbers, int start, int end) {   
        if (start < end) {   
            int base = numbers[start]; // 选定的基准值(第一个数值作为基准值)   
            int temp; // 记录临时中间值   
            int i = start, j = end;   
            do {   
                while ((numbers[i] < base) && (i < end))   
                    i++;   
                while ((numbers[j] > base) && (j > start))   
                    j--;   
                if (i <= j) {   
                    temp = numbers[i];   
                    numbers[i] = numbers[j];   
                    numbers[j] = temp;   
                    i++;   
                    j--;   
                }   
            } while (i <= j);   
            if (start < j)   
                quickSort(numbers, start, j);   
            if (end > i)   
                quickSort(numbers, i, end);   
        }   
    }
  • 相关阅读:
    贴图叠加算法
    Tetrahedron based light probe interpolation(基于四面体的Light Probe插值)
    PS脚本博客
    【Unity优化】资源管理系列03:AssetBundle 基本原理
    【Unity优化】资源管理系列02:Resources 最佳实践
    【Unity优化】资源管理系列01:Assets, Objects and serialization
    【Unity优化】DrawCall与Batch
    【Unity3D技术文档翻译】第1.9篇 使用 Unity AssetBundle Browser tool (AssetBundle系列完结)
    【Unity3D技术文档翻译】第1.8篇 AssetBundles 问题及解决方法
    【Unity3D技术文档翻译】第1.7篇 AssetBundles 补丁更新
  • 原文地址:https://www.cnblogs.com/hwaggLee/p/4437630.html
Copyright © 2011-2022 走看看