概述
一、归并排序
#include<iostream>
using namespace std;
int a[100], b[100];
/*
a原数组,b中间数组,前半段的起始,
m前半段的终止,也是两段的中点,e后半段的结束
*/
void merge(int a[], int l, int m, int e, int b[]) {
/*
- 假设按从小到大排序 -
现有两段已排序的序列 p1和p2分别指向这两个序列的开头
p指向中间数组的开头,中间数组是用来临时保存排序结果的,最后排序后要拷贝回到a中
p1 和 p2 分别从前往后扫,谁的小就插到b中,然后后移
*/
int p1 = l, p2 = m + 1, p = 0;
//两段序列同时往后扫 直到其中的一个序列扫完了
while (p1 <= m && p2 <= e) {
/*
如果p1指向的序列1中的元素小于p2指向的序列2中的元素,
那么将p1指向的元素添加到p指向的b的位置,然后p1和p后移;反之,对p2和p操作
*/
if (a[p1] < a[p2])
b[p++] = a[p1++];
else
b[p++] = a[p2++];
}
//两段有序数列的其中一段已经填充到b中,可能还剩下一段序列还没填充完
while (p1 <= m) {
b[p++] = a[p1++];
}
while (p2 <= e) {
b[p++] = a[p2++];
}
//将中间数组的结果拷贝回到原数组a中 归并步骤才算完成
for (int i = 0; i < e - l + 1; i++)
a[l + i] = b[i];
}
/*
归并排序,下标从l到r,a原数组,b中间数组
中心思想:对数组a从l到r进行排序,分为两个规模小的相同问题:
对前半部分从l到mid排序,对后半部分从mid+1到r排序,
最后对两段排序后的内容进行归并,使整个数组有序。按照这个规律不断递归下去。
*/
void mergesort(int a[], int l, int r, int b[]) {
/*
利用递归实现归并排序,不断地将数组分为前半和后半两部分,
当每部分的起始坐标等于结束坐标时,这一段内只有1个元素,不需要排序。
所以只有当起始坐标小于结束坐标的时候,即这一段内有2个及以上的元素时,才涉及到排序
*/
if (l < r) {
//取得中点
int mid = l + (r - l) / 2;
//对前半段递归排序
mergesort(a, l, mid, b);
//对后半段递归排序
mergesort(a, mid + 1, r, b);
//将排序后的两部分进行归并,使整体有序
merge(a, l, mid, r, b);
}
}
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++)
cin >> a[i];
mergesort(a, 0, n - 1, b);
for (int i = 0; i < n; i++)
cout << a[i] << " ";
cout << endl;
return 0;
}
二、利用归并排序的变形求逆序数
#include<iostream>
using namespace std;
int a[100], b[100];
//归并函数 这里排序是按从大到小
void merge(int a[], int l, int m, int e, int b[], int& count) {
int p1 = l, p2 = m + 1, p = 0;
while (p1 <= m && p2 <= e) {
//前面的大于后面的,产生了逆序数,
//逆序的对数等于当前p2到尾部e的所有数的个数
if (a[p1] > a[p2]) {
count += e - p2 + 1;
b[p++] = a[p1++];
}
//前面小于等于后面 没有逆序产生
else {
b[p++] = a[p2++];
}
}
//两个序列中的一个已经空了,一个巴掌拍不响,没有逆序了
while(p1 <= m) {
b[p++] = a[p1++];
}
while (p2 <= e) {
b[p++] = a[p2++];
}
//拷贝回到原数组中
for (int i = l; i <= e; i++)
a[i] = b[i - l];
}
//求数组a中,下标从l到r的总逆序对数
void mergesort_count(int a[], int l, int r, int b[], int& count) {
/*
先求前半部分的逆序数,再求后半部分的逆序数,
最后求这两部分之间产生的逆序数
*/
if (l < r) {
int mid = l + (r - l) / 2;
//求前半部分逆序数
mergesort_count(a, l, mid, b, count);
//求后半部分逆序数
mergesort_count(a, mid + 1, r, b, count);
//将两部分归并,并求两部分之间的逆序数
merge(a, l, mid, r, b, count);
}
}
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++)
cin >> a[i];
int count = 0;
mergesort_count(a, 0, n - 1, b, count);
cout << "逆序数的对数:" << count << endl;
for (int i = 0; i < n; i++)
cout << a[i] << " ";
cout << endl;
return 0;
}
最后
以上就是健忘大神为你收集整理的归并排序与求逆序数一、归并排序二、利用归并排序的变形求逆序数的全部内容,希望文章能够帮你解决归并排序与求逆序数一、归并排序二、利用归并排序的变形求逆序数所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复