持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第11天,点击查看活动详情
2022计算机考研408—数据结构—排序 手把手教学考研大纲范围内的排序 22考研大纲数据结构要求的是C/C++,笔者以前使用的都是Java,对于C++还很欠缺, 如有什么建议或者不足欢迎大佬评论区或者私信指出
Talk is cheap. Show me the code. 理论到处都有,代码加例题自己练习才能真的学会
二路归并排序
思路:
二路归并,就是把一个数组,先分开,然后在合并的过程中逐步排序
二路就是分开的时候每次分成两个,分成两种路
归并就是把他分开在合上
二路分割数组,一直把数组分割到一路只有一个数为止 然后再把他们两路合一路,两路合一路,在合路的过程中把无序的路合成有序的路,慢慢的合成后的路都为有序的路,大致原理如下图
分路没有什么说的,一分为,对半分即可
合路的时候,AB两个路合成C路,分别两个指针i,j,k对应着A,B,C数组的下标
循环AB两个数组,每次都比较A[i]与B[j] 取两个数组中对应值小的放到C[k]
然后k下标右移,i或者j小的下标右移,完全循环后,C==A+B的有序路
#include <iostream>
#include <vector>
using namespace std;
void mergeSort(vector<int> &num, int left, int right);
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);
}
mergeSort(num, 0, num.size() - 1); //调用自定义的排序方法
cout << "\n\n排序后" << endl;
for (int i = 0; i < num.size(); i++) {
cout << num[i] << " "; //输出
}
return 0;
}
void mergeSort(vector<int> &num, int left, int right) {
if (left == right) return; //如果左节点和右节点相等,说明就分到底了,一路只剩下一个元素
int m = (left + right) / 2; //左节点和右节点的中间节点,从中间节点分路,左面一路,右面一路
mergeSort(num, left, m); //先分左面->左面进入后还会从上面再来,接着分,一直分到一路只有一个元素
mergeSort(num, m + 1, right); //再分右面
//走到这里说明已经分完了,接下来就是合并
int temp [right - left + 1]; //定义一个数组,用来存两路合并后的有序数组
int l = left; //左路起始点下标
int r = m + 1; //右路起始点下标
int k = 0; //合路的起始点下标
while (l <= m && r <= right) { //每次放到时候比较对应的值,小的值放到前面,l要在左路的范围内,r要在右路的范围内
if (num[l] <= num[r]) { //谁小把谁放到合路
temp[k++] = num[l++];
} else {
temp[k++] = num[r++];
}
}
//下面两个while循环处理的是一路全部放进合路了,另一路没有完全放进,循环的作用就是把两路上面没放进去的全部放进去
while (l <= m) {
temp[k++] = num[l++];
}
while (r <= right) {
temp[k++] = num[r++];
}
//temp就是我们合路,然后我们把合好的路放回到num原数组中
for (int i = left, k = 0; i <= right; i++, k++) {
num[i] = temp[k];
}
//每次循环都把数组的变动输出出来
cout << "此次合并的是下标:" << left << "-" << right << "\n";
for (int j = 0; j < num.size(); j++) {
cout << num[j] << " ";
}
cout << "\n";
}
Acwing,这个题就是归并排序
788. 逆序对的数量
给定一个长度为 n 的整数数列,请你计算数列中的逆序对的数量。
逆序对的定义如下:对于数列的第 i 个和第 j 个元素,如果满足 i<j 且 a[i]>a[j],则其为一个逆序对;否则不是。
输入格式
第一行包含整数 n,表示数列的长度。
第二行包含 n 个整数,表示整个数列。
输出格式
输出一个整数,表示逆序对的个数。
数据范围
1≤n≤100000,
数列中的元素的取值范围 [1,109]。
输入样例:
6
2 3 4 5 6 1
输出样例:
5
#include <iostream>
#include <vector>
using namespace std;
void mergeSort(vector<int> &num, int left, int right);
int res = 0;
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);
}
mergeSort(num, 0, num.size() - 1); //调用自定义的排序方法
cout << res;
return 0;
}
void mergeSort(vector<int> &num, int left, int right) {
if (left == right) return; //如果左节点和右节点相等,说明就分到底了,一路只剩下一个元素
int m = (left + right) / 2; //左节点和右节点的中间节点,从中间节点分路,左面一路,右面一路
mergeSort(num, left, m); //先分左面->左面进入后还会从上面再来,接着分,一直分到一路只有一个元素
mergeSort(num, m + 1, right); //再分右面
//走到这里说明已经分完了,接下来就是合并
int temp [right - left + 1]; //定义一个数组,用来存两路合并后的有序数组
int l = left; //左路起始点下标
int r = m + 1; //右路起始点下标
int k = 0; //合路的起始点下标
while (l <= m && r <= right) { //每次放到时候比较对应的值,小的值放到前面,l要在左路的范围内,r要在右路的范围内
if (num[l] <= num[r]) { //谁小把谁放到合路
temp[k++] = num[l++];
} else {
temp[k++] = num[r++];
res += m - l + 1; //当前l大于r证明l到m的数都大于r
//归并就是一段一段的排好序的数组合并起来的
}
}
//下面两个while循环处理的是一路全部放进合路了,另一路没有完全放进,循环的作用就是把两路上面没放进去的全部放进去
while (l <= m) {
temp[k++] = num[l++];
}
while (r <= right) {
temp[k++] = num[r++];
}
//temp就是我们合路,然后我们把合好的路放回到num原数组中
for (int i = left, k = 0; i <= right; i++, k++) {
num[i] = temp[k];
}
}