zoukankan      html  css  js  c++  java
  • 经典算法回顾之快速排序【交换排序】

    算法思想:

      快速排序采用的思想是分治思想。

      快速排序是找出一个元素(理论上可以随便找一个)作为基准(pivot),然后对数组进行分区操作,使基准左边元素的值都不大于基准值,基准右边的元素值都不小于基准值,如此作为基准的元素调整到排序后的正确位置。递归快速排序,将其他n-1个元素也调整到排序后的正确位置。最后每个元素都是在排序后的正确位置,排序完成。所以快速排序算法的核心算法是分区操作,即如何调整基准的位置以及调整返回基准的最终位置以便分治递归。

    算法【算法导论】:

     1 QuickSort(A,start,end)
     2 
     3 if(start<end)
     4     then q<-Partition(A,start,end)
     5 QuickSort(A,start,q-1)
     6 QuickSort(A,q+1,end)
     7 
     8 
     9 //数组划分!!!
    10 Partion(A,start,end)
    11 
    12 index<-random(start,end)
    13 exchange A[end]<->A[index]
    14 small<-start-1
    15 for index<-start to end-1
    16       do if A[index] < data[end]
    17          then small<-small+1
    18               if small!= index
    19                 exchange A[index] <-> A[small]
    20 exchange A[small+1]<->exchange A[end]
    21 return small+1          

      快速排序复杂度:最坏O(N2);平均O(NlogN)

      快速排序的时间主要耗费在划分操作上,对长度为k的区间进行划分,共需k-1次关键字的比较。

      最坏情况是每次划分选取的基准都是当前无序区中关键字最小(或最大)的记录,划分的结果是基准左边的子区间为空(或右边的子区间为空),而划分所得的另一个非空的子区间中记录数目,仅仅比划分前的无序区中记录个数减少一个。时间复杂度为O(n*n)

      在最好情况下,每次划分所取的基准都是当前无序区的"中值"记录,划分的结果是基准的左、右两个无序子区间的长度大致相等。总的关键字比较次数:O(nlgn)

      尽管快速排序的最坏时间为O(n2),但就平均性能而言,它是基于关键字比较的内部排序算法中速度最快者,快速排序亦因此而得名。它的平均时间复杂度为O(nlgn)。

    完整代码如下:

     1  1 #include <algorithm>
     2  2 #include <stdexcept>
     3  3 #include <iostream>
     4  4 using namespace std;
     5  5 
     6  6 // Random Partition
     7  7 int RandomInRange(int min, int max)
     8  8 {
     9  9     int random = rand() % (max - min + 1) + min;
    10 10     return random;
    11 11 }
    12 12 
    13 13 
    14 14 int Partition(int data[], int length, int start, int end)
    15 15 {
    16 16     if(data == NULL || length <= 0 || start < 0 || end >= length)
    17 17 //        throw new std::exception("Invalid Parameters");
    18 18 //Linux下不接受有参数的exception
    19 19         throw new logic_error("Invalid Parameters");
    20 20     int index = RandomInRange(start, end);
    21 21     swap(data[index], data[end]);
    22 22 
    23 23     int small = start - 1;
    24 24     for(index = start; index < end; ++ index)
    25 25     {
    26 26         if(data[index] < data[end])
    27 27         {
    28 28             ++ small;
    29 29             if(small != index)
    30 30                 swap(data[index], data[small]);
    31 31         }
    32 32     }
    33 33     ++ small;
    34 34     swap(data[small], data[end]);
    35 35     return small;
    36 36 }
    37 37 
    38 38 void QuickSort(int unsorted[],int length,int start,int end)
    39 39 {
    40 40     if(start < end)
    41 41     {
    42 42           int q = Partition(unsorted,length,start,end);
    43 43           QuickSort(unsorted,length,start,q-1);
    44 44           QuickSort(unsorted,length,q+1,end);
    45 45     }
    46 46 }
    47 47 
    48 48 
    49 49 int main()
    50 50 {
    51 51     int unsorted[] = {3,6,1,4,5,11,23};
    52 52     int length = sizeof(unsorted)/sizeof(int);
    53 53 
    54 54     for(int i=0;i<length;++i)
    55 55        cout<<unsorted[i]<<" ";
    56 56     cout<<endl;
    57 57 
    58 58     QuickSort(unsorted,length,0,length-1);
    59 59     for(int i=0;i<length;++i)
    60 60         cout<<unsorted[i]<<" ";
    61 61     cout<<endl;
    62 62 
    63 63     return 0;
    64 64 }
    View Code

    Partition()函数的另一种实现方式:

     1 int Partion(int data[], int length, int start, int end)
     2 {//之前一直纠结的另一种Partition()实现方法,因为其用赋值替代了交换,所以更好。
     3     if(data == NULL || length <= 0 || start < 0 || end >= length)
     4         throw new logic_error("Invalid Parameters");
     5         
     6     int index = RandomInRange(start, end);
     7     swap(data[index],data[end]);
     8     int pleft = start;
     9     int pright = end;
    10     int temp = data[end];//保存基数的副本
    11     
    12     while(pleft < pright)
    13     {
    14         //!!注意顺序,因为基准为end,所以先从左向右遍历!!
    15         //从左向右遍历,直到遇到大于temp的值
    16         while(pleft < pright && data[pleft] <= temp)
    17             pleft++;
    18         if(pleft < pright)
    19             data[pright--] = data[pleft];
    20         //从右向左遍历,直到遇到小于temp的值
    21         while(pleft < pright && data[pright] >= temp)
    22             pright--;
    23         if(pleft < pright)
    24             data[pleft++] = data[pright];    
    25     }
    26     
    27     data[pleft] = temp;
    28     return pleft;    
    29 }
  • 相关阅读:
    POJ 1915 简单 广搜题
    poj 2479 最大子数段
    poj 1321 深搜题
    hdu 1024 最大子段和
    .net 学习总结
    [转]SharpDevelop源码分析 (二、主程序+隐藏的初始化)
    工作六年经验分享:软件工程师如何修炼(转)
    Ajax命名空间一个获取指定的页面元素的快捷方式——$get()
    [转]SharpDevelop代码分析 (一、序+基本概念)
    [转]SharpDevelop源码分析 (三、插件系统)
  • 原文地址:https://www.cnblogs.com/dreamrun/p/4365791.html
Copyright © 2011-2022 走看看