[排序算法] 基数排序 (C++)

基数排序解释

基数排序

基数排序 Radix Sort 是一种非基于比较的排序算法。在基数排序中,和计数排序、桶排序的思想类似,我们要再次用到这个东西。😉
*如果还有对计数排序、桶排序不了解的童鞋,可以看看这里哟~ ❤❤❤ 计数排序 桶排序 ❤❤❤

基数排序思想

其基本思想是从数据的低位开始,按照这一位数字的值(0~9)放到对应的编号为 0~9 的桶中。我们按照这一位数字进行完了排序,再按照次低位(下一位)数字进行上述的操作。重复这样的操作一直到最高位,直到最后每一位数字都进行完排序,我们的整个基数排序也就完成啦。🥰

基数排序步骤

1、我们先定义以下几个东西
一个大小为 10 (下标0~9)count[] 数组(count[] 中每一项对应一个桶),统计每一位数字出现的次数;
一个大小为 n 临时数组 tmp[] 用于存储按照当前一位数字排序后的序列;
还有一个大小为 10 数组 start[] 用于记录每一位数字在序列中第一次出现的索引。

2、找到当前待排序序列中的最大元素,计算其最高位数字是第几位;

3、从低位开始,统计每一位数字出现的个数记录到 count[] 中,
由递推式 start[i] = start[i - 1] + count[i - 1] 得到每一位数字第一次出现的位置。
(其中当 i = 0 时,即数字0,第一次出现的位置默认是0。不管是否有数字0,都默认其第一个位置为0,这个递推式才能正确地执行起来)

然后将每个元素按照当前的这一位数字放入对应的 0~9 的桶中,每一次将所有元素放入对应桶中后,根据 start[] 将其放到临时数组 tmp[],再将其拷贝到原数组中;

4、重复步骤3,当按照最高位放入桶中的操作完成后,我们再放回原数组,此时就已经完成了基数排序。😮



基数排序动态演示

我们以序列 a[] = {34, 77, 21, 30, 7, 15, 11, 22, 45, 69, 93, 88, 56} 为例

很明显此时的最高位是十位

统计个位

按照开始索引放回原数组

统计十位

按照开始索引放回 此时到达最高位完成排序



基数排序时间复杂度及局限性

时间复杂度

基数排序的时间复杂度取决于当前最大元素的最高位,若最大元素的最高位大小为 digit,共有 n 个元素,我们对每一位数字都要进行 n 次遍历。故时间复杂度为 O(n×digit)

局限性

因为要计算每一位数字,所以基数排序只适用于元素都是整数的情况。🙄

基数排序核心代码

计算最高位

int GetMaxDigit(int *a, int n){
    //max_element 找到最大元素地址函数,记住是左闭右开哦
    int maxdata = *max_element(a, a + n);//找到最大元素计算其最大位数即可   
    int maxdigit = 0;                    //最大位数
    while(maxdata){
	maxdata /= 10;
	maxdigit++;
    }
    return maxdigit;
}

核心代码

//基数排序
void RadixSort(int *a, int n){
    int base = 1, digit = GetMaxDigit(a, n);
    int *tmp = new int[n];                 //临时数组  
    int *count = new int[10];              //统计数组,统计某一位数字相同的个数
    int *start = new int[10];              //起始索引数组,某一位数字相同数字的第一个的位置
    
    //最大位数为多少,就循环多少次
    while(digit--){
	memset(count, 0, 10 * sizeof(int));//每一次都全初始化为0
	//不可以写sizeof(count),这是指针的大小(若为64位,则为8),和普通数组的数组名不一样
        for(int i = 0; i < n; i++){
            int index = a[i] / base % 10;  //每一位数字
            count[index]++;
        }
         
        memset(start, 0, 10 * sizeof(int));//每一次都全初始化为0
        for(int i = 1; i < 10; i++)
            start[i] = count[i - 1] + start[i - 1];

        memset(tmp, 0, n * sizeof(int));   //每一次都全初始化为0
        for(int i = 0; i < n; i++){
            int index = a[i] / base % 10;
            tmp[start[index]++] = a[i];    //某一位相同的数字放到临时数组中合适的位置
        }

        memcpy(a, tmp, n * sizeof(int));   //复制tmp中的元素到a
        base *= 10;                        //比较下一位
    }      

    delete[] tmp;                          //释放空间
    delete[] count;
    delete[] start;                     
}


完整程序源代码

#include<iostream>
#include<algorithm>  //max_element
#include<cstring>    //memset, memcpy
#include<time.h>
using namespace std;


int GetMaxDigit(int *a, int n){
    //max_element 找到最大元素地址函数,记住是左闭右开哦
    int maxdata = *max_element(a, a + n);//找到最大元素计算其最大位数即可   
    int maxdigit = 0;                    //最大位数
    while(maxdata){
	maxdata /= 10;
	maxdigit++;
    }
    return maxdigit;
}


//基数排序
void RadixSort(int *a, int n){
    int base = 1, digit = GetMaxDigit(a, n);
    int *tmp = new int[n];                 //临时数组  
    int *count = new int[10];              //统计数组,统计某一位数字相同的个数
    int *start = new int[10];              //起始索引数组,某一位数字相同数字的第一个的位置
    
    //最大位数为多少,就循环多少次
    while(digit--){
	memset(count, 0, 10 * sizeof(int));//每一次都全初始化为0
	//不可以写sizeof(count),这是指针的大小(若为64位,则为8),和普通数组的数组名不一样
        for(int i = 0; i < n; i++){
            int index = a[i] / base % 10;  //每一位数字
            count[index]++;
        }
         
        memset(start, 0, 10 * sizeof(int));//每一次都全初始化为0
        for(int i = 1; i < 10; i++)
            start[i] = count[i - 1] + start[i - 1];

        memset(tmp, 0, n * sizeof(int));   //每一次都全初始化为0
        for(int i = 0; i < n; i++){
            int index = a[i] / base % 10;
            tmp[start[index]++] = a[i];    //某一位相同的数字放到临时数组中合适的位置
        }

        memcpy(a, tmp, n * sizeof(int));   //复制tmp中的元素到a
        base *= 10;                        //比较下一位
    }      

    delete[] tmp;                          //释放空间
    delete[] count;
    delete[] start;                     
}


void show(int *a, int n){
    for(int i = 0; i < n; i++)
	cout<<*(a + i)<<" ";
    cout<<endl;
}


main(){
    int a[50];
    srand((int)time(0));
    int k = 0;
    while(k < 50)
	a[k++] = rand() % 100 + 1;
    show(a, 50);

    RadixSort(a, 50);
	
    cout<<endl<<endl;
    show(a, 50);
}


程序运行结果图

posted @ 2022-11-21 12:38  MarisaMagic  阅读(2336)  评论(0编辑  收藏  举报