知识点:归并排序法
C语言最终代码
#include <stdio.h>
#define MAXN 10001
// 合并两个有序数组并统计逆序数
int merge(int arr[], int temp[], int left, int mid, int right) {
int i = left;
int j = mid + 1;
int k = left;
int inversion_count = 0;
while (i <= mid && j <= right) {
if (arr[i] <= arr[j]) {
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
// 当arr[i] > arr[j]时,arr[i...mid]都与arr[j]构成逆序对
inversion_count += (mid - i + 1);
}
}
while (i <= mid) {
temp[k++] = arr[i++];
}
while (j <= right) {
temp[k++] = arr[j++];
}
for (i = left; i <= right; i++) {
arr[i] = temp[i];
}
return inversion_count;
}
// 归并排序主函数并统计逆序数
int mergeSort(int arr[], int temp[], int left, int right) {
int inversion_count = 0;
if (left < right) {
int mid = (left + right) / 2;
// 递归计算左子数组逆序数
inversion_count += mergeSort(arr, temp, left, mid);
// 递归计算右子数组逆序数
inversion_count += mergeSort(arr, temp, mid + 1, right);
// 合并两个子数组并统计逆序数
inversion_count += merge(arr, temp, left, mid, right);
}
return inversion_count;
}
int main() {
int arr[MAXN];
int temp[MAXN];
int n;
while (1) {
scanf("%d", &n);
if (n == 0) break;
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
int inversion_count = mergeSort(arr, temp, 0, n - 1);
printf("%d\n", inversion_count);
}
return 0;
}
代码说明:
merge
函数:负责合并两个有序子数组,在合并过程中统计逆序数。当左子数组元素大于右子数组元素时,左子数组该元素及后面剩余元素都与右子数组当前元素构成逆序对,据此统计逆序数。合并完成后将结果复制回原数组。mergeSort
函数:递归地对数组进行分治,先分别计算左右子数组的逆序数,再通过调用merge
函数合并子数组并统计合并过程中的逆序数,最终返回整个数组的逆序数。main
函数:循环读取序列长度n
和序列元素,调用mergeSort
函数计算逆序数并输出,当n
为0
时结束程序。
初始的暴力求解
#include<stdio.h>
int arr[10001]={0};
int main()
{
int n,i,cnt,j,max;
while(1)
{
cnt=0;
scanf("%d",&n);
if(n==0) break;
scanf("%d",&arr[1]);
max=arr[1];
for(i=2;i<=n;i++)
{
scanf("%d",&arr[i]);
// printf("%d-----------%d\n",i,max);
if(arr[i]>=max) {max=arr[i];continue;}
for(j=i-1;j>0;j--)
{
if(arr[i]<arr[j]) cnt++;
}
}
// for(i=1;i<=n;i++)
// {
// printf("%d----%d\n",i,arr[i]);
// }
printf("%d\n",cnt);
}
return 0;
}
时间复杂度为 O(n2) ,当 n 达到题目允许的最大值 10000 时,计算量会非常大。在 1 秒的时间限制下,很可能超时,难以满足时间限制条件 。
相比之下,归并排序法时间复杂度为 O(nlogn) ,更有机会满足该时间限制要求。