4.统计逆序对个数问题 对于用户给定的一段正整数序列,逆序对就是序列中满足ai >aj且i<j 的有序对,注意序列中可能有重复数字。请基于分治思想设计一个算法编程输出给定的该段正整数序列中不同的逆序对的数量,并且逐一输出这些逆序对。用c语言编译
时间: 2024-10-03 15:04:41 浏览: 63
要基于分治思想解决这个问题,我们可以使用C语言编写一个递归的归并过程,同时计数逆序对。以下是实现这个算法的一个示例:
```c
#include <stdio.h>
// 函数声明
void merge(int arr[], int left[], int leftSize, int right[], int rightSize, int& count);
int countInversions(int arr[], int low, int high);
// 归并函数,合并两个已排序数组,并更新逆序对计数
void merge(int arr[], int left[], int leftSize, int right[], int rightSize, int& count) {
int i = 0, j = 0, k = 0;
while (i < leftSize && j < rightSize) {
if (left[i] <= right[j]) {
arr[k++] = left[i++];
} else {
arr[k++] = right[j];
// 如果当前元素大于左侧元素,则增加一个逆序对计数
count += leftSize - i;
i++;
}
}
// 复制剩余部分(如果有的话)
while (i < leftSize) {
arr[k++] = left[i++];
}
while (j < rightSize) {
arr[k++] = right[j++];
}
}
// 使用分治策略计算逆序对数量
int countInversions(int arr[], int low, int high) {
if (low == high) { // 基线条件:只有一个元素,无逆序对
return 0;
}
int mid = (low + high) / 2;
int leftCount = countInversions(arr, low, mid); // 左半部分
int rightCount = countInversions(arr, mid + 1, high); // 右半部分
int inversions = leftCount + rightCount; // 合并两个子数组的逆序对
// 合并左半部分和右半部分,同时更新逆序对计数
int mergedCount;
merge(arr, arr, low, arr + mid + 1, high - mid, mergedCount);
return inversions + mergedCount;
}
int main() {
int arr[] = {9, 7, 5, 11, 12, 2, 14, 3, 10, 6};
int n = sizeof(arr) / sizeof(arr[0]);
int count = countInversions(arr, 0, n - 1);
printf("Number of unique inversion pairs: %d\n", count);
// 输出每个逆序对
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
if (arr[i] > arr[j] && i != j) {
printf("(%d, %d)\n", arr[i], arr[j]);
}
}
}
return 0;
}
```
在这个程序中,`countInversions` 函数通过递归地分割数组并调用自身来计算逆序对数量,而 `merge` 函数则合并两个已排序的部分,并在合并过程中更新逆序对计数。
阅读全文