快速排序

来源:互联网 发布:python中文编码问题 编辑:程序博客网 时间:2024/05/01 17:20

快排

废话不说,先贴上代码,代码在《c程序设计语言》p74:

void swap(int v[],int i,int j){int temp;temp = v[i];v[i] = v[j];v[j] = temp;}void qsort(int v[],int left,int right){int i,last;void swap(int v[],int i,int j);if(left >= right)return;swap(v,left,(left + right)/2);last = left;for(i = left+1;i<=right;i++)            if(v[i] < v[left])swap(v,++last,i);swap(v,left,last);qsort(v,left,last-1);qsort(v,last+1,right);}


假定初始给定:v[7]

01234567683259这里left = 0,right = 6

①swap( v, left, ( left+right ) / 2 )
本例swap(v, 0 , 3),即将  首元素 ↔中间元素

01234563687259


②last = left

last = left = 0


③for(i = left + 1;i <= right;i++)

      if ( v[i] < v[left])

         swap(v, ++last, i)

本例:for( i = 1; i <= 6; i++),将数组v[7]从v[1]到v[6]扫描,

              当满足条件:v[i] < v[left] = v [0] = 3,也就是,比首元素3还要小的话,

                   那么执行:swap(v,++last,i),执行的是交换元素的操作。


结合上面的实例,i = 1, v[1] = 6 > v[left] = 3,不执行交换操作;

                            i = 2, v[2] = 8 > v[left] = 3,不执行交换操作;

                            i = 3, v[3] = 7 > v[left] = 3,不执行交换操作;

                            i = 4, v[4] = 2 < v[left] = 3,满足if的条件,第一次执行swap操作,将v[4]与v[++last]交换,last之前为0,++执行完结果为last = 1,那么就是交换v[4]和v[1],结果:

01234563287659

                            i = 5, v[5] = 5 > v[left] = 3,不执行交换操作;

                            i = 6, v[6] = 9 > v[left] = 3,不执行交换操作;

那么这个for循环结束,只进行了1次swap交换,效果是将小于3的元


④swap(v ,left ,last)

swap(v , 0,1)交换v[0]和v[1]:

01234562387659

⑤qsort(v , left,last - 1)

递归调用快排qsort,这时,qsort(v ,0,0),无需进行。


⑥qsort(v ,last+1,right)

qsort(v ,2 ,6),对v[2] ~ v[6]重复上述步骤,继续。


根据刚刚总结的,执行:

1. 首元素↔ 中间元素,这里left = 2 , right = 6

01234562367859
2. last = left = 2

3. for循环,操作的目的是:

           范围:v[3] ~ v[6]

           条件:小于v[left] = 6

           操作:v[i] ↔ v[++last]


     在v[3] ~ v[6]里,只有v[5]比v[left]小,所以只要swap一次即可,同时last = 3v[5]  v[3],

01234562365879
4.swap(v, 2, 3)

01234562356879
5.qsort(v, 2, 2)

     因为for循环里,也只执行了一次swap操作,故这一步不需要操作,已经有序。


6.qsort(v, 4, 6)

01234562356879
6.1 首元素 ↔ 中间元素,left = 4, right = 6

01234562356789
6.2  last = left = 4


6.3 for循环:

            范围:v[4] ~ v[6]

            条件:小于v[left] = 7

            操作:v[i]  ↔ v[++last]

      发现,没有比v[left] = 7还小的数,所以不执行操作。不过此时,我们发现,顺序好像已经排好了。当然接下来的操作也没有意义了。


总结
通观整个算法思想,利用了递归,减少了代码量,不过理解起来也稍加费力。打完上面的例子,才发现不好,因为每次for循环之多只执行了一次,没有完全展现出“分治”的思想来。不妨再来一个,简单说明一下。

01234568476329
初始:left = 0, right = 6


step1. 将中间元素与首元素交换,即把a[3] = 6选为key,放到首位。同时将last 赋值为left的值,last = 0.因为left不能随意改变,last可以记录交换的位置。

01234566478329
step2. for循环:

            范围:v[1] ~ v[6]

            条件:小于v[0] = 6

            操作:交换v[i]↔ v[++last]

            i = 1, v[1] = 4 < v[0] = 6,++last = 1 ,v[1] ↔ v[1],不需要交换。

            i = 2, v[2] = 7 > v[0] = 6,无需操作

            i = 3, v[3] = 8 > v[0] = 6,无需操作

            i = 4, v[4] = 3 < v[0] = 6,++last = 2 ,v[4] ↔ v[2]。

01234566438729
            i = 5, v[5] = 2 < v[0] = 6,++last = 3 ,v[5] ↔ v[3]。

01234566432789
            i = 6, v[6] = 9 > v[0] = 6,无需操作

可以看到for循环的效果是:将比6小的数依次从1开始排,而last记录了最后一个比6小的数。


step3. 将v[left] ↔ v[last]

01234562436789可以看到,6作为key,在6的前面是比6小的数,6的后面是比6大的数。


step4. qsort(v, left, last - 1)

           qsort(v, last + 1, right)


递归再次快排,将之前划分的两个子集再次排序,即v[0] ~ v[2] ,v[4] ~ v[6],只要两个子集顺序排好,自然连在一起是有序的。

当left >= right时候,即数组包含的元素的个数少于两个的时候,那么就意味着不能再划分了,已经有序了,不执行操作,return即可。