首先来了解桶排序
将数组分成若干类 分这个类的条件 我们自己决定
这里我们用的是 每隔5个数分为一类
如20~24 25~29 30~34...
数组中的元素满足这样的条件就会被放在相应的桶中
如: 23会被放在20~24的桶中
假设我们有这样一个数组
int arr[15] = { 34,36,31,78,65,32,33,34,89,90,91,67,52,71,77};
我们决定桶的数量 为确保数组中的元素都能如桶
一般设定为 :
原数组中的最大值-最小值+1
想判断当前数组元素应该入哪个桶 我们这里的条件是:
当前元素的值-最小值/5 为他要入的桶的下标
如 最小元素20 当前元素40 那么他要进去的桶的下标为 (40-20)/5=4
我们这里所谓的桶 其实就是一个哈希数组
这里用的是链式存储法 (每一个元素都是一个链表的头)
如相应的桶 就是 把元素添加到哈希数组的相应下标上的链表上去 在这里我们添加用的是
链表插入的方式 直接根据节点的值将节点插入到相应的位置 完成排序
之后我们只需要 遍历哈希数组并遍历哈希数组元素 吧 哈希数组中的元素都放回到原数组中去
这样就实现了桶排序
桶排序完整代码如下
#include<iostream>
using namespace std;
#define jiange 5
struct List
{
int id;
List* pNext;
};
void Insert(List*&pHead,int value)
{
List* pTemp=new List;
pTemp->id = value;
pTemp->pNext = NULL;
//链表中没有节点
if (pHead == NULL)
{
pHead = pTemp;
return;
}
//链表中的头节点比当前节点的值大
//头插入
if (pTemp->id < pHead->id)
{
pTemp->pNext=pHead;
pHead = pTemp;
return;
}
//链表的头的值比当前要插入的节点的值小
//遍历链表 找到要插在谁的后面
List* pMark = pHead;
while (pMark->pNext != NULL)
{
if (pMark->pNext->id > pTemp->id)
{
pTemp->pNext = pMark->pNext;
pMark->pNext = pTemp;
return;
}
pMark = pMark->pNext;
}
//遍历到最后一个节点 都没找到比当前节点大的节点 插在最后
pMark->pNext = pTemp;
}
void BuckeSort(int arr[],int nLen)
{
int begin = arr[0];
int end =arr[0];
//参数校验
if (arr == NULL || nLen <= 10)
{
return;
}
//找到最大值和最小值确定桶的数量
for (int i = 0; i < nLen; i++)
{
if (arr[i] < begin)
begin = arr[i];
if (arr[i] > end)
end = arr[i];
}
int nBucketCount = end -begin + 1;
//开辟空间
List** Hash = new List*[nBucketCount];
::memset(Hash, 0, sizeof(List*)* nBucketCount);
//遍历数组入桶
for (int i = 0; i < nLen; i++)
{
//入桶函数
Insert(Hash[(arr[i]-begin)/jiange], arr[i]);
}
//出桶
int j = 0;
for (int i = 0; i < nBucketCount; i++)
{
while (Hash[i])
{
List* pDel = Hash[i];
Hash[i] = Hash[i]->pNext;
arr[j++] =pDel->id;
delete pDel;
pDel = NULL;
}
}
delete Hash;
Hash = NULL;
}
int main()
{
int arr[15] = { 34,36,31,78,65,32,33,34,89,90,91,67,52,71,77};
BuckeSort(arr, 15);
for (int val : arr)
{
cout << val << " ";
}
return 0;
}
基数排序:
可以看做是桶排序的另一种优化 只不过 他的如桶条件变了
而且需要额外创建一个记录链表的尾的哈希数组; 用于添加节点
尾入 头出
思想:
先把数组中的元素根据个位入桶
出桶放入原数组
在把数组中的元素根据十位入桶
出桶放入原数组...
直到把数组中的元素根据 数组中的最大的元素的最高位 入桶
出桶放入原数组 结束
这样一来 数组自己就排序好了
基数排序:
代码如下
#include<iostream>
using namespace std;
#define jiange 5
struct List
{
int id;
List* pNext;
};
void AddNode(List*& pHead, List*& pEnd ,int value)
{
List* pTemp = new List;
pTemp->id = value;
pTemp->pNext = NULL;
//链表中没有节点
if (pHead == NULL)
{
pHead = pTemp;
}
//链表有节点
//尾插入
else
{
pEnd->pNext = pTemp;
}
pEnd = pTemp;
}
void RadixSort(int arr[], int nLen)
{
//参数校验
if (arr == NULL || nLen <= 10)
{
return;
}
//找到最大值
int max = arr[0];
for (int i = 0; i < nLen; i++)
{
if (arr[i] > max)
{
max = arr[i];
}
}
int base = 1;
//创建桶中链表的头节点数组
List** pHeadarr = new List * [10];
//创建桶中链表的尾节点数组
List** pEndarr = new List * [10];
::memset(pHeadarr, 0, sizeof(List*) * 10);
::memset(pEndarr, 0, sizeof(List*) * 10);
while (max / base != 0)
{
//arr的元素放入桶中
for (int i = 0; i < nLen; i++)
{
//链表尾部添加
AddNode(pHeadarr[arr[i] / base % 10], pEndarr[arr[i] / base % 10], arr[i]);
}
//出桶
int j = 0;
for (int i = 0; i < 10; i++)
{
while (pHeadarr[i])
{
List* pDel = pHeadarr[i];
pHeadarr[i] = pHeadarr[i]->pNext;
arr[j++] = pDel->id;
delete pDel;
pDel = NULL;
}
}
base *= 10;
}
}
int main()
{
int arr[15] = { 34,36,31,78,65,32,33,34,89,90,91,67,52,71,77 };
RadixSort(arr, 15);
for (int val : arr)
{
cout << val << " ";
}
return 0;
}