C語言排序算法之桶排序解析
1. 算法思想
桶排序(Bucket sort)或所謂的箱排序,是一個排序算法,工作的原理是將數(shù)組分到有限數(shù)量的桶里,每個桶再分別排序(大部分是在分桶時,即插入時就排序了)。
個人理解,適合數(shù)據(jù)比較集中排序,桶的數(shù)量適當設(shè)置。
2. 實現(xiàn)原理
桶排序以下列程序進行:
- 設(shè)置一個定量的數(shù)組當作空桶子。
- 尋訪序列,并且把項目一個一個放到對應(yīng)的桶子去。
- 對每個不是空的桶子進行排序。
- 從不是空的桶子里把項目再放回原來的序列中。
3. 動態(tài)演示

(1)數(shù)據(jù)分桶

(2)桶內(nèi)數(shù)據(jù)排序(大部分是在分桶時,即插入時就排序了)

(3)然后連接就好了
4. 完整代碼
主要函數(shù)
插入函數(shù):void insert(BN* list, int value) 排序函數(shù):void bucket_sort(int* array, int size, int num)
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h> // rand() srand()
#include <time.h> // time()
typedef struct BucketNode
{
int data;
struct BucketNode* next;
} BN;
void displayL(BN* L); // 輸出鏈表
void display(int* array, int size); // 輸出數(shù)組
int check(int* array, int size); // 檢查函數(shù)
/***************************************************************************
* @date 2020/12/03
* @brief 合并鏈表
* @param head 頭指針
* @param list 順序數(shù)據(jù)鏈表
***************************************************************************/
BN* merge(BN* head, BN* list)
{
BN* last = head;
last->next = list->next;
while (last->next) {
last = last->next;
}
return last;
}
/***************************************************************************
* @date 2020/12/03
* @brief 順序插入節(jié)點
* @param list 代表第幾個桶的鏈表
* @param value 數(shù)據(jù)
***************************************************************************/
void insert(BN* list, int value)
{
BN* prev = list;
BN* curr = list->next;
BN* node = (BN*)malloc(sizeof(BN));
node->data = value;
node->next = NULL;
if (curr == NULL) {
prev->next = node;
} else {
while (curr != NULL && curr->data < value) {
prev = curr;
curr = curr->next;
}
prev->next = node;
node->next = curr;
}
}
/***************************************************************************
* @date 2020/12/03
* @brief 桶排序主程序
* @param array 數(shù)組
* @param size 數(shù)組大小
* @param num 幾個桶
***************************************************************************/
void bucket_sort(int* array, int size, int num)
{
// 申請內(nèi)存,二級指針,初始化,可以理解頭指針沒數(shù)據(jù),從下一個開始存數(shù)數(shù)據(jù)
BN** buckets = (BN**)malloc(sizeof(BN*) * num);
for (int i = 0; i < num; i++) {
*(buckets + i) = (BN*)malloc(sizeof(BN));
(*(buckets + i))->next = NULL;
}
// 1. 找到最大值和最小值求間隔(桶的大?。?
int max = array[0];
int min = array[0];
for (int i = 0; i < size; i++) {
if (array[i] > max) {
max = array[i];
}
if (array[i] < min) {
min = array[i];
}
}
int space = ((max - min) / num) + 1;
// 2. 一個一個分桶排序
for (int i = 0; i < size; i++) {
int n = (array[i] - min) / space;
insert(*(buckets + n), array[i]);
}
for (int i = 0; i < num; i++) {
printf("第 %d 個桶數(shù)據(jù): ", i);
displayL((*(buckets + i))->next);
}
// // 3. 合并鏈表
// BN* head = (BN*)malloc(sizeof(BN));
// head->next = NULL;
// BN* last = merge(head, *(buckets + 0));
// for (int i = 1; i < num; i++) {
// if ((*(buckets + i))->next) {
// last = merge(last, *(buckets + i));
// }
// }
// head = head->next;
// // 4. 把鏈表值返回數(shù)組
// for (int i = 0; i < size; i++) {
// array[i] = head->data;
// head = head->next;
// }
// 3+4. 當然也可以不合并鏈表,直接把數(shù)據(jù)返回數(shù)組
int index = 0;
for (int i = 0; i < num; i++) {
if ((*(buckets + i))->next != NULL) {
BN* temp = (*(buckets + i))->next;
while (temp != NULL) {
array[index++] = temp->data;
temp = temp->next;
}
}
}
}
int main()
{
// 測試用例
// int array[] = {49, 38, 65, 97, 76, 13, 27, 49, 10};
// int array_size = sizeof(array) / sizeof(array[0]);
// int bucket_num = 5;
// printf("%d \n", array_size);
// printf("排序前數(shù)組:");
// display(array, array_size);
// bucket_sort(array, array_size, bucket_num);
// printf("排序后數(shù)組:");
// display(array, array_size);
// 隨機測試
int bucket_num = 5; // 桶的個數(shù)
int array_num = 20; // 數(shù)組數(shù)量
int array_size = 20; // 數(shù)組大小
int array[array_size]; // 數(shù)組初始化
srand((unsigned int)time(NULL)); // 隨機數(shù)種子,保證每次不一樣
for (int i = 0; i < array_num; i++) {
for (int j = 0; j < array_size; j++) {
array[j] = rand() % 1000; // 隨機生成數(shù)大小 0~999
}
printf("原來的數(shù)組:");
display(array, array_size);
bucket_sort(array, array_size, bucket_num);
printf("排序后數(shù)組:");
display(array, array_size);
// 檢測排序結(jié)果
if (check(array, array_size) != 0) {
exit(-1);
}
printf("\n");
}
return 0;
}
/***************************************************************************
* @date 2020/12/03
* @brief 輸出線性表
* @param L 首節(jié)點
***************************************************************************/
void displayL(BN* L)
{
BN* p = L; // p 指向首結(jié)點
while (p != NULL) { // 不為空,依次遍歷
printf("%d ", p->data); // 打印
p = p->next; // p 移向下一個節(jié)點
}
printf("\n");
}
/***************************************************************************
* @date 2020/12/03
* @brief 輸出數(shù)組
* @param array 數(shù)組
* @param size 數(shù)組大小
***************************************************************************/
void display(int* array, int size)
{
for (int i = 0; i < size; i++) {
printf("%d ", array[i]);
}
printf("\n");
}
/**
* @brief 檢查函數(shù),從小到大
*
* @param array 數(shù)組首指針
* @param size 數(shù)組大小
*/
int check(int* array, int size)
{
for (int i = 0; i < size - 1; i++) {
if (array[i] > array[i + 1]) {
printf("sort array fail...\n");
return -1;
}
}
printf("sort array success...\n");
return 0;
}
5. 結(jié)果展示

