public static void Sort(int[] numbers)
{
Sort(numbers, 0, numbers.Length - 1);
}
private static void Sort(int[] numbers, int left, int right)
{
if (left < right)
{
int middle = numbers[(left + right) / 2];
int i = left - 1;
int j = right + 1;
while (true)
{
while (numbers[++i] < middle) ;
while (numbers[--j] > middle) ;
if (i >= j)
break;
Swap(numbers, i, j);
}
Sort(numbers, left, i - 1);
Sort(numbers, j + 1, right);
}
}
private static void Swap(int[] numbers, int i, int j)
{
int number = numbers[i];
numbers[i] = numbers[j];
numbers[j] = number;
}
这个是维基百科上关于快速排序的例子,我写了半天的例子在和这个对比的时候,直接就叹息了。一些代码组合起来的差距确实是有点大,这个还是体现出自己水平的缺失。
首先我们来看看概念上什么是快速排序。快速排序是由东尼.霍尔发展的一种排序算法,她主要使用分治法策略把一个串行分成两个子串行。具体的排序过程如下:
首先,从数列中挑出一个元素,称为“基准”;然后,重新排列数列,所有元素比基准小的摆放在基准前面,大的摆放到后面,相同的可以摆放到任意一边,所有的列摆放完毕后,该基准就处于数列的大小分界点,右边的数最小的都不比左边最大的小;最后,我们在子列中递归地进行处理,直到递归完成。
下面我们详细看看上面代码。
Sort(int[] numbers, int left, int right);
递归函数,传入参数为数组、数组排序的左界限和右界限。
if (left < right)
递归函数的结束条件,我们可以想象,当left==right的时候,实际上,一个子数组就排序完成了,程序就会跳出当前Sort函数。
int middle = numbers[(left + right) / 2];
取数组临界中的值为基准。
while (numbers[++i] < middle) ;
while (numbers[--j] > middle) ;
从左右两边开始循环,左边找到比middle(基准)大的结束循环,右边找到比middle(基准)下的结束循环。这里有个潜台词,i>j是否有可能,实际上是不可能的,我们来假设一下,如果i>j,也就是i和j在循环过程中有相交点,假设当 i==j时的值为n,numbers[n]<middle,同时numbers[n]>middle,显然这两个条件是不能同时成立的,自然最临界到i==j。这段代码是我最喜欢的,在自己写的过程中我也用了 while但却没有这边用的那么简练。
if (i >= j)
break;
如果交换完成,跳出当前循环。
Sort(numbers, left, i - 1);
Sort(numbers, j + 1, right);
继续对子数组进行排序,直到整个排序过程结束为止。
以上就是整个快速排序过程,实际上就代码实现来说,有很多种,至于效率可能还有更好的。下面我们来看看快速排序的复杂度,这里我们只探讨一下时间复杂性。
在通常情况下,基本没有比快速排序更快的排序方式了,但如上所述,快速排序是递归的,比较占用内存,所以对于有限内存的机器来说,她不是一个好的选择。
我们来看看快速排序算法的稳定性,先定义一下排序稳定性:
假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,ri=rj,且ri在rj之前,而在排序后的序列中,ri仍在rj之前,则称这种排序算法是稳定的;否则称为不稳定的。
根据上面的定义,我们在快速排序中,明显在交换值的时候,打乱了原值在整个记录序列中的顺序,所以我们说,快速排序是不稳定的。
下面我们来简单讨论一下快速排序的时间复杂度,对于整个数组而言,假设有n个元素,每次二分之,那整个n被划分的次数为根号n,即为logn次划分,而每次划分后,需要经过n次的比较,所以其时间复杂度为O(nlogn).我们来看看一个极端的情况,第一次划分完以后,出现了左边是n-1个,右边是1个的情况,第二次划分以后,左边n-2,右边1。。。。。。,这样就出现了划分次数最大化了,其时间复杂度也相应变为O(n*n),具体的数据推导比较复杂,我也没弄明白,只能解释到这了。
其实我只是很喜欢上面的这段代码,觉得相当的酷了。。。