22计算机408考研—数据结构—基数排序和计数排序

186 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第12天,点击查看活动详情

2022计算机考研408—数据结构—排序 手把手教学考研大纲范围内的排序 22考研大纲数据结构要求的是C/C++,笔者以前使用的都是Java,对于C++还很欠缺, 如有什么建议或者不足欢迎大佬评论区或者私信指出

Talk is cheap. Show me the code. 理论到处都有,代码加例题自己练习才能真的学会

基数排序

说基数排序之前,先大概说一下计数排序

计数排序

计数排序就是把元素的值当作下标使用,数量用那个下标对应的值记录 例如int num[]={5,2,1,4,3,2,1,2,6,4,1,2,5,2} 这样的数组我们就用计数排序 count的长度是上面数组的最大值-最小值+1或者最大值-最小值+1 循环上面的数组 count[num[i]]++; 到时候判断这个值存不存在,直接判断count[值]是否大于0 显而易见,计数排序的缺点就是如果数组中最大值很大,那么这个效率会很低

leetcode 计数排序例题
1122. 数组的相对排序
给你两个数组,arr1 和 arr2,

arr2 中的元素各不相同
arr2 中的每个元素都出现在 arr1 中
对 arr1 中的元素进行排序,使 arr1 中项的相对顺序和 arr2 中的相对顺序相同。未在 arr2 中出现过的元素需要按照升序放在 arr1 的末尾。

 

示例:

输入:arr1 = [2,3,1,3,2,4,6,7,9,2,19], arr2 = [2,1,4,3,9,6]
输出:[2,2,2,1,4,3,3,9,6,7,19]
 

提示:

1 <= arr1.length, arr2.length <= 1000
0 <= arr1[i], arr2[i] <= 1000
arr2 中的元素 arr2[i] 各不相同
arr2 中的每个元素 arr2[i] 都出现在 arr1 中


class Solution {
    //arr2的数在arr1中一定出现
    //arr1的数不一定在arr2中有
    //arr2在arr1中出现过的数,按照arr2的相对顺序排列,arr1中剩下的数按照升序排在后面
public:
    vector<int> relativeSortArray(vector<int>& arr1, vector<int>& arr2) {
        int upper = *max_element(arr1.begin(), arr1.end());
        vector<int> count(upper + 1);
        //arr1中的数计数放到count
        for (int x: arr1) {
            ++count[x];
        }
        vector<int> ans;
        //如果arr1出现的数,arr2也出现了就输出
        //这样就是按照arr2的相对顺序输出
        for (int x: arr2) {
            for (int i = 0; i < count[x]; ++i) {
                ans.push_back(x);
            }
            //arr2出现的数字,就添加到ans里面,
            //添加过就把这个数字清零了,
            count[x] = 0;
        }
        //把剩下的未在arr2中出现的按照升序输出
        for (int x = 0; x <= upper; ++x) {
            for (int i = 0; i < count[x]; ++i) {
                ans.push_back(x);
            }
        }
        return ans;
    }
};



再回来说基数排序 基数排序也是大概这个意思,不过不是直接把值当作下标,而是把值的每一位当作下标排序 这个也需要保存一下最大值,因为要判断最高有多少位。 先把个位放进去,排序,再把十位放进去排序,然后……

把个位放进去后,就按照个位排序好了,把数取出,记得按照顺序取出, 然后十位放进去排序,把数按顺序取出…… 思路大概就是这样 顺序放入顺序取出,在进行下一位的排序 PS: 如果是Java的话,直接用一个ArrayList[] temp; 这种数组就可以

在这里插入图片描述 PS:当来的图片

#include <iostream>
#include <vector>

using namespace std;

void radixSort(vector<int> &num);

int main() {
    int n;    //n为将要输入的数组长度
    cin >> n;   //输入n   cin方法需要上面使用std
    vector<int> num;    //定义vector  记得上面导入vector
    int temp;   //temp为输入vector时的中间变量
    for (int i = 0; i < n; i++) {
        cin >> temp;            //输入
        num.push_back(temp);
    }
    radixSort(num);    //调用自定义的排序方法
    cout << "\n\n排序后" << endl;
    for (int i = 0; i < num.size(); i++) {
        cout << num[i] << " ";     //输出
    }
    return 0;
}

void radixSort(vector<int> &num) {
    int max = -1;
    for (int i = 0; i < num.size(); i++) {
        max = max < num[i] ? num[i] : max;
    }
    int temp[num.size()];
    int count[10] = {0};
    for (int i = 0; i < num.size(); i++) {
        temp[i] = 0;                                    //初始化temp赋值0
    }

    for (int places = 1; places <= max; places *= 10) {     //基数排序就是按照位数进行排序,所以循环的次数就是数字位数

        for (int i = 0; i < num.size(); i++) {
            count[(num[i] / places) % 10]++;                  // 记录一下当前位上,各个数字的个数
        }                                                   //count[3]如果是5 就代表的个位为3的数是5个
        //当前位置上各个数字的个数确定了,我们就可以确定当前位某个数字的范围了
        //count[0] = 3, count[1] = 4, count[2] = 7, count[3] = 2……
        //当前位上为0的数在此次排序后的位置为数组1-3,当前位为1的数在此次位置为4-7,当前位为2的数的范围8-14……
        //也就是前面的和,加起来,得出的count[i] 就是当前位为i的数的范围的右边界
        for (int i = 1; i < 10; i++) {
            count[i] = count[i - 1] + count[i];
        }
        //因为我们上面count[i]得出的是当前位为i的时候的右边界,所以排序后的数组我们也应该从右面放
        //如果这里我们从左面开始放就会把放入的顺序弄反,我们已知右边界,然后把数字从右开始放顺序是正的
        //当然我们上一步也可以求每段范围的左边界,如果求得是左边界就可以从左放
        for (int i = num.size() - 1; i >= 0; i--) {
            int k = (num[i] / places) % 10;   //count[k]就是当前位为k的值的右边界
            temp[count[k] - 1] = num[i];    //这里的右边界我们用的是位置,下标要记得-1
            count[k]--;                     //当前位为k的数放进去后,count[k]要-1  因为已经放进去一个数了,右边界左移一位
        }
        //当所有的都循环完以后,count[i]代表的是当前位为i的数字范围的左边界
        for (int i = 0; i < 10; i++) {
            count[i] = 0;
        }
        //把此次排序的数组放到num中
        for (int i = 0; i < num.size(); i++) {
            num[i] = temp[i];
        }
        //输出展示此次排序后的数组
        cout << "\n哪一位是1,此次排序就是排的哪一位  " << places << "\n";
        for (int i = 0; i < num.size(); i++) {
            cout << num[i] << " ";
        }

    }

}

在这里插入图片描述