有关快速排序及其时间复杂性(QuickSort)

来源:互联网 发布:面板数据竖着是时间 编辑:程序博客网 时间:2024/05/22 03:34
      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),具体的数据推导比较复杂,我也没弄明白,只能解释到这了。

其实我只是很喜欢上面的这段代码,觉得相当的酷了。。。

 

原创粉丝点击