持续创作,加速成长!这是我参与「掘金日新计划 · 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] << " ";
}
}
}