问题描述:
输入一个原始数列,把它进行升序排序,从小到大输出。
例如:给定数列如下:
5 15 99 45 12 1 90 19 33 41
排序后的结果为:
1 5 12 15 19 33 41 45 90 99
快速排序的基本思想是,找出一个分界的数num,把不大于num的数全部放在它左边,把不小于num的数全部放在它右边,然后对左右区间做相同的操作,直到各个区间都只有一个数位置,下面来看一下具体的过程:
下标值序号: 0 1 2 3 4 5 6 7 8 9
原始状态为: 5 15 99 45 12 1 90 19 33 41
第一趟排序: 1 5 99 45 12 15 90 19 33 41 (选a[0]也就是5作为那个分界数)
第二趟排序: 1 5 41 45 12 15 90 19 33 99(对左右两边进行操作,左边只有a[0],右边从a[2]-a[9],选择a[2]=99作为分界数)
第三趟排序: 1 5 33 19 12 15 41 90 45 99(对a[2]-a[8]进行排序,选择a[2]=41为分界数)
第四趟排序: 1 5 15 19 12 33 41 45 90 99(对a[2]-a[5],a[7]-a[8]分别进行)
第五趟排序: 1 5 12 15 19 33 41 45 90 99(对a[2]-a[4]到进行)
从上面我们可以发现:
1. 对于N个数的数列来说,快速排序选择分界数非常重要
2. 本例中是采用选择每次分组的第一个元素作为分界数,另外一种策略可以找一个这个范围内的随机下标
3. 快速排序在基本有序的情况下反而发挥不出其优势
4. 快速排序是采用一种分而治之的思想,把一个整体排序的问题,通过找到分界点,进而划分为左右两个更小一些的子问题进行求解。
5. 算法的平均时间和最好复杂度都是O(nlogn),但是在最坏情况下,就会退化为O(n^2)
参考代码:
#include<stdio.h>
int arr[] = { 5, 15, 99, 45, 12, 1, 90, 19, 33, 41 };
int GetPartition(int low, int high)
{//找到分界的数num,使得左边的数都不大于num,右边的都不小于num
int nTemp = arr[low];
while (low < high)
{
while (low < high && arr[high] >= nTemp) //从右边开始比较
high--;
arr[low] = arr[high];
while (low < high && arr[low] <= nTemp) //从左边开始比较
low++;
arr[high] = arr[low];
}
arr[low] = nTemp;
return low;
}
void QuickSort(int low, int high)
{
int nPartition = 0;
if (low < high)
{
nPartition = GetPartition(low, high);
QuickSort(low, nPartition - 1);
QuickSort(nPartition + 1, high);
}
}
int main()
{
int i, nCount = sizeof(arr) / sizeof(arr[0]);
printf("排序前\n");
for (i = 0; i < nCount; i++)
printf("%d ", arr[i]);
printf("\n");
QuickSort(0, nCount - 1);
printf("\n排序后\n");
for (i = 0; i < nCount; i++)
printf("%d ", arr[i]);
printf("\n");
return 0;
}
运行结果: