快速排序
快速排序由于排序效率在同为O(N*logN)的几种排序方法中效率较高,因此经常被采用,再加上快速排序思想----分治法也确实实用,因此很多软件公司的笔试面试,包括像腾讯,微软等知名IT公司都喜欢考这个,还有大大小的程序方面的考试如软考,考研中也常常出现快速排序的身影。
快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-Conquer Method)。
1.算法步骤
该方法的基本思想是:
- 先从数列中取出一个数作为基准数(头部尾部都可以,实际上任何一个都可以)。
- 分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
- 再对左右区间重复第二步,直到各区间只有一个数。
2.动图演示
3.代码实现
void swap(int* x, int* y) {
int t = *x;
*x = *y;
*y = t;
}
3.1.首元素作为基准数
void quick_sort_recursive_front(int arr[], int start, int end) {
if (start >= end)//这个地方大于等于都可以,只不过当start==end的时候,多了一层递归。当然这一层递归并没有任何实质性作用
return;
int mid = arr[start];
int left = start+1, right = end;
while (left < right) {
while (arr[right] > mid && left < right)
right--;
while (arr[left] < mid && left < right)
left++;
//left不可能大于right,最多是等于
swap(&arr[left], &arr[right]);//最后一次肯定有自己交换一次
}//while语句运行完后,left==right
if (arr[left] >= arr[start])
left--;//这是一种特殊情况,mid的值恰好是最大值,left--将指向基准值
else
swap(&arr[left], &arr[start]);
if (left)//这里的left可要可不要,只不过多了一次函数递归而已
quick_sort_recursive_front(arr, start, left - 1);//左递归
quick_sort_recursive_front(arr, left + 1, end);//右递归
}
3.2.尾元素作为基准数
void quick_sort_recursive_tail(int arr[], int start, int end) {
if (start >= end)//这个地方大于等于都可以,只不过当start==end的时候,多了一层递归。当然这一层递归并没有任何实质性作用
return;
int mid = arr[end];
int left = start, right = end - 1;
while (left < right) {
while (arr[left] < mid && left < right)
left++;
while (arr[right] > mid && left < right)
right--;
//left不可能大于right,最多是等于
swap(&arr[left], &arr[right]);//最后一次肯定有自己交换一次
}//while语句运行完后,left==right
if (arr[left] >= arr[end])
swap(&arr[left], &arr[end]);
else
left++;//这是一种特殊情况,mid的值恰好是最大值,left++将指向基准值
if (left)//这里的left可要可不要,只不过多了一次函数递归而已
quick_sort_recursive_tail(arr, start, left - 1);//左递归
quick_sort_recursive_tail(arr, left + 1, end);//右递归
}
void quickSort(int arr[], int len)
{
quick_sort_recursive_front(arr, 0, len - 1);
//quick_sort_recursive_tail(arr, 0, len - 1);
}
3.3.测试程序
void main()
{
int arr[] = { 22, 34, 3, 32, 82, 55, 89, 50, 37, 5, 64, 9, 70, 35,32};//定义一个待排序的数组
int len = sizeof(arr) / sizeof(*arr);//获取数组长度
printf("\nsort before\n");
for (int i = 0; i < len; i++)//排序前数组元素的顺序
{
printf("%d\t", arr[i]);
}
quickSort(arr,len);//快速排序
printf("\quickSort after\n");//排序后数组元素的顺序
for (int i = 0; i < len; i++)
{
printf("%d\t", arr[i]);
}
system("pause");
}
4.归纳总结
- 从while循环出来之后left == right
- 存在一种极为特殊的情况:选择的基准值就是最大值
- 递归的终止条件start>=end可以改为start>end,只不过多了一层递归而已,对整个数组元素的顺序没有任何变化
- 如果不是处于特殊情况,从while循环出来之后,left和right同时指向比基准值更大的值然后再与基准值进行交换,此时left与right同时指向基准值,但如果是处于特殊情况,那么此时left和right指向基准值旁边的值,至于++还是–则取决于是首元素作为基准数还是尾元素作为基准数。