目录
挖坑版
基本思路
代码实现
注意点
前后指针版
基本思路
代码实现
注意点
由于hoare版本的快速排序有很多坑和需要注意的地方,就会导致代码写起来不容易,这里我们给出两种不同的单趟排序思路:挖坑版&前后指针版。
挖坑版
基本思路
先将第一个数记作key,然后把它当作一个坑位。右边先走找小,找到后填补到坑位上,然后该位置变成新的坑位。接着左边走找大,找到后再将该数填到坑位上,该位置变成新坑位。如此循环往复,直到二人相遇,再把key填补到相遇点。
如下为图解
代码实现
- 注意:holei是下标!!
// 挖坑法
int PartSort2(int* a, int begin, int end)
{int midi = GetMidi(a, begin, end);Swap(&a[midi], &a[begin]);int key = a[begin];int holei = begin;while (begin < end){// 右边找小,填到左边的坑while (begin < end && a[end] >= key){--end;}a[holei] = a[end];holei = end;// 左边找大,填到右边的坑while (begin < end && a[begin] <= key){++begin;}a[holei] = a[begin];holei = begin;}a[holei] = key;return holei;
}
注意点
- holei是下标
- key是最左边的值,则right先走
- key是最右边的值,则left先走
- 要记得将坑位转移
- 时间复杂度:O(N)
该方法本质上还是hoare的思想,在性能上并没有比hoare好,但是更好理解!
前后指针版
基本思路
首元素为key,设置两个指针cur和prev,prev指向第一个元素,cur指向它的下一个元素。
- cur找大比key值大的值,++cur
- cur找到比key值小的值,++prev,交换prev和cur位置的值,++cur
关于交换:
- prev可能会和cur指向同一个值,这个时候他们两个还没有分开。
- 当二者拉开距离,prev就会和远处的cur交换值了。此时的prev就是比key要大的值,因为cur在之前已经过滤掉了这些数,从而达到小值换到前面,大值换到后面的效果。
如下图解
我们可以看出,这就类似于推箱子,遇到比key小的值了后,一直将7和9往后退,将小的那个值往前推。
代码实现
//前后指针
int PartSort3(int* a, int begin, int end)
{int midi = GetMidi(a, begin, end);Swap(&a[midi], &a[begin]);int keyi = begin;int prev = begin;int cur = prev + 1;while (cur <= end){if (a[cur] < a[keyi] && ++prev != cur)Swap(&a[prev], &a[cur]);++cur;}Swap(&a[prev], &a[keyi]);keyi = prev;return keyi;
}
注意点
- 如果++prev==cur的话,那就是自己和自己交换,那么在这里是没有必要的,我们可以直接让cur++即可,所以我们将它归并到else里。
- keyi是下标
- 注意结束条件,cur<=end要加等号,因为当cur==end的时候,还要判断。只有当它越界的时候才跳出循环。
- 时间复杂度:O(N)
这三种方法单趟排序出来的结果都不一样!!注意区分。