几种常见的排序方法(1)

1.Quicksort
快排的基本思想是分组和组合。
分组:将待排序的数组(假设数据以数组形式存储的)分成两部分
然后这里有个东西叫Pivot,中文名叫中枢纽元,多么衰的名字……我们就叫它x吧。
知道了这两个东西以后,介绍一下快排的思路:

刚才说过,快排把待排数组分成两部分,怎么分呢,根据x,分成 <x,x,>x ,也就是说分成小于x, 大于x 的两组
也许你会问,这样的分组是怎么实现的呢?这个待会说,姑且我们认为这个是可实现的。(-_-|||)
这样的分组后,x就到了正确的位置, 比如说,x 应该排老十五,那他前面14个比它小的找出来放到<x的那部分里了,这样它自然就在第15的位置上了,剩下在它后面的自然就是比它大的了。
实际上,所说的分组不是真的分组,这个待排的数组还是一个整体,只是把小于x的数据挪到大于x的数据之前,然后把x挪到小于x的数据之后,这样在x身后的数据就都大于x了。
有图有真相(假设我们选数组的第一个数据为 X):

这样以后,对于<x和>x的两组,注意,他们两组还没有排序呢,对这两组继续用同样的方法,直到排完序为止。

接下来,我们要关心的是怎么分组。怎么x就跑到<X,>X中间了呢?
我们用一个例子来说明。
看图:

开始的时候,i=0,j=1,因为
(1).除了x所有的数据都是未分组部分,所以j=1。
(2).小于x的部分还没有产生。所以i=0.
接下来,我们让未分组部分的第一个元素和x比较。如果未分组部分的的首元素小于x,我们自然要把这个首元素归到<x的组里,
怎么做呢?两步:
(1).扩大<x组的边界。
(2).将未分组的首元素放到<x组里面去。

所以我们让i=i+1,然后调换a[i],a[j]。也就是把未知组的首元素调换到<x里面,既最后一个<x的位置上,至于被调换走的a[i],想想,1.i=i+1以后,i=j。
这样相当于没调换,仅仅增加了i,也就是<x组的边界,这正是我们想要的。有>x组的时候,在未调换之前实际上a[i]里的元素实际上是>x组的(因为i已经被增加1了),
因为<x组后面紧接着是>x组,将i=i+1,实际将>x组里面的首元素纳入了<x组里面去了,这不是错误的么,是啊,所以我们有了调换a[i],a[j],这
样把这个属于>x的元素放到了未知组的第一个元素的位置上了。这个不是还是不对的么?是的,但是我们还有第三招:将j=j+1,没错,减少未知
组的边界。我想问问大家,<x组的尾边界是i,那么>x的尾边界是什么?是j-1。将j增加了以后,相当于增加了>x组,又重新把a[j]的这个元素纳入>x组了。
看图从左到右,从上到下阅读:


接下来对1 3 2与 8 9 的排序就不细说了。步骤是一致的。
下面写一下伪代码:
quicksort(A,p,q){
    if p<q
        then {
               r=partition(A,p,q);
               quicksort(A,p,r-1);
               quicksort(A,r+1,q);
        }
partition(A,p,q){
    x=A[p];
    i=p;
    For(j=p+1 to q){
        if (A[j]<=x)
            then {
                i=i+1;
                Swap(A[i],A[j]);
            }
    }
    Swap(A[p],A[i]);
    return i;
}

这种算法的时间复杂度是O(nlogn),是一个比较高效的方法,关于时间复杂度的证明第二章介绍。

此文档基于MIT 网络课程。
Posted on 2010-01-13 02:49 LSC 阅读(135) 评论(0)   编辑  收藏 引用

你可能感兴趣的:(几种常见的排序方法(1))