最近学习了快速排序,鼠鼠俺来做笔记了!
本篇博客用排升序为例介绍快速排序!
目录
1.快速排序
快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。
如果对上面的介绍蒙圈的话,没关系,我们继续看下面的内容,会仔细介绍的!
1.1.快速排序的”单趟“
快速排序的”单趟“简单来说就是在需排序数组中任取一个元素作为基准值,经过”单趟“过后,大于或者等于基准值的元素都排在基准值的后面,小于或者等于基准值的元素都排在基准值的前面,也就是说基准值所在的位置就是它应该出现的位置,这个基准值就排好了!
对于”单趟“的实现方法有但不限于下面三种:
1.1.1.hoare版本
这个动图就是hoare版本的”单趟“实现方法!这里取第一个元素6为基准值;R从最”右边“开始找比基准值小的元素,L从最”左边“开始找比基准值大的元素, 然后交换下标为R和L的元素;R继续找比基准值小的元素,L继续找比基准值大的元素,再交换下标为R和L的元素…………直到R和L相遇,将基准值和相遇位置的元素即可!
其实这个本质就是将比基准值大的元素”甩“到”后面“,将比基准值小的元素”甩“到”前面“。
也许会有疑问,怎么保证相遇位置的元素一定不大于基准值呢?
因为只要是R先动,L后动的话必然能保证相遇的元素一定不大于基准值!
相遇无非两种情况:
1.R遇L:R在去找小于基准值的元素的过程中,下标为L的元素必然是不大于基准值的元素。当R去找小于基准值的元素没有找到却遇到L时, 那么相遇位置的值就是不大于基准值的元素。
2.L遇R:由于R先动,那么L在找大于基准值的元素的过程中,下标为R的元素必然是不大于基准值的元素。当L去找大于基准值的元素没有找到却遇到R时,那么相遇位置的值就是不大于基准值的元素。
hoare版本的“单趟”代码如下,需排序数组下标为begin—end:
//hoare版本
int keyi = begin;
int left = begin, right = end;
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[keyi], &a[right]);
keyi = right;
由于hoare版本写起来很容易出错误,所以我们一般写下面两种版本!
1.1.2.挖坑法版本
也是取第一个元素6为基准值。初始坑位设置为基准值下标。让R从最“右边”开始找比基准值小的元素,找到后将下标为R的元素填入坑位,那么新的坑位就变成了R;让L从最“左边”开始找比基准值大的元素,找到后将下标为L的元素填入坑位,那么新的坑位就变成了L;R再找比基准值小的元素……直到R和L相遇,将基准值填入坑位即可。
本质就是R找小填入“左边”坑位,L找大填入“右边”坑位,最后一个坑位必定是R和L相遇位置,填入基准值就好。
挖坑法版本“单趟”代码如下,需排序数组下标为begin—end:
//挖坑法版本
int key=a[begin];
int left = begin, right = end;
int hole = begin;
while (left < right)
{
while (left < right && a[right] >= key)
{
right--;;
}
a[hole] = a[right];
hole = right;
while (left < right && a[left] <= key)
{
left++;
}
a[hole] = a[left];
hole = left;
}
a[hole] = key;
int keyi = hole;
1.1.3.前后指针版本
取第一个元素6为基准值。prev初始指向基准值,cur初始指向基准值的下一个元素。cur遍历数组:如果cur遇到大于基准值的元素,++cur;否则++prev、cur指向的元素和prev指向的元素交换、++cur。
前后指针版本“单趟”代码如下, 需排序数组下标为begin—end:
//前后指针版本
int cur = begin + 1, prev = begin;
int