幾種常用排序算法

 

 

  排序算法是數據結構學科經典的內容,其中內部排序現有的算法有很多種,究竟各有什麼特點呢?本文力圖設計實現常用內部排序算法並進行比較。分別爲冒泡排序,直接插入排序,簡單選擇排序,快速排序,堆排序,針對關鍵字的比較次數和移動次數進行測試比較。

 

  

  待排序表的元素的關鍵字爲整數.用正序,逆序和不同亂序程度的不同數據做測試比較,對關鍵字的比較次數和移動次數(關鍵字交換計爲3次移動)進行測試比較.要求顯示提示信息,用戶由鍵盤輸入待排序表的表長(100-1000)和不同測試數據的組數(8-18).每次測試完畢,要求列表現是比較結果.

要求對結果進行分析.

 

 

 

 

  1、冒泡排序

 

   算法:核心思想是掃描數據清單,尋找出現亂序的兩個相鄰的項目。當找到這兩個項目後,交換項目的位置然後繼續掃描。重複上面的操作直到所有的項目都按順序排好。

 

bubblesort(struct rec r[],int n)

{

int i,j;

struct rec w;

unsigned long int compare=0,move=0;

for(i=1;i<=n-1;i++)

  for(j=n;j>=i+1;j--)

   {

    if(r[j].key<r[j-1].key)

     {

     w=r[j];

     r[j]=r[j-1];

     r[j-1]=w;

     move=move+3;

     }

    compare++;

   }

printf("\nBubbleSort compare= %ld,move= %ld\n",compare,move);

}

 

 

  2、直接插入排序

 

算法:經過i-1遍處理後,L[1..i-1]己排好序。第i遍處理僅將L[i]插入L[1..i-1]的適當位置,使得L[1..i]又是排好序的序列。要達到這個目的,我們可以用順序比較的方法。首先比較L[i]和L[i-1],如果L[i-1]≤ L[i],則L[1..i]已排好序,第i遍處理就結束了;否則交換L[i]與L[i-1]的位置,繼續比較L[i-1]和L[i-2],直到找到某一個位置j(1≤j≤i-1),使得L[j] ≤L[j+1]時爲止。

 

insertsort(struct rec r[],int n)

{

int i,j;

unsigned long int compare=0,move=0;

for(i=2;i<=n;i++)

   {compare++;

    r[0]=r[i];

    move++;

    j=i-1;

   while(r[0].key {r[j+1]=r[j];

j--;

move++;

++compare;}

   r[j+1]=r[0];

   move++;

   }

  printf("\nInsertSort compare= %ld,move= %ld\n",compare,move);

}

 

 

  3、簡單選擇排序

 

  算法:首先找到數據清單中的最小的數據,然後將這個數據同第一個數據交換位置;接下來找第二小的數據,再將其同第二個數據交換位置,以此類推。

 

selectsort(struct rec r[],int n)

{

unsigned long int compare=0,move=0;

int i,j,k;

struct rec w;

for(i=1;i<=n-1;i++)

{      k=i;

     for(j=i+1;j<=n;j++)

 

     { if(r[j].key>r[k].key) {k=j; compare++; }

     w=r[i];

     r[i]=r[k];

     r[k]=w;

     move=move+3;

 

     }

}

printf("\nSelectSort compare= %ld,move= %ld\n",compare,move);

}

 

 

  4、快速排序

 

  算法:首先檢查數據列表中的數據數,如果小於兩個,則直接退出程序。如果有超過兩個以上的數據,就選擇一個分割點將數據分成兩個部分,小於分割點的數據放在一組,其餘的放在另一組,然後分別對兩組數據排序。通常分割點的數據是隨機選取的。這樣無論你的數據是否已被排列過,你所分割成的兩個字列表的大小是差不多的。而只要兩個子列表的大小差不多。

 

q(struct rec r[],int s,int t)

{

int i=s,j=t;

if(s<t)

{

  r[0]=r[s];    ++a;  c++;

  do{

while(j>i&&r[j].key>=r[0].key)

   {j--;

    ++a; }

if(i<j)

{ r[i]=r[j];

   i++;

   c++; }

while(i<j&&r[i].key<=r[0].key)

   {i++;

    ++a; }

if(i<j)

   { r[j]=r[i];

     j--;

     c++; }

    } while(i<j);

r[i]=r[0];

c++;

q(r,s,j-1);

q(r,j+1,t);

}

}

 

 

  5. 堆排序

 

  基本思想:堆排序是一樹形選擇排序,在排序過程中,將R[1..N]看成是一顆完全二叉樹的順序存儲結構,利用完全二叉樹中雙親結點和孩子結點之間的內在關係來選擇最小的元素。

 

  (2)堆的定義: N個元素的序列K1,K2,K3,...,Kn.稱爲堆,當且僅當該序列滿足特性:

       Ki≤K2i Ki ≤K2i+1(1≤ I≤ [N/2])

 

sift(struct rec r[],int l,int m)

{

int i,j;

struct rec w;

i=l; j=2*i;

w=r[i];

while(j<=m)

{

  if(j<m&&r[j].key<r[j+1].key)  { j++;

  }

  if(w.key<r[j].key)

  {

   r[i]=r[j];

   i=j;

   j=2*i;

   }

  else j=m+1;

  }

  r[i]=w;

}

 

heapsort(struct rec r[],int n)

{

  unsigned long int compare=-1,move=-1;

  struct rec w;

  int i;

  int a;

  for(i=n/2;i>=1;i--) a=sift(r,i,n);

  compare++;

  move++;

 

  for(i=n;i>=2;i--)

  {

    w=r[i];

    r[i]=r[1];

    r[1]=w;

    a=sift(r,1,i-1);

    compare+=a;

    move+=a;

   }

}

 

 

小結:

 

  1.學會使用隨機函數randomize( )爲數組賦初值要在頭文件中添加#include 。

 

  2.在做此程序之前基本上是在理解了各種排序過程以後完成的。

 

  3.對排序算法的總結:

 

  (1)若n較小(如n≤50),可採用直接插入或直接選擇排序。當記錄規模較小時,直接插入排序較好;否則因爲直接選擇移動的記錄數少於直接插人,應選直接選擇排序爲宜。

 

  (2)若文件初始狀態基本有序(指正序),則應選用直接插人、冒泡或隨機的快速排序爲宜;

 

  (3)若n較大,則應採用時間複雜度爲O(nlgn)的排序方法:快速排序、堆排序或歸併排序。

 

  快速排序是目前基於比較的內部排序中被認爲是最好的方法,當待排序的關鍵字是隨機分佈時,快速排序的平均時間最短;堆排序所需的輔助空間少於快速排序,並且不會出現快速排序可能出現的最壞情況。這兩種排序都是不穩定的。

 

(轉)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章