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

桶排序

算法思想

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

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

稳定性

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

相关推荐
happymaker06262 小时前
LeetCodeHot100——42.接雨水
算法
阿正的梦工坊2 小时前
【Rust】07-错误处理:Option、Result 与 ? 运算符
开发语言·算法·rust
烬羽3 小时前
从零理解树与二叉树:用 JS 带你手撕遍历和递归
javascript·数据结构
YHL3 小时前
🚀从零理解树与二叉树 —— 概念、实现与遍历
前端·javascript·数据结构
JieE2123 小时前
JS 到底有多少种数据类型?从ECMA规范到内存本质,一文彻底搞懂
javascript·数据结构·面试
努力努力再努力wz4 小时前
【内存管理与高并发内存池系列】从 mmap 到 malloc:文件映射、匿名映射与 glibc 内存分配机制详解
linux·c语言·数据结构·数据库·c++·qt·链表
J2虾虾4 小时前
C 语言 void 完全用法
c语言·开发语言
八解毒剂4 小时前
数据结构-平衡二叉树——对二叉搜索树的优化
数据结构·c++·算法
wu_ye_m4 小时前
学习c语言第35天 函数声明和定义
c语言·开发语言·学习
运行时记录4 小时前
别再手动写提示词了 — SkillOpt 让技能文档自己进化
算法