C++用連結串列實現一個箱子排序附原始碼詳解
01 箱子排序
1.1 什麼是分配排序?
分配排序的基本思想:排序過程無須比較關鍵字,而是通過"分配"和"收集"過程來實現排序.它們的時間複雜度可達到線性階:O(n)。
1.2 什麼是箱子排序?
箱子排序是分配排序的一種,箱子排序也稱桶排序(Bucket Sort),其基本思想是:設定若干個箱子,依次掃描待排序的記錄 R[0],R[1],…,R[n-1],把關鍵字等於 k 的記錄全都裝入到第 k 個箱子裡(分配),然後按序號依次將各非空的箱子首尾連線起來(收集)。
比如,要將一個班的同學按分數排序,分數範圍是0-100分。需設定 101 個"箱子"(R[0],R[1],…,R[100]),排序時依次將每個同學按分數放入相應的箱子裡,然後依次將這些箱子首尾相接,就得到了按分數遞增序排列的一個班的同學。
1.3 關於箱子個數
箱排序中,箱子的個數取決於關鍵字的取值範圍。
若關鍵字的取值範圍是0到m-1的整數,則必須設定 m 個箱子。因此箱排序要求關鍵字的型別是有限型別,否則可能要無限個箱子。
02 連結串列實現箱子排序
一般情況下每個箱子中存放多少個關鍵字相同的記錄是無法預料的,故箱子的型別應設計成連結串列為宜。
我們現在來講解一個簡單的例子,以便來讓大家更好了解這個過程。
2.1 example
下面是一個學生連結串列。為了更好說明問題,我們簡化了學生的儲存結構。每個學生節點儲存一個字元,表示學生的姓名,再存一個數字,表示學生的分數。分數範圍為0-5。

2.2 箱子排序的步驟
有了上面的輸入連結串列以後。我們採用以下步驟進行箱子排序:
1) 逐個刪除輸入連結串列的節點,然後把刪除的節點分配到相應的箱子中。
2) 把每個箱子中的元素收集並連結起來,使其成為一個有序連結串列。
比如上面的輸入連結串列,我們要做的是:
1) 連續刪除連結串列的首元素,並將其插入到相對應箱子的連結串列頭部。
2) 從最後一個箱子開始,逐個刪除每個箱子的元素,並將其插入一個初始為空的連結串列的頭部。
如下圖所示:

那麼排序好的連結串列如下:

03 動手寫程式碼
3.1 studentRecord結構體
先來看看程式碼:
1struct studentRecord 2{ 3int score; 4string name; 5 6studentRecord() {} 7studentRecord(int theScore, string theName) :score(theScore), name(theName) {} 8 9int operator != (const studentRecord & x) const 10{ 11return (score != x.score); 12} 13operator int() const { return score; } 14};
在studentRecord這個結構體裡面,我們過載了 != 這個運算子,以便用於比較等操作。還過載了int()運算子,這樣一來,藉助int()轉換符就可以直接對學生結構體進行+-*/等操作了。
3.2 箱子排序程式碼
還是先看看程式碼吧。
1void binSort(chain<studentRecord> & theChain, int range) 2{ 3chain<studentRecord> * bin = new chain<studentRecord>[range + 1];// 0 to range 4int numberOfElements = theChain.size(); 5 6for (int i = 0; i < numberOfElements; i++) 7{ 8studentRecord record = theChain.get(0); 9theChain.erase(0); 10 11bin[record.score].insert(0, record); 12} 13for (int j = range; j >= 0; j--) 14{ 15while (!bin[j].empty()) 16{ 17studentRecord record = bin[j].get(0); 18bin[j].erase(0); 19theChain.insert(0, record); 20} 21} 22 23delete[] bin; 24}
該函式只有兩個引數,一個是學生連結串列。還有一個是排序範圍(設定為0~range)。函式主體就是按部就班的進行上面所說的兩步操作了。這裡的chain連結串列是事先封裝好的一個類。
04 完整程式碼
貼上一個完整的程式碼:
1#include <iostream> 2#include <string> 3#include <time.h> 4#include <stdlib.h> 5#include "../03_線性表_鏈式描述/chain.h" 6#include "../03_線性表_鏈式描述/chain.cpp" 7 8using std::cout; 9using std::cin; 10using std::endl; 11using std::string; 12 13struct studentRecord 14{ 15int score; 16string name; 17 18studentRecord() {} 19studentRecord(int theScore, string theName) :score(theScore), name(theName) {} 20 21int operator != (const studentRecord & x) const 22{ 23return (score != x.score); 24} 25operator int() const { return score; } 26}; 27 28//override out 29ostream & operator<<(ostream & out, const studentRecord & x) 30{ 31out << x.name << "" << x.score << endl; 32return out; 33} 34 35void binSort(chain<studentRecord> & theChain, int range) 36{ 37chain<studentRecord> * bin = new chain<studentRecord>[range + 1];// 0 to range 38int numberOfElements = theChain.size(); 39 40for (int i = 0; i < numberOfElements; i++) 41{ 42studentRecord record = theChain.get(0); 43theChain.erase(0); 44 45bin[record.score].insert(0, record); 46} 47for (int j = range; j >= 0; j--) 48{ 49while (!bin[j].empty()) 50{ 51studentRecord record = bin[j].get(0); 52bin[j].erase(0); 53theChain.insert(0, record); 54} 55} 56 57delete[] bin; 58} 59 60int main() 61{ 62srand(time(0)); 63chain<studentRecord> students; 64studentRecord someOne; 65for (int i = 0; i < 100; i++) 66{ 67char Name = i % 26 + 'A'; 68someOne.name = Name; 69someOne.score = rand() % 101; 70students.insert(0, someOne); 71} 72 73binSort(students, 100); 74cout << ""; 75students.output(cout); 76 77cin.get(); 78 79return 0; 80}
最後貼上一張執行效果:

欲獲取程式碼,請關注我們的微信公眾號【程式猿聲】,在後臺回覆: listbox 。即可下載。

推薦文章: ofollow,noindex" target="_blank">10分鐘教你用Python做個打飛機小遊戲超詳細教程
推薦文章: 10分鐘教你用python下載和拼接微信好友頭像圖片
推薦文章: 10分鐘教你用python一行程式碼搞點大新聞
推薦文章: 10分鐘教你用python打造貪吃蛇超詳細教程