【数据结构】排序算法系列——桶排序(附源码+图解)

桶排序

算法思想

桶排序(BucketSort),也被叫做箱排序,它将整个数据组分为n个相同大小的子区间,这类子区间或称为 。输入数据是均匀、独立分布的,所以一般不会出现一个桶中装有过多数据的情况。作为一种排序算法,它会对每个桶中的数进行排序,然后直接遍历桶,最终就可以按照次序输出数据。

它的算法步骤大概如下所示:

  1. 设置定量数组作为每个桶的容量大小
  2. 遍历数据组,并将数据一个一个放到对应桶中
  3. 对非空桶中的数据进行排序
  4. 最后将数据按照大体排序放回原来序列中

图解

C语言代码解析

c 复制代码
#define CRT_SECURE_NO_WARNINGS 1
//桶排序
#include <stdio.h>
#include <stdlib.h>	

#define MAX 1000
#define BUCKET_NUM 10

//建桶中节点
struct BNode
{
	int data;
	struct Node* next;
};

//建桶
struct BNode* CreateNode(int data)
{
	struct BNode* newNode = (struct BNode*)mlooc(sizeof(struct BNode));
	newNode->data = data;
	newNode->next = NULL;
	return newNode;
}

//插入节点到链表中
void insertNode(struct BNode* head, struct BNode* newNode)
{
	struct BNode* p = head;
	while (p->next != NULL)
	{
		p = p->next;
	}
	p->next = newNode;
}

//桶排序
void BucketSort(int arr[], int n)
{
	struct BNode* bucket[BUCKET_NUM];
	for (int i = 0; i < BUCKET_NUM; i++)
	{
		bucket[i] = CreateNode(0);//创建多个桶
	}
	for (int i = 0; i < n; i++)
	{
		int index = arr[i] / BUCKET_NUM;//确定元素所在桶的位置
		struct BNode* newNode = CreateNode(arr[i]);
		insertNode(bucket[index], newNode);//插入节点到链表中
	}
	for (int i = 0; i < BUCKET_NUM; i++)//对每个桶进行排序
	{
		struct BNode* p = bucket[i]->next;
		while (p != NULL)
		{
			printf("%d ", p->data);
			p = p->next;
		}
	}
}

时间复杂度

桶排序的时间复杂度取决于以下几个因素:

  1. 将数据分配到桶的时间
  2. 对每个桶内的数据进行排序的时间
  3. 合并所有桶中的数据的时间

假设我们有 n 个元素需要排序,并且我们使用了 k 个桶。

1. 将数据分配到桶的时间复杂度

将每个元素放入对应的桶中的操作通常是一个线性的操作。对于每一个元素,确定它所属的桶位置的时间是 O(1) 的,总的时间复杂度为 O(n)。

2. 对每个桶内的数据进行排序的时间复杂度

每个桶中的数据数量决定了桶内排序的复杂度。如果所有元素均匀分布到 k 个桶中,那么每个桶中的元素大约是 n/k 个。通常,我们会在每个桶内使用一种常规的排序算法(如快速排序或插入排序)来对桶内的元素排序。

  • 如果使用插入排序或其他 O((n/k)^2) 的排序算法来对每个桶排序,那么对所有桶排序的时间复杂度为 O(k * (n/k)^2) = O(n^2/k)。
  • 如果使用更高效的排序算法(如快速排序,时间复杂度为 O((n/k) * log(n/k))),那么对每个桶排序的时间复杂度为 O(n/k * log(n/k)),所有桶的总排序时间复杂度为 O(n * log(n/k))。
3. 合并所有桶中的数据的时间复杂度

在所有桶都排序好之后,需要将它们合并起来,这个步骤的时间复杂度是 O(n)。

综合时间复杂度

综合上述三部分的分析,桶排序的平均时间复杂度为:

O(n) + O(n \log(n/k)) + O(n) = O(n \log(n/k))

桶排序的最坏情况时间复杂度

桶排序的最坏情况发生在所有元素都被分配到一个桶中,导致排序退化为对所有 n 个元素进行一次 O(n log n) 的排序。在这种情况下,桶排序的时间复杂度为:

O(n \log n)

总而言之,桶排序在数据分布均匀的情况下效率非常高,但如果数据分布不均匀或者不适合划分到桶中时,可能会退化为更高的复杂度。

稳定性

桶排序是否稳定取决于我们将元素插入桶中时是否会改变元素的相对顺序。

相关推荐
昂子的博客20 分钟前
热门面试题第15天|最大二叉树 合并二叉树 验证二叉搜索树 二叉搜索树中的搜索
java·数据结构·算法
ん贤41 分钟前
蓝桥杯考前复盘
c语言·c++·算法·职场和发展·蓝桥杯
想成为配环境大佬1 小时前
P8697 [蓝桥杯 2019 国 C] 最长子序列
算法·蓝桥杯·双指针
khazix1011 小时前
【C语言】--- 文件操作
c语言·开发语言
理智的灰太狼1 小时前
题目 2701: 蓝桥杯2022年第十三届决赛真题-取模(C/C++/Java组)
c语言·c++·蓝桥杯
麦麦Max1 小时前
STL-函数对象
开发语言·c++·算法
DeepLink2 小时前
🧠 AI论文精读 :《Attention is All You Need》
人工智能·算法
躺着听Jay3 小时前
QCustomPlot-相关优化
java·qt·算法
扫地僧0093 小时前
【中大厂面试题】腾讯 后端 校招 最新面试题
java·数据结构·后端·算法·面试·排序算法
天天年年天天。3 小时前
在 Linux 或 Unix 系统中使用 pthread_create 创建新线程的步骤
linux·数据结构