快速排序介绍
过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
快速排序算法通过多次比较和交换来实现排序,其排序流程如下:
1、首先设定一个分界值,通过该分界值将数组分成左右两部分。
2、将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于或等于分界值,而右边部分中各元素都大于或等于分界值。
3、然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。
4、重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。
概括来说为 挖坑填数 + 分治法。
———————————————
快速排序框架;
void QuickSort(int* a, int left, int right)
{
if (left >= right)
return;
int keyi = PartSort3(a, left, right);
QuickSort(a, left, keyi - 1);
QuickSort(a, keyi + 1, right);
}
共有三种方法实现;
1.hoare版本;
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[keyi], &a[left]);
keyi = left;
return keyi;
}
单趟排序:通过左边找大,右边找小的将小数的移动到左边,大数移动到右边,最后将key与left和right相遇的位置进行交换;
递归排序左区间,右区间;(类似递归二叉树);
2.挖坑法
int PartSort2(int* a, int left, int right)
{
int key = a[left];
int hole = left;
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;
return hole;
}
左边left做坑,右边找到一个小的进坑,然后此位置做坑,左边找到比key大的进坑,当两边相遇时让一开始保留的key进坑;
3.前后指针法;
int PartSort3(int* a, int left, int right)
{
int keyi = left;
int prev = left;
int cur = left + 1;
//cur为遍历指针;
//[0,prev] [prev,cur-1] [cur.right];
for (cur = left + 1; cur <= right; cur++)
{
if (a[cur] < a[keyi])
{
prev++;
swap(&a[prev], &a[cur]);
}
}
swap(&a[prev], &a[keyi]);
keyi = prev;
return keyi;
}
这是一种很重要的思想;
数组划分,数组分块
cur指针作用从左往右扫描数组,遍历数组;
prev指针指向已扫描的区间内,小于关键字的最后一个位置;