1. 程式人生 > >24.C語言最全排序方法小結(不斷更新)

24.C語言最全排序方法小結(不斷更新)

http 希爾 找到 sin -s arr span 計算機 gpo

希爾排序:

該方法的基本思想是:先將整個待排元素序列切割成若幹個子序列(由相隔某個“增量”的元素組成的)分別進行直接插入排序,然後依次縮減增量再進行排序,待整個序列中的元素基本有序(增量足夠小)時,再對全體元素進行一次直接插入排序。

由於直接插入排序在元素基本有序的情況下(接近最好情況),效率是非常高的,因此希爾排序在時間效率上比前兩種方法有較大提高。

以n=10的一個數組49, 38, 65, 97, 26, 13, 27, 49, 55, 4為例

第一次 gap = 10 / 2 = 5

49 38 65 97 26 13 27 49 55 4

1A 1B

2A 2B

3A 3B

4A 4B

5A 5B

1A,1B,2A,2B等為分組標記,數字同樣的表示在同一組,大寫字母表示是該組的第幾個元素, 每次對同一組的數據進行直接插入排序。

即分成了五組(49, 13) (38, 27) (65, 49) (97, 55) (26, 4)這樣每組排序後就變成了(13, 49) (27, 38) (49, 65) (55, 97) (4, 26),下同。

第二次 gap = 5 / 2 = 2

排序後

13 27 49 55 4 49 38 65 97 26

1A 1B 1C 1D 1E

2A 2B 2C 2D 2E

第三次 gap = 2 / 2 = 1

4 26 13 27 38 49 49 55 97 65

1A 1B 1C 1D 1E 1F 1G 1H 1I 1J

第四次 gap = 1 / 2 = 0 排序完畢得到數組:

4 13 26 27 38 49 49 55 65 97

以下給出嚴格依照定義來寫的希爾排序:

技術分享圖片
 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 void show(int *p, int length)
 5 {
 6     for (int i = 0; i < length; i++)
 7     {
 8         printf("%4d", p[i]);
 9     }
10     printf("\n");
11 }
12 
13 void shellsort(int *p, int length)
14 {
15     int d = length / 2;//增量
16     while (d >= 1)
17     {
18         //從後往前推
19         for (int i = d;d<length && i<length; i++)
20         {
21             int x = p[i];//備份當前數據
22             int j = i - d;//前面一個元素
23 
24             //在數組範圍內,找到插入的位置,如果大則把大的賦給後面,j一直是前一個位置
25             while (j >= 0 && p[j] > x)
26             {
27                 p[j + d] = p[j];
28                 j = j - d;
29             }
30             //所以這裏要加d
31             p[j + d] = x;
32         }
33         d /= 2;//增量變化
34     }
35 }
36 
37 void main()
38 {
39     int a[10] = { 49 ,  38  , 65   ,97   ,26  , 13,   27  , 49  , 55 ,  4 };
40     show(a, 10);
41     shellsort(a, 10);
42     show(a, 10);
43     system("pause");
44 }
View Code


桶排序(基數排序)

桶排序(也稱箱排序),據坊間演繹,其實現方式有很多。

在此我們僅僅闡述一下本文的實現思想,以便於更好的理解下面的內容,同時加深對桶排序的認識。

首先,說明一點,我們是使用數組模擬桶(最好應該是使用鏈表模擬)。

所謂數組模擬桶實現排序的過程到底是怎麽進行的呢?呵呵!其實還真有點抽象。

實現步驟如下:

(1)定義映射函數

<1>求得欲排數據序列中的最大數據。

<2>通過遍歷欲排數據對每個數據乘以10再與最大數據取余,求得每個數據對應桶的索引(或稱關鍵字)。

(2)求得每個桶中盛放的數據個數(為了保證隨後準確分配數據)

(3)求得每個桶盛放數據個數的右邊界索引(所謂的桶邏輯控制)

(4)從右向左(確保穩定性)掃描欲排數據序列,依次分配到對應桶中

(5)對各桶中所盛數據進行收集

(6)利用插入排序再對各個桶中所盛數據進行排序

(7)直至排序結束,即為已排序數據序列

其實,整個過程再講通俗一點,可以如下描述:

建立一個數組作為我們的所謂的桶(邏輯桶)

然後,申請開辟與欲排數據所占空間相同的內存,作為真正的盛放數據的桶(物理桶)

數組的索引默認為桶號

對數組的每一次賦值都有著不同的意義(請參考代碼分析)

最後再用插入排序對各桶中所收集數據分別進行排序。即完成桶排序。

總而言之:先分類,後收集,再排序。

【2】示例代碼及其分析過程

