LintCode-31: Partition Array 及QuickSort学习

Partition Array类似于quickSort里面的Paritition的过程,但是有点细微区别。代码如下:

    int partitionArray(vector<int> &nums, int k) {
        int start=0, end=nums.size()-1;
        while (start<=end) { //note: <= 
            while ((start<=end) && (nums[start]<k)) start++; //note: <=  <
            while ((start<=end) && (nums[end]>=k)) end--; //note" <= >=
            if (start<=end) { //note: <=
                swap(nums[start], nums[end]);
               // start++; **//这两行代码可要可不要**
               // end--;
            }
        }
        return start;
    }

QuickSort的代码如下:

    void quickSort(vector<int>& A, int start, int end) {

        if (start>=end) return;

        int left=start, right=end;
        //1. pivot cannot be start or end, and don't choose index, we need to choose the value, as the partition is not stable, the elements' sequence is not garanteed!
        int pivot=A[start+(end-start)/2]; //if pivot=A[start] or A[end] it is easy to cause the non-even partition, or the random() will have overhad.

        //2. it is <=, not <
        while(left<=right) {   
            while(left<=right && A[left]<pivot) {
                left++;
            }

            while(left<=right && A[right]>pivot) {
                right--;
            }

            if (left<=right) {
                int temp=A[left];
                A[left]=A[right];
                A[right]=temp;
                left++;
                right--;
            }
        } 

        quickSort(A, start, right); //right moved to left
        quickSort(A, left, end); ///left moved to right
    }

    void sortIntegers2(vector<int> &A) {
        if (A.size()==0) return;
        quickSort(A, 0, A.size()-1);
    }

要注意的地方有:
1)所有地方都用left<=right。为什么呢?因为如果写成left < right,就会导致死循环(迭代版)或stack overflow(递归版)。举个例子:
nums[]={3,2,1,4,5},一开始left=0(指向3), right=4(指向5), pivot=nums[(0+4)/2]=1 (index=1),然后left指向3(不动),right指向1(–两次)。然后left和swap的元素交换,变成{1,2,3,4,5}。left和right都是1,指向2(即pivot)。此时(left < right)这个条件不满足了,会继续递归,
quickSort(A, start,right) => quickSort(A,0,1)
quickSort(A, left, end) => quickSort(A,1, 4)。这里pivot还是nums[(1+4)/2]=1,数组为{X,2,1,4,5},最后left=1指向2,right=2指向1,交换元素以后变成{X,1,2,4,5},left=2指向2,right=1指向1,然后又递归
quickSort(A,1,1)
quickSort(A,1,4) 所以导致stack overflow。

而用(left <= right)的话,上面当left=right=1时,while(left<=right)仍然满足,此时内部while()的A[left] < pivot和A[right]>pivot不满足,所以进入if(left <= right),此时原地交换,left=2,right=0,进行递归
quickSort(A,0,0), nums={1,X,X,X,X} 不会再递归了。
quickSort(A,2,4), nums={X,X,3,4,5}, start=2, end=4, pivot=nums[3]=4。
left=2指向3, right=4指向5,此时left++,right–,都=3指向4。此时left <= right仍然满足,原地交换后left++变成4,right–变成2。再递归
quickSort(A,2,2)不递归了
quickSort(A,4,4)也不递归了。

2)pivot必须是元素值而不是index,因为partition可能会交换元素,所以index就不管用了。这也是为什么quickSort是不稳定排序的原因。
3)<=pivot的在左边,>=pivot的在右边。也就是说pivot即在左边又在右边。为什么不是<的在左边,>=的在右边,或者<=的在左边,>的在右边呢?这是考虑到数组里面可能很多重复元素,比如说nums={1,1,1,1,1,1,1},如果< p的在左边,>=p的在右边,会导致左边一个都没有,右边还是n个的极端情况。
4) quickSort的话,if(left<=right)的left++和right–是必须的。
而这个LintCode的Partition Array则可要可不要。我想这个是为了防止递归overflow的缘故。
5) quickSort里面是(A[left] < pivot)和(A[right] > pivot)。而Partition Array则是(nums[start] < k)和(nums[start] >= k)。我想quickSort是要把元素分为< pivot,= pivot和> pivot三部分,而Partition Array只是分为2部分。
6) 这些是我的理解,还没有确认。
quickSort里面每次partition完之后,[start, end]里面可分为3部分:左边是[start, j], 中间是pivot,右边是[i, end]。注意这里pivot是取的数组元素,所以一定可以取到。不过什么时候会只分成2部分呢?

而上面的Partition Array里面的k不一定是数组里面的元素,每次partition完之后,数组分为2部分,[0, start] 都是小于k的数,[start+1, end]都是大于等于k的数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值