首先来了解桶排序
将数组分成若干类 分这个类的条件 我们自己决定
这里我们用的是 每隔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
- 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
- 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;
- }