前两章讲到的桶排序和冒泡排序各有他们的优点,但他们的缺陷却很难避免。桶排序以空间换取时间,冒泡排序则以时间换取空间,他的时间复杂度是O(N^2),假如我们的计算机每秒种可以运行10亿次,那么对1亿个数进行排序,桶排序只需要0.1秒,而冒泡排序则需要1000万秒,达115天之久。那有没有既不浪费空间又可以快一点的排序算法呢?那就是“快速排序”啦!
假如现在我们对“6 1 2 7 9 3 4 5 10 8”进行排序,那么先在这些数中找一个基准数,也就是参照数。然后对数进行移动,使得在基准数左边的数都比它小,基准数右边的数都比它大。那要怎样移动才能做到呢?想想上一节的冒泡排序,我们用了交换的方式,这里我们同样也用交换的方式来实现。不过冒泡排序的交换必须是相邻的两个数交换,而快速排序之所以比冒泡快是因为它可以交换任意位置的两个值。当然在最差的情况下,快速排序也是交换相邻位置的数达到排序目的,这时的时间复杂度和冒泡排序一样。下面来说说快速排序的具体过程。
假设我们以6为基准数,分别从初始序列6 1 2 7 9 3 4 5 10 8两端开始探测。从右往左找一个小于6的数,再从左往右找一个大于6的数,然后交换它们。这里可以用两个变量i和j,分别指向序列最左边和最右边。先开始移动j,当j移动到5的时候停止,开始移动i到7,此时交换7和5的位置。然后继续向左移动j,发现4比6小,j不动,移动i,发现9比6大,交换9和4的位置,继续移动j,发现3比6小,j不动,移动i,这是他们相遇在3的位置了,此时交换3和6,第一轮探测结束。此时在6左边的数都比6小,6右边的数都比6大。现在以同样的方法处理6左边的数列和六右边的数列。
笔者水墨功夫确实差。下面贴代码,有兴趣的盆友看看代码就什么都懂了
#include <iostream>
using namespace std;
int a[100],n;
void quicksort(int left, int right)
{
int i,j,t,temp;
if(left>right)
return;
i = left;
j = right;
temp = a[left];
while(i!=j)
{
while(a[j]>=temp&&i<j)
{
j--;
}
while(a[i]<=temp && i<j)
{
i++;
}
if(i<j)
{
t=a[j],a[j]=a[i],a[i]=t;
}
a[left]=a[i];
a[i] = temp;
}
quicksort(left,i-1);
quicksort(i+1,right);
}
int main()
{
int i,j;
cin >> n;
for(i=1;i<=n;i++)
{
cin >> a[i];
}
quicksort(1,n);
for(i=1;i<=n;i++)
{
cout << a[i] << " ";
}
return 0;
}