一、思想
1、基于分治策略
核心:选择基准点,将比基准点小的数放在基准点左边,比基准点大的数放在基准点右边。
2、分析思想
如何选择基准点??
首先我们选择第一个数据为基准点放在变量 key 中,那么0号位置就暂时成为无效位。但是并不是每次都选择第一个数据,举例:
从上述我们可以发现
(1)如果从左往右比较,小数不移动,就继续按顺序++,如果从右往左比较,大数不移动,继续按倒叙- -。
(2)如果移动,遵循的是大数在后,小数在前的规律,移动到前面或者后面无效的位置。
(3)此时key = 15,已经排序完成,所以就把整个数据分成了两个部分,现在我们先对前半部分进行同样方法的排序操作。
(4)其中每次的key保存的不一定是0号元素,应该说基准点key保存每次可排列分组的第一个数据。
(5)我们发现分组数据小于或等于1时,也就是一个或没有数据时,我们不进行排列,认为他有序或者无效。
3、小结论
以基准点的位置将数据分为两部分,然后再将小数放在左边,大数放在右边进行快速排序处理,不断的又找基准点,又排序,又分组,这样的思想可以通过递归来处理。
4、借助代码理解
(1)给出基准点 key ,key并不一定从0号位置开始,可以认为是从每个可排序的小组中的第一个元素。
(2)start 标记小组的起始位置;end标记小组的末尾位置
所以key = arr[ start ];//小组的起始为基准点
(3)当倒序处理后面的数据时
arr[ end ] >= key
时,不移动数据,end--
;
arr[ end ] < key
时,arr[ start ] = arr[ end ];//小数放在前面
(4)当顺序处理前面的数据时
arr[ start ] <= key
时,不移动数据,start++
;
arr[ start ] > key
时,arr[ end ] = arr[ start ];//大数放在后面
(5)当 start = end时,表示找到了基准点的位置,最后将基准点数据放在位置上即可。
二、完整代码实现
#include<stdio.h>
int parition(int arr[], int start, int end)//找到基准点后的基准点下标
{
int boundkey = arr[start];
while (start < end)//元素没有遍历完,如果start<=end表示所有数据比较完成
{
while (start < end && arr[end] >= boundkey)//元素没有遍历完并且大数就在后面,不用移动
end--;
arr[start] = arr[end];//后面有数据比基准值小
while (start < end && arr[start] <= boundkey)//元素没有遍历完并且小数就在前面,不用移动
start++;
arr[end] = arr[start];
}
arr[end] = boundkey;
return start;//此时start = end
}
void Quick(int arr[], int start, int end)//控制区间
{
int key;
if (start < end)//判断这个区间是否需要排序
{
key = parition(arr,start,end);//在start和end找到基准点
Quick(arr,start, key - 1);//递归调用把基准点左边划分成一个区间
Quick(arr,key + 1, end);//递归调用把基准点右边划分成一个区间
}
}
void QuickSort(int arr[], int len)//拿到数据和数组大小,在主函数中被调用
{
Quick(arr, 0, len - 1);
}
int main()
{
int arr[] = { 12, 3, 21, 32, 1, 34, 12, 35, 34 };
int len = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < len; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
QuickSort(arr, len);
for (int i = 0; i < len; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
三、快排的优化???
1、当数据基本有序时
如果数据基本有序时,快排会一步一步找基准点进行递归遍历,这时递归层次达到了最大,效率最低,对于这种情况,我们怎么优化??
2、当数据是随机的
如果数据是随机的,又该如何处理?
3、如果是小数据量
当数据量过小时,调用递归会使效率降低,杀鸡焉用牛刀?此时该如何处理。
4、数据中多个重复数据
当重复数据过多时,用我们学到的代码会一次又一次对相同的数据进行递归排序,这样会导致程序开销大,效率低,该如何处理??
5、函数调用递归,开销大
递归调用会使程序开销大,能不能用一种不是用递归的方式进行快速排序???
欲知后事如何,请听下回分解…
快排的五个优化