快速排序

终于有时间坐下来写一写这半年学习的算法,否则又要白学了。

1.Partition函数:

    快排中最重要的是划分算法Partition(A,l,r):该算法输入是数组A,以及我们在这次划分中考虑的元素的范围——从下标为l的元素考虑到下标为r的元素。假设总是选取下标为r的元素作为轴p,那么一次划分结束后,p元素左边的元素都比它小,右边的元素都比它大。例如:有数组2 3 1 3 4 2 ,选取末尾红色的2为轴,经过一次划分后数组变为2 1 2 3 4 3,可以看到划分后轴元素2的左边都是小于等于2的元素,右边都是大于2的元素。

    记住算法中重要的变量就可以快速的写出算法,划分函数中主要有三个:i,j,p;p就是上述说的轴元素,假设每次都选取数组最后一个元素作为轴。在划分过程中j是游标,从l遍历到r;i指向比轴p大的元素中最左边的那个,如果发现j指向的元素比轴p小了,就和i指向的元素互换,i向后移动。见下图,红色的2是选中的轴元素,i指向的3是比2大的第一个元素,当前j遍历的元素是1,比轴元素2小,所以将这个1与i指向的元素3交换,得到右边交换后的图。所以这里,我们可以这样理解i,它维护了一个大于p和小于等于p的元素的分界线,并且它指向的元素总是大于p并且“准备”与比p小(或者等于p)的元素交换的。

2.quick_sort函数

    有了partition函数,快排就很容易写出来了,就是三个步骤:调用partition,递归快排轴左边的元素序列,递归调用轴右边的元素序列。代码如下:

   

 1 #include <iostream>
 2 using namespace std;
 3 int A[10] = {2,5,4,2,1,4,7,8,4,3};
 4 
 5 void Swap(int A[10],int i,int j)
 6 {
 7     int temp = A[i];
 8     A[i] = A[j];
 9     A[j] = temp;
10 }
11 int Partition(int A[10],int l,int r)
12 {
13     int p = A[r]; //选取最后一个元素最为轴元素
14     int i = l;
15     for(int j = l;j <= r-1;j++)
16     {
17         if(A[j] <= p)    
18         {
19             Swap(A,i,j);   //如果j指向的元素比轴p小,就和i指向的元素互换位置
20             i++;
21         }
22     }
23     Swap(A,i,r);    //每一次partition的过程中,轴元素p都被放到最终的位置上
24     return i;
25 }
26 
27 void quick_sort(int A[10],int l,int r)
28 {
29     if(l < r){
30         int pivot = Partition(A,l,r);
31         quick_sort(A,l,pivot-1);
32         quick_sort(A,pivot+1,r);
33     }
34     return;
35 }
36 int main()
37 {
38     quick_sort(A,0,9);
39     for(int i = 0;i <= 9;i++)
40         cout << A[i]<<" ";
41     cout <<endl;
42 }

    说一下partition这个函数,除了在快排中,还有很多其他情况都可以应用。比如《算法导论》Problems8-4的“水壶问题”:有一堆红色水壶和蓝色水壶,所有的红色水壶中水量不等,所有的蓝色水壶中水量不等。对于任意一个红色水壶,对应一个蓝色水壶水量和它相等,比较一个蓝色水壶和红色水壶中水量多少记为一次操作,同色水壶间不能进行水量比较。问多少进行多少次操作,能够把所有红色水壶和蓝色水壶配对。

    这个问题就可以用partition的思想:任意选取一个红色水壶,把它和所有的蓝色水壶比较一遍水量,比它少的放一堆,多的放一堆,相等的单独拿出来,再用这个和它水量相等的蓝色水壶和所有的红色水壶比较一遍,同样分成比它小的和比它大的,这样所有的水壶就被分成三堆,其中一堆为一对已经配对的水壶,对剩下两堆水壶进行递归操作,直到所有水壶都配对。

    最后记一下快排的性质:最优时间复杂度O(nlogn),最坏时间复杂度O(n^2),不稳定排序。之所以速度快是因为它的过程符合现代计算机的cache机制,即每次需要操作的元素在计算机中物理位置很近,通常可以一次性取进cache。

原文地址:https://www.cnblogs.com/sunshineatnoon/p/3529896.html