编程语言
首页 > 编程语言> > 基数排序算法——C++

基数排序算法——C++

作者:互联网

基数排序的主要思想是选择多位基数依次进行排序,利用每次排序后还是相对有序,也就是稳定排序性质,依次比较完所有基数后,完成整个数组排序。其中,每次比较基数比如对整数进行排序时可以采用计数排序,因为整数位数有限并且每个位上的数值范围是0-9,所以最适合采用优化后计数排序对每个基数进行排序。

时间复杂度为 O(n + m),空间复杂度为 O(n + m),其中n为数组个数,m为数组最大值位数。

基数排序跟数组规模有关,假如规模很大的话,不一定比快速排序更优,故需要就具体数据模块进行分析。

一、代码实现分析

下面举一个具体例子。

假如要对数组arr={ 2,0,1,6,8,10,5,99,87,333,2,0,1 }排序,则最大值为333,这个最大值有三位数,故只需要进行三次大循环对所有原始数组arr进行个位数,十位数,百位数分别进行计数排序即可完成整个排序。

为什么分别对个位、十位、百位数进行排序后,最后整个数组arr是有序的呢?这个就是刚刚说的计数排序是稳定排序算法,经过一轮个位数排序后,整个数组消除了个位数的逆序对;此时只剩下十位和百位数的逆序对,故只需要分别对十位数和百位数进行计数排序即可消除整个数组arr的逆序对完成排序。

1.1具体实现步骤

a1 先找出原始数组arr最大值,求出最大值有多少个位数digitLen

int max = *std::max_element(nums.begin(), nums.end()); // 找出数组最大值
int digitLen{ 0 };
int div{ 1 };
while (max)
{
    ++digitLen; // 计算最大值位数
    max /= 10;
}

a2 对原始数组每个位(个位、十位、百位、千位、...)分别进行计数排序,即digitLen次最外层循环

for (int i = 0; i < digitLen; i++) // 从最低位开始依次遍历所有基数
{
    // 进行计数排序
}

a3 每个位计数排序完成后,将结果复制到原始数组arr中,并且清除原始计数countArr数组后,再进行下一个位的计数排序,直到完成所有位的排序,则完成整个数组排序

for (int i = 0; i < digitLen; i++) // 从最低位开始依次遍历所有基数
{
    vector<int> countArr(10, 0);
    vector<int> result(nums.size());
    for (auto& it : nums) // 统计每个基数个数
        countArr[it / div % 10]++;
    for (int i = 1; i < countArr.size(); ++i) // 变化计数数组
        countArr[i] += countArr[i - 1];
    for (int i = nums.size() - 1; i >= 0; --i) // 逆序遍历原始数组nums,放入结果数组进行排序
    {
        result[countArr[nums[i] / div % 10] - 1] = nums[i];
        countArr[nums[i] / div % 10]--;
    }
    nums = result; // 赋值到原始数组nums后,进行下一个位遍历        
    div *= 10;
}

1.2完整代码

Sorts.h

#pragma once

#include <iostream>
#include <vector>

using namespace std;

struct Sorts {    
    void radix(vector<int>& nums);    
    void print(vector<int>& nums);
};

Sorts.cpp

#include "Sorts.h"
#include <algorithm>

void Sorts::radix(vector<int>& nums)
{
    int max = *std::max_element(nums.begin(), nums.end()); // 找出数组最大值
    int digitLen{ 0 };
    int div{ 1 };
    while (max)
    {
        ++digitLen; // 计算最大值位数
        max /= 10;
    }
    for (int i = 0; i < digitLen; i++) // 从最低位开始依次遍历所有基数
    {
        vector<int> countArr(10, 0);
        vector<int> result(nums.size());
        for (auto& it : nums) // 统计每个基数个数
            countArr[it / div % 10]++;        
        for (int i = 1; i < countArr.size(); ++i) // 变化计数数组
            countArr[i] += countArr[i - 1];
        for (int i = nums.size() - 1; i >= 0; --i) // 逆序遍历原始数组nums,放入结果数组进行排序
        {            
            result[countArr[ nums[i] / div % 10] - 1 ] = nums[i];
            countArr[nums[i] / div % 10]--;
        }
        nums = result; // 赋值到原始数组nums后,进行下一个位遍历        
        div *= 10;
    }
}

void Sorts::print(vector<int>& nums)
{
    for (const auto& it : nums)
        cout << it << ",";
    cout << endl;
}

main.cpp

 #include <vector>
#include "Sorts.h"

using namespace std;

int main()
{
    vector<int> nums = { 2,0,1,6,8,10,5,99,87,333,2,0,1 };
    Sorts sorts;
    sorts.print(nums);
    sorts.radix(nums);
    sorts.print(nums);
   
	return 1;
}

1.3输出结果

1.4总结

从上面代码可以看出,基数排序其本质就是对每个基数依次进行排序,并且排序前后的排序算法是稳定的,除了每次基数排序采用计数排序算法外,还可以采用其它稳定排序算法,比如插入排序,堆排序等,但常用的还是基数排序中嵌入计数排序。

标签:10,nums,int,countArr,C++,算法,基数排序,数组,排序
来源: https://blog.csdn.net/naibozhuan3744/article/details/121569687