基数排序算法的思想
基数排序也称作:桶排序
思想:把所有元素的个位进行排序,然后十位进行排序,然后百位进行排序,依次向高位递进,最后得到一个全局的小到大或者大到小的序列。
我们看下面序列
如果每次比较的都是1位的话,比如说57和54,先比较个位,7大于4,十位,是5==5,也就是说,每次比较的这一位的话,取值范围就是0-9
每一位取的范围是0-9
我们现在对下面这个序列进行桶排序:
从左向右,依次遍历原始的数据,最开始,是个位进行比较
43的个位是3,我们把43放在3号桶,47的个位是7,我们把47放在7号桶
11的个位是1,我们把11放在1号桶
以此类推。
我们先利用所有元素的个位和桶的序号进行比较,相等的话就放进去。
然后依次遍历0-9号桶,把所有的元素拷贝到原始的序列中
从全局来说,数列并没有变成有序的,但是我们看到它们的个位变得有序了。
因为最长的数字是2位。
所以我们要计算到十位。
接下来,我们从头开始遍历,根据每个元素的十位的数字,放到与之相等的桶号的桶中。
然后从0号-9号桶,依次把元素拷贝到原始的序列中
处理完了个位和十位之后,现在的序列就是有序的了!
len表示序列中的最多位数。
index依次输出number的个位,到十位,到百位,一直到最高位的值
桶:有的桶的元素多,有的桶的元素少
vector可动态扩容
基数排序算法的代码实现
如果我们用基数排序排序原始的乱序,对于整数和浮点数的排序方式在代码上是有区别的,没有办法得到统一。
我们在实现的时候,要考虑到负数的情况
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <string>
#include <vector>
using namespace std;
//基数排序代码
//时间复杂度:O(nd) 空间复杂度:O(n) 稳定性:稳定的排序
void RadixSort(int arr[], int size)
{
int maxData = arr[0];
for (int i = 1; i < size; i++)//找序列中的最大值
{
if (maxData < abs(arr[i]))//abs是求绝对值
{
maxData = abs(arr[i]);
}
}
int len = to_string(maxData).size();
//转成C++string字符串,然后调用size函数,获取字符个数
vector<vector<int>> vecs;//定义桶
int mod = 10;
int dev = 1;
for (int i = 0; i < len; mod *= 10, dev *= 10, i++)//O(d) d:数据的长度
{
vecs.resize(20);//20个桶,为了能处理负数 -9 - 9
for (int j = 0; j < size; j++) // O(n)
{
//得到当前元素第i个位置的数字
int index = arr[j] % mod / dev + 10;//前面10个桶存储负数,后面10个桶存储正数
vecs[index].push_back(arr[j]);
}
//依次遍历所有的桶,把元素拷贝回原始的数组当中
int idx = 0;
for (auto vec : vecs)//O(20) //从0-19号桶依次拷贝元素到原始数组中
{
for (int v : vec)//O(n) O(20)*O(n) = O(n)
{
arr[idx++] = v;
}
}
vecs.clear();//清空桶
}
}
int main()
{
int arr[10];
srand(time(NULL));
for (int i = 0; i < 10; i++)
{
arr[i] = rand() % 100 + 1;
}
arr[9] = -123;
arr[6] = -38;
for (int v : arr)
{
cout << v << " ";
}
cout << endl;
RadixSort(arr, 10);
for (int v : arr)
{
cout << v << " ";
}
cout << endl;
}
基数排序算法的性能分析
时间复杂度:O(nd)
空间复杂度😮(n)
开辟的桶的大小,存放的是所有的元素,所以空间复杂度是O(n)
稳定性:是稳定的排序
如果元素相同,都是在一个桶里放着,而且都是 从左到右遍历,从左向右放进桶的
而且最后桶里的元素也是按左右顺序依次拷贝到原序列中