Divide and Conquer&Count Inversions归并排序求逆序数

本文介绍了一个使用C++处理包含10万个整数的大数据集的程序案例,重点介绍了如何解决数据溢出问题,以及使用Divide and Conquer策略进行排序和计数逆序对的过程。
Divide and Conquer

The attached le Q8.txt contains 100,000 integers between 1 and 100,000 (each row has a single integer), the order of these integers is random and no integer is repeated.

刚写程序是用的visual C++,遇到了数据溢出的问题,发现long long在visual C++中不能使用,换成double之后可以,中间其实还试过了__int64,也是不可以,不过总算double可以了。Visual Studio中可以使用long long,这是我第一次使用C++,所以遇到了很多问题,仅写此篇留念。

写代码过程中,由于函数定义时忘记更改数据类型了,只修改了函数内部的,所以一开始怎么都不对,还好后面发现了,虽然用了很多的时间,但是我相信,以后一定不会再犯此类问题了,即便有也能很快发现,总之,很惭愧。

此代码中包括第一次使用的C++读取文件并放入数组。


#include<iostream>
#include <fstream>
#include<iomanip> 
#define n 100000
int arr[100000];
using namespace std;


double MergeAndCount(int ll,int lr,int rl,int rr)
{
double count=0;
int i,j=rl,k=0;
int *tmp;
tmp = new int[rr-ll+1];
for(i=ll;i<=lr;i++)
{
while(j<=rr && arr[i]>arr[j])
tmp[k++] = arr[j++];
count += j-rl;
tmp[k++] = arr[i];
}
while(j<=rr)
tmp[k++] = arr[j++];
memcpy(arr+ll, tmp, sizeof(int)*(rr-ll+1));
delete tmp;
return count;
}


double SortAndCount(int i,int j)
{


if(i<j)
{
int mid = i+((j-i)/2);
double r= SortAndCount(i,mid);
double l= SortAndCount(mid+1,j);
double m = MergeAndCount(i,mid,mid+1,j);
return r+l+m;
}
else
return 0;
}



int main()
{
ifstream in("Q8.txt", ios::in);
char buf[10];
if(!in.is_open())
{
cout<<"Error opening file!";
exit(1);
}
int i=0;
while(!in.eof())
{
in.getline(buf,10);     //int line;
arr[i++] = atoi(buf);    //in>>line; data[k]=line;
}
double number = SortAndCount(0,n-1);
cout<<"The number of invertions is "<<setprecision(20)<<number<<'.'<<endl;
return 0;
system("pause");
}


使用归并排序算法计算逆序对数量,可利用归并排序的分治思想,在排序过程中统计逆序对。归并排序本质是分治思想的体现,将大问题拆分,分别解小问题,再合并结果得到最终解 [^4]。 归并排序的三个核心步骤如下 [^3]: 1. **分(Divide)**:拆分数组为子区间。不断将无序数列拆分成子序列,直至子序列只剩一个或两个元素。 2. **治(Conquer)**:递归计算子区间逆序对。对拆分后的子区间递归地进行逆序对统计和排序。 3. **合(Merge)**:合并有序子区间,统计跨区逆序对。在合并两个有序子区间时,若左边子区间的元素大于右边子区间的元素,说明存在逆序对,且逆序对的数量为左边子区间剩余元素的数量。 以下是使用 Python 实现的代码示例: ```python def merge_sort_and_count(arr): if len(arr) <= 1: return arr, 0 mid = len(arr) // 2 # 递归拆分 left, left_count = merge_sort_and_count(arr[:mid]) right, right_count = merge_sort_and_count(arr[mid:]) # 合并子区间并统计跨区逆序对 merged, cross_count = merge_and_count(left, right) return merged, left_count + right_count + cross_count def merge_and_count(left, right): merged = [] count = 0 i, j = 0, 0 while i < len(left) and j < len(right): if left[i] <= right[j]: merged.append(left[i]) i += 1 else: # 出现逆序对 merged.append(right[j]) j += 1 # 统计逆序对数量 count += len(left) - i # 处理剩余元素 merged.extend(left[i:]) merged.extend(right[j:]) return merged, count # 测试 arr = [7, 5, 6, 4] sorted_arr, inverse_count = merge_sort_and_count(arr) print(f"排序后的数组: {sorted_arr}") print(f"逆序对的数量: {inverse_count}") ``` 该算法的时间复杂度是 $O(n log n)$,其中 $n$ 是数组的大小。这比直接暴力计算所有逆序对数量的 $O(n^2)$ 方法要高效得多 [^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值