目录
1.题目概述:
给定一个数组
, 若 (ai>aj)且(i<j) 就为一个逆序对。 例如数(3,1,4,5,2)的逆序对为4个,分别是<3,1>,<3,2>,<4,2>、<5,2>。 编写一个实验程序,采用分治法求序列A中逆序对的个数,即逆序数。
2.题目解析:
问题思路:利用分治法进行求解
1.将数组分成两半,分别求出左半边的逆序数和右半边的逆序数
2.再算有多少逆序是由左半边取一个数和右半边取一个数构成
实际上就是归并排序的改造,即对此排列进行归并排序,边排序边计算它的逆序数
问题关键:设左半边和右半边都是从小到大有序的(此时进行归并),从左到右依次扫描,比较两个各取一个数的大小,如果左边第一个数比右边第一个数大,那么左边排列的其他数字也可以和右边第一个数构成逆序数,以此类推。
3.题目代码:
#include <stdio.h>
int sum = 0;
int MergeSort(int SR[], int s, int m, int n)
{
int j, i = s;
int b[n - i + 1];
int k, l = s, temp = 0, count = 0;
for (j = m, k = 0; i < m && j <= n;)
{
if (SR[i] > SR[j])
{
b[k++] = SR[j++];
temp++;
}
if (SR[i] <= SR[j] || j == n + 1)
{
count += temp * (m - i);
b[k++] = SR[i++];
temp = 0;
}
}
for (; i < m; k++)
b[k] = SR[i++];
for (; j <= n; k++)
b[k] = SR[j++];
for (k = 0; l <= n; l++, k++)
SR[l] = b[k];
return count;
}
void Sort(int SR[], int s, int t)
{
int m;
if (s < t)
{
m = (s + t) / 2;
Sort(SR, s, m);
Sort(SR, m + 1, t);
sum += MergeSort(SR, s, m + 1, t);
}
}
int main()
{
int n, i;
printf("A数组中数的个数是:");
scanf("%d", &n);
int a[n], b[n];
printf("A数组序列为:\n");
for (i = 0; i < n; i++)
{
scanf("%d", &a[i]);
b[i] = a[i];
}
Sort(a, 0, n - 1);
printf("序列A中逆序对为:%d\n", sum);
return 0;
}
4.样例展示:
5.题目总结:
对于该问题,我将序列分成子序列,并分别求解各个子序列中存在的逆序对数量,然后将结果合并,即可求出整个序列的逆序对,这也就是分治法,在这个过程中,排序并且找到逆序对同时进行计数,根据这一特点我想到了归并排序,因此,我在归并排序中增加计数器,解决了这个问题,是这个问题的难点。这是对于该问题的简要分析。