zoukankan      html  css  js  c++  java
  • 排序算法(六)快速排序

      快速排序算法最早由图灵奖获得者 Tony Hoare 设计出来的 ,被列为 20 世纪十大算法之一。在C++ STL 、Java SDK等开发工具包的源码中都能找到它的某种实现版本。

      希尔排序相当于直接插入排序的升级,它们同属于插入排序类,堆排序相当于简单选择排序的升级,它们同属于选择排序类。而快速排序其实就是我们前面认为最的冒泡排序的升级,它们都属于交换排序类。即官也是通过不断比较和移动交换来实现排序的 , 只不过宫的实现,增大了记景的 比较和移动的距离 , 将关键字较大的记录从前面直接移动到后面,关键字较小的记录从后面直接移动到前面,从而减少了总的比较次数和移动交换次数。 

    1,算法描述

    快速排序 ( Quick Sort) 的基本思想是:通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序的目的。 

    2,实现步骤

    1. 从序列中挑出一个元素,作为"基准"(pivot).
    2. 把所有比基准值小的元素放在基准前面,所有比基准值大的元素放在基准的后面(相同的数可以到任一边),这个称为分区(partition)操作。
    3. 对每个分区递归地进行步骤1~2,递归的结束条件是序列的大小是0或1,这时整体已经被排好序了。

      实现

     1 private static void quickSort(int[] arr,int start,int end){  
     2         if(start<end){
     3             int keyIndex = partition(arr, start, end);//原始数组选的主元现在所在的位置索引
     4             quickSort(arr, start, keyIndex-1);//对主元左侧的序列进行快速排序    
     5             quickSort(arr, keyIndex+1, end);//对主元右侧的序列进行快速排序    
     6         }  
     7     }  
     8     
     9     /** 
    10      * 本函数实现一趟快速排序,以数组的第一个元素为主元
    11      * !!!本函数运行结束后使得主元左侧的元素小于主元,主元右侧的元素大于主元。 
    12      * @param arr 待排序的数组 
    13      * @return 返回经一趟排序后主元的下标 j
    14      */ 
    15     public static int partition(int[] arr, int start, int end){
    16         int key = arr[start];//把数组第一个元素设为主元(如果需要优化可以从arr中随机一个数作为主元)
    17         int i = start;//两个指针,i指向数组头,j指向数组尾
    18         int j = end;    
    19         while(i < j){//若i与j未相遇,则执行以下循环
    20             while(arr[j] >= key && j > start){//j从右向左扫描,直到当前元素小于主元素停下
    21                 j--;
    22             }
    23             while(arr[i] <= key && i < end){//i从左向右扫描,直到当前元素大于主元时停止
    24                 i++;
    25             }
    26             if(i < j)//因为上述扫描有可能发生i>j的情况
    27                 swap(arr, i, j);
    28         }
    29         swap(arr, start, j);//将主元与j交换
    30         return j;        
    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     }

    3,算法优化

    优化选取枢轴 (主元),选取的该值最好每次都在待排序列的中间值附近,如果选的主元是最大值,每次调用就只是进行了第29行的一次交换。

    1)随机选取枢轴(主元),感觉是在碰运气。
    2)数取中法,靠谱一点,就是从序列的前,中,后取三个元素,中间的作为主元。

    4,算法分析

    快速排序比较适合大量数据的排序,如果序列元素个数小于7(有资料认为 7 比较合适,认为 50 更理,实际应用可适调整) ,不如直接用插入排序。

    时间复杂度:

    最佳情况:T(n) = O(nlogn)

    最差情况:T(n) = O(n^2)

    平均情况:T(n) = O(nlogn)

    时间复杂度计算过程:http://blog.csdn.net/wangqyoho/article/details/52584640

    空间复杂度:

    O(log(n))

    稳定性:不稳定

    5,应用

    Java SDK提供的Arrays.sort函数。对于基础类型,底层使用快速排序。对于非基础类型,底层使用归并排序。请问是为什么?

    答:这是考虑到排序算法的稳定性。对于基础类型,相同值是无差别的,排序前后相同值的相对位置并不重要,所以选择更为高效的快速排序,尽管它是不稳定的排序算法;而对于非基础类型,排序前后相等实例的相对位置不宜改变,所以选择稳定的归并排序。 

    6,比较排序总结

    从算法的简单性来看,我们将 7 种算法分为两类:
    • 简单算法:冒油、简单选择、直接插入。
    • 改进算法:希尔、堆、归并、快速。

    从平均情况来看,显然最后 3 种改进算法要胜过希尔排序,并远远胜过前 3 种简单算法。

    从最好情况看,反而冒泡和直接插入排序要更胜一筹,也就是说,如果你的待排序序列总是基本有序,反而不应该考虑 4 种复杂的改进算法。

    从最坏情况看,堆排序与归并排序叉强过快速排序以及其他简单排序。

    参考:

    《大话数据结构》

    http://www.cnblogs.com/eniac12/p/5329396.html

  • 相关阅读:
    关于Linux启动时挂载rootfs的几种方式【转】
    文件子系统-(rootfs)根文件系统挂载流程03【转】
    linux根文件系统挂载过程【转】
    linux的initrd机制和initramfs机制之根文件挂载流程:代码分析【转】
    ramdisk配置、解压、创建rootfs、启动简单分析【转】
    linux文件系统初始化过程(4)---加载initrd(中)【转】
    Linux内核学习:EXT4 文件系统在 Linux 内核系统中的读写过程【转】
    Flyway数据库版本管理工具的使用
    RabbitMQ消息发送与接收
    RabbitMQ简介以及安装
  • 原文地址:https://www.cnblogs.com/xdyixia/p/9147788.html
Copyright © 2011-2022 走看看