快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。
而对于基准值,我们一般取得是第一个元素。每执行一次微排序就确定了目前的基准值的位置,再次将基准值左边的部分和右边的部分分别进行微排序(递归),直至最终完全有序即可
1. hoare版本
微排序分析
此时设定基准数(key)对应的值就是6,i 和 j分别就是从两头开始走,直到相遇就停止,我们最终目的是:左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值。
所以我们就在左边找大于key的值,右边找小于key的值,找到就交换,此时问题就来了
- 谁先走呢?
- 左边是从key开始还是从下一个开始呢?
3. 最后相遇的值与基准值交换位置,那如果相遇的值大于key呢?那交换不就会出错吗?
分析问题:
- 假如说我们不从右边开始走,而是从左边开始走,找较大值,此时下面就会相遇在8的位置,发生交换,所以就出错了。但是我们如果让右边的先走,找较小值,最后就会停在较小值的位置,即使是没找到的话也是和左边的相遇,也会是一个较小值,从而交换就是正确的交换。但是如果左边先走找较大值,最后交换的就会是较大值。基准值定在最左边,此时右边先走不仅是正确的交换,而且还保证的最后相遇的一定是小于基准值的值。如果基准值在最右边就得让左边先走了。
- 假如说左值不是从基准值开始走,而是从基准值下一个位置开始走。此时如果基准值是最小值的话,就会在1的位置相遇,所以就会出错,所以左边从基准值开始走就保证了此情况。
微排序代码
int Part1Sort(int* arr, int left, int right)
{int keyi = left;/基准值下标while (left < right){//右边找小于arr[keyi]的值while (left<right&&arr[right] >= arr[keyi])right--;//左边找大于arr[keyi]的值while (left<right&&arr[left] <= arr[keyi])left++;Swap(&arr[left], &arr[right]);}//left=rightSwap(&arr[left], &arr[keyi]);return left;//返回相遇值的下标
}
外层循环条件就是 left<right,同时也要保证内部找较大较小值时 left<right,防止在找值的过程中就发生了越界,而且如果找到的值与基准值相等的话也继续找,防止死循环。
快排递归部分
//递归部分
void QuickSort(int* arr,int left,int right)
{if (left >= right)return;int keyi = Part1Sort(arr, left, right);QuickSort(arr, left, keyi - 1);QuickSort(arr, keyi + 1,right);
}
这里主要就是分析一下停止条件:即区间left和right之间只剩最后一个数或者没有数的情况
2.挖坑法
其实挖坑法也是通过霍尔的思想改了一下,原理都是一样的,只不过更容易理解一点。就是先将基准值的值存起来,形成坑位,同样是从右边开始找较小值,找到了就将该较小值填在原来的坑里,此处形成新的坑,再从左边开始找较大值,填到坑里,并形成新的坑......最后一定是在坑中相遇,将基准值填入坑中就算完成一次微排序。
代码
int Part2Sort(int* arr, int left, int right)
{int key = arr[left];int hole = left;while (left < right){//找小while (left<right&&arr[right] >= key)right--;arr[hole] = arr[right];//找到小于key的值就填坑hole = right;//形成新的坑//找大while (left < right && arr[left] <= key)left++;arr[hole] = arr[left];//找到对于key的值就填坑hole = left;//形成新的坑}//在坑的位置相遇arr[hole] = key;return hole;
}
3.前后指针法
这种方法就是遍历一遍,将大于基准值的数向后拨。一前一后两个指针相邻为1,如果cur指向的值小于基准值,就pre++再交换,如果cur指向的值大于基准值就,cur++。当cur与pre之间相距大于1的话就证明它们之间的值都是大于基准值的数,而此时cur指向的值一定是小于基准值,发生交换。
代码
int Part3Sort(int* arr, int left, int right)
{int keyi = left;int pre = left;int cur = left + 1;while (cur <= right)//等于时cur指向最后一个数{if (arr[cur] <= arr[keyi]){pre++;Swap(&arr[pre], &arr[cur]);}cur++;}Swap(&arr[keyi], &arr[pre]);return pre;}