6. 算法分析
時間復(fù)雜度:
- 最好: O ( n ) O(n) O(n)
- 最壞: O ( n 2 ) O(n^{2}) O(n2)
- 平均: O ( n + k ) O(n+k) O(n+k)
空間復(fù)雜度: O ( n ∗ k ) O(n*k) O(n∗k)
穩(wěn)定性:穩(wěn)定(也有說根據(jù)桶內(nèi)排序決定穩(wěn)定性)
到此這篇關(guān)于C語言排序算法之桶排序解析的文章就介紹到這了,更多相關(guān)C語言桶排序內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言中的pause()函數(shù)和alarm()函數(shù)以及sleep()函數(shù)
這篇文章主要介紹了C語言中的pause()函數(shù)和alarm()函數(shù)以及sleep()函數(shù),是C語言入門學(xué)習中的基礎(chǔ)知識,需要的朋友可以參考下2015-09-09
C++中的頭文件與Extern(外部函數(shù)調(diào)用)方式
這篇文章主要介紹了C++中的頭文件與Extern(外部函數(shù)調(diào)用)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08
深入HRESULT與Windows Error Codes的區(qū)別詳解
本篇文章是對HRESULT與Windows Error Codes的區(qū)別進行了詳細的分析介紹,需要的朋友參考下2013-05-05
Linux系統(tǒng)下C語言中的標準IO總結(jié)
最近用到了C語言的標準IO庫,由于對其中的一些細節(jié)不是非常清楚,導(dǎo)致了許多Bug,花了好長時間來調(diào)試,所以在此做個筆記,這篇文章主要給大家介紹了關(guān)于Linux系統(tǒng)下C語言中標準IO的相關(guān)資料,需要的朋友可以參考下2024-01-01

