🥔 原理介绍:
[排序算法] 基数排序 (C++) - Amαdeus - 博客园
前述的各类排序方法都是建立在关键字比较的基础上,而基数排序是一种非比较型整数排序算法。它的基本思想是将整数按位数切割成不同的数字,然后按每个位数分别比较。
例如,将数字按个位、十位、百位...分别比较,基数排序有两种方法:
-
MSD:从低位到高位进行排序。这样从最低位开始排序时,较小的数就先出现在桶里。
-
LSD:从高位到低位进行排序。这样从最高位开始排序时,较大的数就先出现在桶里。
基数排序算法适用于对多个整数或者多个字符串进行升序或降序排序。
一个整数由多个数字组成,例如 123 由 1、2、3 这 3 个数字组成;一个字符串由多个字符组成,例如 "lisi" 由 "l"、"i"、"s"、"i" 这 4 个字符组成。基数排序算法的实现思路是:对于待排序序列中的各个元素,依次比较它们包含的各个数字或字符,根据比较结果调整各个元素的位置,最终就可以得到一个有序序列。
详见:基数排序算法
🥔 特点:
-
非比较型排序算法:基数排序不通过比较来决定元素间的相对次序,而是通过对数据的每位进行计数来确定每个数字的位置。
-
稳定性:基数排序是稳定的排序算法,也就是说,在基数排序过程中,相同大小的数字的相对位置不会发生变化。
-
时间复杂度:基数排序的时间复杂度取决于数据范围和数据的位数。当数据范围很小,且数据的位数较少时,基数排序是一种较快的排序算法。
-
空间复杂度:基数排序需要较多的空间来存储桶和计数器,因此空间复杂度较高。
-
适用范围:基数排序适用于排序非负整数,并且在数据范围不大,且数据的位数较少的情况下效率较高。
🥔 代码示例:
数组数字排序:
/************************************************************
* @description: heap sort
* @author: kashine
* @version: 1.0
* @mail: likaiqinchina@gmail.com
* @date: 2022/12/31
*************************************************************/
#include <iostream>
using namespace std;
// 对于数字来讲0~9,MAX = 10,对于字符串来讲a~z,MAX = 26
#define MAX 10 //基数
//计数排序算法
// array:数组
// place:数位,如1 10 100 1000等
// 按照某一位对数组array进行排序
void counting_sort(int array[], int place, int size)
{
int output[size];
// 初始化一个数组,记录各个元素的出现次数
int count[MAX] = { 0 };// 统计每个桶放了几个数字
// 统计各个元素出现的次数
for (int i = 0; i < size; i++) count[(array[i] / place) % 10]++;
// if(place == 1)
// {
// cout<< "个位各个数字出现次数:";
// for(int i = 0; i < 10; i++)cout<< count[i]<< " ";
// cout<<endl;
// }
// 累加count 数组中的出现次数
// 真的是妙!
// 某个数字,比如2,个位数为2的可能有多个,个位数比2小的可能同样有多个
// 那么个位数为2的元素放在哪里呢?前面肯定是个位数小于2的,个数为:个位数小于2的数字的个数和,
// 个位数同样为2的放在其后面,顺序不限
// 上面的count中从下标0~9,代表着各个个位数字出现次数,按照下面方式累加
// cout[2]变为第二个元素应该放的位置,也就是2出现次数加上1、0出现次数
// 假如存在2个 个位数为2的数字,其前面只有一个 个位数为0的数字,
// 那么cout[0] = 1; cout[1] = 0; cout[2] = 2;
// 经过累加之后cout[0] = 1; cout[1] = [1]; cout[2] = 3;
// 也就是说个位数为0的应该放在第一个位置,下标-1,即下标为0的位置
// 由于不存在个位数为1的数字,所以count[1]不会被访问,不影响前后数字存放
// 个位数为2的数字应该放在第三个位置,下标为3 - 1 = 2
// 由于存在两个个位数为2的数字,在存放完一个个位数为2的数字之后,将count[2] - 1,
// 下次再遇到个位数为2的数字,存放在前一个位置,也就是下标为1的位置,再次cout[2] - 1,
// 由于不存在第三个个位数为2的数字,所以cout[2]不会被继续访问递减,
// count[2]最终等于个位数小于2的数字个数
for (int i = 1; i < 10; i++) count[i] += count[i - 1];
// if(place == 1)
// {
// cout<< "从小到大累加后:";
// for(int i = 0; i < 10; i++)cout<< count[i]<< " ";
// cout<<endl;
// }
// 根据count 数组中的信息,找到各个元素排序后所在位置,存储在output 数组中
for (int i = size - 1; i >= 0; i--)
{
output[count[(array[i] / place) % 10] - 1] = array[i];
count[(array[i] / place) % 10]--;
}
// 将output 数组中的数据原封不动地拷贝到 array 数组中
for (int i = 0; i < size; i++) array[i] = output[i];
}
// 找到整个序列中的最大值
int get_max(int array[], int size)
{
int i, max = array[0];
for (i = 1; i < size; i++)
if (array[i] > max)
max = array[i];
return max;
}
// 基数排序算法
void radix_sort(int array[], int size) {
// 找到序列中的最大值
int place, max = get_max(array, size);
// 根据最大值具有的位数,从低位依次调用计数排序算法
for (place = 1; max / place > 0; place *= 10)
counting_sort(array, place, size);
}
// 输出 array 数组中的数据
void display_array(int array[], int size) {
int i;
for (i = 0; i < size; ++i) {
cout<< array[i]<< " ";
}
cout<< endl;
}
int main() {
int array[12] = { 121, 432, 564, 23, 1, 10, 45, 788, 2, 6, 23, 19};
int size = sizeof(array) / sizeof(array[0]);
display_array(array, size);// 前
radix_sort(array, size);
display_array(array, size);// 后
return 0;
}
🥔 算法复杂度:
最坏时间复杂度:O(k*n)
最好时间复杂度:O(k*n)
空间复杂度:O(n + k)
k为程序中place变量大小,在对数组排序的时候为10,对小写字符串排序的时候为26。