(1)代碼如下:

  1 #include<iostream>
  2 #include<malloc.h>
  3 using namespace std;
  4 
  5 
  6 void  PrintArr(int ar[],int n)
  7 {
  8     for(int i = 0; i < n; ++i)
  9         cout<<ar[i]<<" ";
 10     cout<<endl;
 11 }
 12 
 13 int MapToIndex(int x,int max)  
 14 {  
 15     return (10 * x) / max;  
 16 } 
 17 
 18 void insertion_sort(int arr[],int begin,int end)
 19 {
 20     for(int i = begin+1; i <= end; ++i)
 21     {
 22         int v = arr[i];
 23         int j = i;
 24         while(j-1 >= begin && v<arr[j-1])
 25         {
 26             arr[j--] = arr[j-1];  
 27         }
 28         arr[j] = v;
 29     }
 30 } 
 31 
 32 void bucket_sort(int ar[], int begin, int end)  
 33 {  
 34 
 35     const int radix = 11 ;  //註意:為什麽是11?
 36     int count[radix], i, j;    
 37     int size = end-begin+1;
 38 
 39     //計數值置空
 40     for(i = 0; i < radix; ++i)  
 41     {
 42         count[i] = 0;    //置空
 43     }
 44     
 45     //end-begin+1 = 9 - 0 + 1 = 10
 46     int *Temp = (int *) malloc((size) * sizeof(int));     //分配臨時空間
 47 
 48     //取得當前待排序數據中的最大數據
 49     int max = 0;  
 50     for(i = begin; i < size; ++i)  
 51     {  
 52         if(ar[i] > max)  
 53             max = ar[i];  
 54     }  
 55 
 56     //統計各桶需要裝的元素的個數  
 57     for(i = begin; i < size; ++i)   
 58     {
 59         count[MapToIndex(ar[i], max)]++;   
 60     }
 61           
 62     //輸出計數結果:
 63     PrintArr(count, radix);
 64 
 65     //求出桶的邊界索引,count[i]為第i個桶的右邊界索引+1   
 66     for(i = 1; i < radix; ++i)   
 67     {
 68         count[i] = count[i] + count[i-1];  
 69     }
 70 
 71     //輸出桶邊界索引        
 72     PrintArr(count, radix);
 73 
 74     //從右向左掃描,保證排序穩定性   
 75     for(i = end; i >= begin; --i)             
 76     {    
 77         j = MapToIndex(ar[i], max);        
 78         Temp[count[j]-1] = ar[i];  //放入對應的空間中,count[j]-1是第j個桶的右邊界索引   
 79         --count[j];       //準備放置下一個元素的位置索引   
 80     }     
 81 
 82     for(int i = 0; i < size; ++i)
 83     {
 84         cout<<Temp[i]<<"  ";
 85     }
 86     cout<<endl;
 87 
 88     PrintArr(count, radix);
 89 
 90     //從各個桶中收集數據   
 91     for(i = begin, j = 0; i < size; i++, j++)  
 92     {
 93         ar[i] = Temp[j];        
 94     }
 95     
 96     PrintArr(ar, end+1);
 97 
 98      //釋放空間  
 99     free(Temp);                          
100     
101     for(i = 0; i < size; i++)  
102     {   
103         int index1 = begin + count[i];             //得到第i個桶的左邊界   
104         int index2 = begin + count[i+1] - 1;       //得到第i個桶的右邊界   
105         if(index1 < index2)  
106             insertion_sort(ar, index1, index2);          
107     }  
108 }  
109 
110 void  main()
111 {
112     int  ar[] = {12, 14, 54, 5, 6, 3, 9, 8, 47, 89};
113     int len = sizeof(ar)/sizeof(int);
114     bucket_sort(ar, 0, len-1);
115     PrintArr(ar, len);
116 }
117 /*
118 4 3 0 0 0 1 1 0 0 0 1
119 4 7 7 7 7 8 9 9 9 9 10
120 5  6  3  8  12  14  9  47  54  89
121 0 4 7 7 7 7 8 9 9 9 9
122 5 6 3 8 12 14 9 47 54 89
123 3 5 6 8 9 12 14 47 54 89
124 */

(2)分析過程如下:

學過數據結構的估計都可以想象得到:桶排序中所謂的桶應該是用一個單鏈表實現

因為,我們一直覺得,計算機世界就是對現實世界的模擬。那麽,既然是山寨,當然越逼真越好

但是,假如我們沒有學習過單鏈表,腦子裏面根本沒有單鏈表的概念。而且,我們要實現桶排序。

好吧!我唯一可以借助的就是數組。

不過數組模擬桶實現桶排序的確不是很好理解,有幾分抽象

上面這就是一個用數組模擬桶實現的桶排序示例代碼,現在做一下具體分析,希望可以更深刻理解桶排序。

分析過程如下:

(1)待排序數據序列為:

技術分享圖片

(2)count數組本質上是邏輯的桶,為什麽說是邏輯上的桶?因為,它控制著桶的所有數據邏輯

但是申請的內存Temp才是每個桶的真正儲存空間,所以只能說是邏輯上的桶。

而當數據被分配到各個桶中又從桶(即就是從申請空間)被收集之後,就對申請空間進行釋放(因為留著再沒有必要)。

如何理解以上內容?請結合一下圖示理解具體分析:

技術分享圖片

第一行:所建桶的索引(可以看到總共為11個桶)

為什麽是11個桶?由我們在對待排數據求輸入桶對應的索引時匹配函數(MapToIndex)決定。

由於最大數據輸入匹配函數後所得桶對應索引為10。所以,在此必須如此設計。

第二行:所有桶置空

第三行:每個桶中待盛的數據個數

第四行:每個桶的右邊界索引

如何理解右邊界索引?

比如0號桶,第三行已經得出其待盛四個數據,那麽將來數據就會存入Temp[0],Temp[1],Temp[2],Temp[3]

比如1號桶,第三行已經得出其待盛三個數據,那麽將來數據就會存入Temp[4],Temp[5],Temp[6]

第五行:待排數據全部放入各個桶中後,桶的左邊界索引(這個是為了下面插入排序使用)。

技術分享圖片

(3)對每一個桶(即就是申請空間)中所盛的數據再利用插入排序進行排序

(4)數組中的數據即為已排序序列

技術分享圖片

【3】桶排序分析

桶排序是穩定排序算法。

桶排序使用範圍比較窄。

24.C語言最全排序方法小結(不斷更新)