hoare版本
基本思想
快速排序的hoare版本是Hoare创建这个算法时最原始的方法,也叫左右指针法,其基本思想是在数组中选出一个key值,一般是最左边的或最右边的值,然后通过左右两个指针,假设我们以最左边的值作为key值,那么就是右指针先向左走,寻找比key值小的元素,找到之后就暂停,然后左指针向右走,寻找比key值大的元素,找到之后,交换这时候左右指针指向的值,如果以最右边作为key值,就是左指针先走。
以最左边作key值为例,当左右指针相遇的时候,在把key与现在的左指针进行交换,这时就保证了在key的左边的元素都是比key小的,右边的元素都是比key大的。
下面是一组数的比较过程。
通过这一组的比较,我们就把这个数组分成了两部分,仔细观察我们还能发现这个key值现在的位置其实就是排序结束后它应该在的位置,相当于我们就排序好了key这个值,那么接下来我们就可以通过递归的方法,在对key值左边和右边的元素用相同的方法进行排序,最终就可以把整个数组排好。
以上就是hoare版本快排的基本思想,在实现排序之前,我们还有一点需要研究一下,那就是我们的最后一步是交换left与keyi的值,那么如果我们要在一组结束之后满足左侧内容比keyi值小,右侧比keyi值大,那就必须满足left与right相遇的时候left指针指向的值是小于keyi的,这一点可以保证吗?答案是可以的,下面我们来分析一下
left与right相遇只有两种情况:
(1)right遇left。
因为在比较时是right先走,所以当right先走然后遇到left时,这时的left指向的值是刚刚在上一轮与right找到的比keyi值小的值交换来的,所以它一定是小于keyi的值的,符合要求。
(2)left遇right。
left在right后走,而left寻找的是大于keyi的值,当left开始移动时说明right这时候已经找到了比keyi小的值,当left遇到right时,说明在right的左边的值没有比keyi大的值,那么这时候left指向的值就一定是小于keyi的,也符合要求。
以上的两种情况都是符合的,那么如果我们比较时让left先走,right后走,这时候就出现问题了。当right遇到left时,因为left是找大于keyi的,所以这时的left是比keyi大的,就不符合要求,所以比较时left和right的先后顺序是不可以调换的。
hoare版本的实现
我们把快排的实现分为两部分。
首先是通过一次排序排好keyi值并且返回keyi值的下标,
第二部分是我们通过递归的方法,对keyi的左边部分和右边部分进行排序
上面是第一部分的过程
这是第二部分的过程。
int PartSort1(int* a, int left, int right)
{
int keyi = left;
while (left < right)
{
while (left < right && a[right] >= a[keyi])
right--;
while (left < right && a[left] <= a[keyi])
left++;
Swap(&a[left], &a[right]);
}
Swap(&a[left], &a[keyi]);
return left;
}
void QuickSort(int* a, int left, int right)
{
if (left >= right)
return;
int keyi = PartSort1(a, left, right);
QuickSort(a, left, keyi - 1);
QuickSort(a, keyi + 1, right);
}
挖坑法
基本思想
挖坑法的思路是把keyi作为一个坑,也是使用left和right两个指针,right向向左找比keyi值小的元素,然后用这个元素去填坑,这时right就变成了一个新坑。然后再让left向右找大的,找到后让这个元素去填坑,让left的位置变成新坑,以此往复,直到left与right相遇,那么这时left与right一定会在坑处相遇,这时再把keyi的值填到坑这里就好了。
下面是挖坑法一次排序的过程
每次交换完成后都像是留下一个坑一样。
其思路与hoare版本类似,先对一组数进行排序,然后再用递归的方法对整个数组进行排序。
int PartSort2(int* a, int left, int right)
{
int key = a[left];
while (left < right)
{
while (left < right && a[right] >= key)
{
right--;
}
//放到左边的坑位,右边形成新的坑
a[left] = a[right];
while (left < right && a[left] <= key)
{
left++;
}
a[right] = a[left];
}
//相遇的位置一定是坑
a[left] = key;
return left;
}
void QuickSort(int* a, int left, int right)
{
if (left >= right)
return;
int keyi = PartSort2(a, left, right);
QuickSort(a, left, keyi - 1);
QuickSort(a, keyi + 1, right);
}
学习链接:https://blog.csdn.net/qq_45967533/article/details/123919118