【C++】逆序对计数问题
还是分治的思想,解决方法利用了归并排序。具体可以看一下这篇博客。
第三章:分治II - 不妨不妨,来日方长 - 博客园 (cnblogs.com)
C++代码如下,可以在VS直接运行。
#include<iostream> #include<vector> #include<algorithm> using namespace std; int sort_merge_recursive(vector<int>& data, int left, int right); int sort_crossing_merge_recursive(vector<int>& data, int left, int mid, int right); void merge(vector<int>& data, int left, int mid, int right); int main() { /* 使用归并排序的思路来解决逆序数对计数的问题:还是分治的思想,分解成小问题、解决小问题、合并问题解。 数组的分解跟归并排序里头的分解是一样的,都是二分,最后分到只剩单独一个元素。不同的是,归并排序直接 比较分解之后子数组的大小,在合并的时候按照从小到大或者从大到小的顺序往新的容器里放就行了。 逆序对问题,分解的步骤跟归并排序是一模一样的,在合并的过程中,两个子数组之间比较大小进行排序时, 恰好可以判断子数组逆序对,条件在代码中后面注释了,就加了那一句代码;跟数组的最大子数组和不同的是,那个 是求的左子数组、右子数组、跨中心数组中最大的一个,而求子数组逆序对,是把这三者相加。 */ vector<int> data = { 7,5,6,4}; //获取序列元素个数 int length = data.size(); int left = 0; int right = 3; int number=0; vector<int> result; number = sort_merge_recursive(data, left, right); cout << "逆序对的个数是:"<< number << endl; for (int i = 0; i < length; i++) { cout << data.at(i) << " "; } } int sort_merge_recursive(vector<int>& data, int left, int right) { if (left >= right) return 0; else { int mid = (left + right) >> 1; int s1, s2, s3, s_end; s1 = sort_merge_recursive(data, left, mid);//左子数组 s2 = sort_merge_recursive(data, mid + 1, right);//右子数组 s3 = sort_crossing_merge_recursive(data, left, mid, right);//跨中心数组 s_end = s1 + s2 + s3;//求三个的和 return s_end; } } int sort_crossing_merge_recursive(vector<int>& data, int left, int mid, int right) { int i = left; int j = mid + 1; int number=0; vector<int> temp; temp.resize(right - left + 1); int k = 0; while (i <= mid && j <= right) { if (data.at(i) > data.at(j)) { temp.at(k++) = data.at(j++); number += mid-i+1;//这里是相比于归并排序增加的部分 } else { temp.at(k++) = data.at(i++); } } while (i <= mid) { temp.at(k++) = data.at(i++); } while (j <= right) { temp.at(k++) = data.at(j++); } for (int n = 0; n < k; n++) { data.at(left++) = temp.at(n); } return number; }