首页  编辑  

快 速 排 序

Tags: /超级猛料/Alogrith.算法和数据结构/排序/   Date Created:

快 速 排 序

基本思路:通过一次分割,将无序序列分成两部分,其中一部分的元素值均不大于后一部分的元素值。然后用同样的方法对每一部分进行分割,一直到每一个子序列的长度小于或等于1为止。

具体过程:设序列P进行分割。首先,从第一个、中间一个、最后一个元素中选出中项,设为P[k],并将P[k]赋给t,再将序列中的第一个元素移到P[k]的位置上。然后,再设两个指针i、j分别指向起始和最后位置上:(1)将i逐渐增大,与此同时比较P[i]与t的大小,直到发现P[i]>t,将P[i]移到P[j]的位置上;(2)将j逐渐减小,与此同时比较P[j]与t的大小,直到发现P[j]<t,将P[j]移到P[i]的位置上;直到i=j为止,这时将t移到P[i]的位置上。最后就得到了排序结果。

   C函数如下:

void prqck(p,n)

int n;double p[];

{

int m,i0,*i;

double *s;

void rsplit();

i=&i0;

if(n>1)

  {

   rsplit(p,n,i);

   m=i0;prqck(p,m);

   s=p+(i0+1);m=n-(i0+1);prqck(s,m);

   }

return;

}

static void rsplit(p,n,m)

int n,*m;double[];

{

int i,j,k,l;

double t;

i=0;j=n-1;k=(i+j)/2;

if((p[i]>=p[j])&&(p[j]>=p[k])) l=j;

   else if((p[i]>=p[k])&&(p[k]>=p[j])) l=k;

else l=i;

t=p[l];p[l]=p[i];

while(i!=j)

     {

      while((i<j)&&(p[j]>=t)) j=j-1;

            if(i<j)

               {

                p[i]=p[j];i=i+1;

                while((i<j)&&(p[j]<=t)) i=i-1;

                      if(i<j)

                         {p[j]=p[i];j=j-1;}

                 }

        }

p[i]=t;*m=i;

return;

}

************************

般来说,冒泡法是程序员最先接触的排序方法,它的优点是原理简单,编程实现容易,但它的缺点就是--程序的大忌--速度太慢。下面我介绍一个理解上简单但编程实现上不是太容易的排序方法,我不知道它是不是现有排序方法中最快的,但它是我见过的最快的。排序同样的数组,它所需的时间只有冒泡法的4%左右。我暂时称它为"快速排序法"。

"快速排序法"使用的是递归原理,下面我结合一个例子来说明"快速排序法"的原理。首先给出一个数组{53,12,98,63,18,72,80,46,32,21},先找到第一个数--53,把它作为中间值,也就是说,要把53放在一个位置,使得它左边的值比它小,右边的值比它大。{21,12,32,46,18,53,80,72,63,98},这样一个数组的排序就变成了两个小数组的排序--53左边的数组和53右边的数组,而这两个数组继续用同样的方式继续下去,一直到顺序完全正确。

我这样讲你们是不是很胡涂,不要紧,我下面给出实现的两个函数:

void quicksort(int n[], int left,int right)//n就是需要排序的数组,left和right是你需要排序的左界和友界,如果要排序上面那个数组,那么left和right分别是0和9

{

int dp;

if (left<right) {

dp=partition(n,left,right);//这就是下面要讲到的函数,按照上面所说的,就是把所有小于53的数放到它的左边,大的放在右边,然后返回53在整理过的数组中的位置。

quicksort(n,left,dp-1);

quicksort(n,dp+1,right);//这两个就是递归调用,分别整理53左边的数组和右边的数组

}

}

我们上面提到先定位第一个数,然后整理这个数组,把比这个数小的放到它的左边,大的放右边,然后返回这中间值的位置,下面这函数就是做这个的。

int partition(int n[],int left,int right)

{

int lo,hi,pivot,t;

pivot=n[left];

lo=left-1;

hi=right+1;

while(lo+1!=hi) {

if(n[lo+1]<=pivot)

lo++;

else if(n[hi-1]>pivot)

hi--;

else {

t=n[lo+1];

n[++lo]=n[hi-1];

n[--hi]=t;

}

}

n[left]=n[lo];

n[lo]=pivot;

return lo;

}

这段程序并不难,应该很好看懂,我把过程大致讲一下,首先你的脑子里先浮现一个数组和三个指针,第一个指针称为p指针,在整个过程结束之前它牢牢的指向第一个数,第二个指针和第三个指针分别为lo指针和hi指针,分别指向最左边的值和最右边的值。lo指针和hi指针从两边同时向中间逼近,在逼近的过程中不停的与p指针的值比较,如果lo指针的值比p指针的值小,lo++,还小还++,再小再++,直到碰到一个大于p指针的值,这时视线转移到hi指针,如果hi指针的值比p指针的值大,hi--,还大还--,再大再--,直到碰到一个小于p指针的值。这时就把lo指针的值和hi指针的值做一个调换。持续这过程直到两个指针碰面,这时把p指针的值和碰面的值做一个调换,然后返回p指针新的位置。

我知道我怎么说你们还是不太明白,其实只要看程序就行了,有很多程序的语言是用人类的语言无法表达的。有什么问题,email我:allexit@hotmail.com。

*********************************

数据都保存在Items中

  function RSplit ( Left , Right : integer ): integer ;

  var

   L , H , P , T : integer ;

  begin

   P := Items [ Left ];

   L := Left - 1 ;

   H := Right + 1 ;

    while L + 1 <> H do

    begin

      if Items [ L + 1 ] <= P then

       Inc ( L )

      else if Items [ H - 1 ] > P then

       Dec ( H )

      else begin

       T := Items [ L + 1 ];

       Inc ( L );

       Items [ L ] := Items [ H - 1 ];

       Dec ( H );

       Items [ H ] := T ;

      end ;

    end ;

   Items [ Left ] := Items [ L ];

   Items [ L ] := P ;

   Result := L ;

  end ;

  procedure QuickSort ( iStart , iEnd : integer );

  var

   Position : integer ;

   i , j , t : integer ;

  begin

    if iStart < iEnd then

    begin

     Position := RSplit ( iStart , iEnd );

     QuickSort ( iStart , Position - 1 );

     QuickSort ( Position + 1 , iEnd );

    end ;

  end ;

Invoke: QuickSort(0,Items.Count -1);

---------------------------------------

{

The following procedure sorts an Array with the

fast Shell-Sort algorithm.

Invented by Donald Shell in 1959,

the shell sort is the most efficient of the O(n2)

class of sorting algorithms

}

{

Die folgende Prozedur Sortiert ein Array mit

dem schnellem Shell-Sort Algorithmus.

}

Procedure Sort_Shell(var a: array of Word);

var

 bis, i, j, k: LongInt;

 h: Word;

begin

 bis := High(a);

 k := bis shr 1;// div 2

 while k > 0 do

 begin

   for i := 0 to bis - k do

   begin

     j := i;

     while (j >= 0) and (a[j] > a[j + k]) do

     begin

       h := a[j];

       a[j] := a[j + k];

       a[j + k] := h;

       if j > k then

         Dec(j, k)

       else

         j := 0;

     end; // {end while]

   end; // { end for}

   k := k shr 1; // div 2

 end;  // {end while}

end;