【算法】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{

3    int score;
4    string name;
5
6    studentRecord() {}
7    studentRecord(int theScore, string theName) :score(theScore), name(theName) {}
8
9    int operator != (const studentRecord & x) const
10    {
11        return (score != x.score);
12    }
13    operator int() const return score; }
14};

在studentRecord這個結構體里面,我們重載了 != 這個運算符,以便用於比較等操作。還重載了int()運算符,這樣一來,借助int()轉換符就可以直接對學生結構體進行+-*/等操作了。

3.2 箱子排序代碼

還是先看看代碼吧。

 1void binSort(chain<studentRecord> & theChain, int range)
2
{
3    chain<studentRecord> * bin = new chain<studentRecord>[range + 1];  // 0 to range
4    int numberOfElements = theChain.size();
5
6    for (int i = 0; i < numberOfElements; i++)
7    {
8        studentRecord record = theChain.get(0);
9        theChain.erase(0);
10
11        bin[record.score].insert(0, record);
12    }
13    for (int j = range; j >= 0; j--)
14    {
15        while (!bin[j].empty())
16        {
17            studentRecord record = bin[j].get(0);
18            bin[j].erase(0);
19            theChain.insert(0, record);
20        }
21    }
22
23    delete[] 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{

15    int score;
16    string name;
17
18    studentRecord() {}
19    studentRecord(int theScore, string theName) :score(theScore), name(theName) {}
20
21    int operator != (const studentRecord & x) const
22    {
23        return (score != x.score);
24    }
25    operator int() const return score; }
26};
27
28//override out
29ostream & operator<<(ostream & out, const studentRecord & x)
30{
31    out << x.name << "  " << x.score << endl;
32    return out;
33}
34
35void binSort(chain<studentRecord> & theChain, int range)
36
{
37    chain<studentRecord> * bin = new chain<studentRecord>[range + 1];  // 0 to range
38    int numberOfElements = theChain.size();
39
40    for (int i = 0; i < numberOfElements; i++)
41    {
42        studentRecord record = theChain.get(0);
43        theChain.erase(0);
44
45        bin[record.score].insert(0, record);
46    }
47    for (int j = range; j >= 0; j--)
48    {
49        while (!bin[j].empty())
50        {
51            studentRecord record = bin[j].get(0);
52            bin[j].erase(0);
53            theChain.insert(0, record);
54        }
55    }
56
57    delete[] bin;
58}
59
60int main()
61
{
62    srand(time(0));
63    chain<studentRecord> students;
64    studentRecord someOne;
65    for (int i = 0; i < 100; i++)
66    {
67        char Name = i % 26 + 'A';
68        someOne.name = Name;
69        someOne.score = rand() % 101;
70        students.insert(0, someOne);
71    }
72
73    binSort(students, 100);
74    cout << "  ";
75    students.output(cout);
76
77    cin.get();
78
79    return 0;
80}

最后貼上一張運行效果:

欲獲取代碼,請關注我們的微信公眾號【程序猿聲】,在后台回復:listbox 。即可下載。

微信公眾號

推薦文章:10分鍾教你用Python做個打飛機小游戲超詳細教程

推薦文章:10分鍾教你用python下載和拼接微信好友頭像圖片

推薦文章:10分鍾教你用python一行代碼搞點大新聞

推薦文章:10分鍾教你用python打造貪吃蛇超詳細教程


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM