定义:对于一个给定的数列,如果有
i<j
,且Ai>Aj
,则称(i,j)
为一逆序对.
要解决的问题是,给出一个数列,求出这个数列包含多少个逆序对。
例如,数组(3,1,4,5,2)
的“逆序对”有<3,1>,<3,2><4,2><5,2>
,共4个。
解题思路
使用归并排序可以用O(nlogn)
的时间解决统计逆序对个数的问题 .
逆序对数实质就是插入排序过程中要移动元素的次数。
归并的时候 前后两个序列都是有序的,可以把这个过程想象成插入排序,将第二个序列的内容插入到第一个有序的序列中。那么插入第二个序列中的元素时,要移动的元素的位数即第一个序列中还未插入到新序列中的元素的个数。即:distance(iL,mid).
实现代码
#include <iostream>
using namespace std;
int merge(int *num, int left, int mid, int right)
{
int *temp = new int[right - left + 1];
int i = 0;
int j = left, k = mid + 1;
int count = 0;
while (j <= mid && k <= right)
{
if (num[j] <= num[k])
{
temp[i++] = num[j++];
}
else
{
temp[i++] = num[k++];
count += mid - j + 1;
}
}
while (j <= mid)
{
temp[i++] = num[j++];
}
while (k <= right)
{
temp[i++] = num[k++];
}
for (int m = 0; m <= right - left; m++)
{
num[left + m] = temp[m];
}
delete [] temp;
return count;
}
//int merge(int *num, int left, int mid, int right)
//{
// int len1 = mid - left + 1;
// int len2 = right - mid;
// int *L = new int[len1];
// int *R = new int[len2];
// for (int i = 0; i < len1; i++)
// {
// L[i] = num[left + i];
// }
// for (int i = 0; i < len2; i++)
// {
// R[i] = num[mid + i + 1];
// }
//
// int i = 0;
// int j = 0;
// int k = left;
// int count = 0;
// while (i < len1 && j < len2)
// {
// if (L[i] < R[j])
// {
// num[k++] = L[i++];
// }
// else
// {
// num[k++] = R[j++];
// count += mid - (left + i) + 1;
// }
// }
// while (i < len1)
// {
// num[k++] = L[i++];
// }
// while (j < len2)
// {
// num[k++] = R[j++];
// }
//
// return count;
//}
int mergeSort(int *num, int left, int right)
{
if (left < right)
{
int mid = (left + right) / 2;
int n1 = mergeSort(num, left, mid);
int n2 = mergeSort(num, mid + 1, right);
int n3 = merge(num, left, mid, right);
return n1 + n2 + n3;
}
return 0;
}
int main()
{
int num[] = {3,1,4,5,2};
//int num[] = {1, -3, 2, -5, 4, 0};
cout<<mergeSort(num, 0, sizeof(num)/sizeof(num[0])-1)<<endl;
for (int i = 0; i < sizeof(num)/sizeof(num[0]); i++)
{
cout<<num[i]<<" ";
}
}