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

桶排序

算法思想

桶排序(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)

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

稳定性

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

相关推荐
西几1 小时前
代码训练营 day48|LeetCode 300,LeetCode 674,LeetCode 718
c++·算法·leetcode
武子康1 小时前
大数据-187 Elasticsearch - ELK 家族 Logstash Filter 插件 使用详解
大数据·数据结构·elk·elasticsearch·搜索引擎·全文检索·1024程序员节
liuyang-neu1 小时前
力扣第420周赛 中等 3324. 出现在屏幕上的字符串序列
java·算法·leetcode
无际单片机项目实战1 小时前
为什么STM32的HAL库那么难用,ST还是要硬推HAL库?
c语言·stm32·单片机·嵌入式硬件·物联网
想做白天梦2 小时前
双向链表(数据结构与算法)
java·前端·算法
小卡皮巴拉2 小时前
【力扣刷题实战】相同的树
c语言·算法·leetcode·二叉树·递归
zyhomepage2 小时前
科技的成就(六十四)
开发语言·人工智能·科技·算法·内容运营
想做白天梦2 小时前
多级反馈队列
java·windows·算法
潇雷2 小时前
算法Day12|226-翻转二叉树;101-对称二叉树;104-二叉树最大深度;111-二叉树最小深度
java·算法·leetcode
爱编程— 的小李3 小时前
开关灯问题(c语言)
c语言·算法·1024程序员节