第一:快速排序+递归调用
1)选取标点,一般取第一个数,空出一个坑A。
2)从右边标志向左扫描,找到第一个比自己小的数,然后将数填充到位置A中,留出一个坑B,然后将左边标志指向左边坑后面的第一个数;
3)从左边标志向右扫描,找到第一个比自己大的数,然后将数填到位置B中,留出一个坑A,然后将右边标志指向右边坑前面的第一个数上。
4)重复2) 3)知道左边标志遇到右边标志
5)将标点数填到左边标志的坑中,返回左边标志的位置。
View Code
对于快排提高效率的地方主要地方时如何选取标点数据。目前常用的有随机快排(不是选取第一个数,而是随机选取一个数)、平衡快排(从第一个、中间一个、最后一个分部取出三个树,然后选取他们当中接近中值的那个数)。
为了分析快速排序的时间复杂度,请先看下面的主定理:
主定理: T [n] = aT[n/b] + f (n)
其中 a >= 1 and b > 1 是常量 并且 f (n) 是一个渐近正函数, 为了使用这个主定理,您需要考虑下列三种情况:
想必大家都知道快速排序的过程,如果对这个过程有什么不了解,请参考下文:
http://www.cnblogs.com/pugang/archive/2012/06/27/2565093.html
快速排序的每一次划分把一个 问题分解成两个子问题,其中的关系可以用下式表示:
T[n] = 2T[n/2] + O(n) 其中O(n)为PARTITION()的时间复杂度,对比主定理,
T [n] = aT[n/b] + f (n)
我们的快速排序中:a = 2, b = 2, f(n) = O(n)
那么为什么还有最坏情况呢?
考虑如下极端情况,
T[n] = T[n-1] + T[1] + O(n),
问题来了,这一次的划分白玩了,划分之后一边是一个,一边是n-1个,这种极端情况的时间复杂度就是O(n2).
#include <stdio.h> #include <stdlib.h> typedef int DataType; int quick_snort(DataType data[],int lf,int rt) { DataType flag; int ilf,jrt; ilf = lf; jrt = rt; flag = data[ilf]; while(ilf < jrt){ while(ilf< jrt && data[jrt] >flag) jrt--; if(ilf < jrt){ data[ilf] = data[jrt]; ilf++; } while(ilf < jrt && data[ilf] <= flag) ilf++; if(ilf < jrt){ data[jrt] = data[ilf]; jrt--; } } data[ilf] = flag; return ilf; } void quick(DataType data,int lf,int rt) { if(lf < rt){ int ilf = quick_snort(data,lf,rt); quick(data,lf,ilf-1); quick(data,ilf+1,rt); } } int main() { int i=0; int data[10]={9,8,7,6,5,4,3,2,1,0}; quick(data,0,9); for(i=0;i<10;i++) printf("%d ",data[i]); printf("\nHello world!\n"); return 0; }