归并排序采用了分治和递归的思想
归并排序入口
void merge_sort(int arr[],int n)
{
//分配一个辅助数组
int *tempArr=(int*)malloc(n*sizeof(int));
if(tempArr)//辅助函数分配成功
{
msort(arr,tempArr,0,n-1);
free(tempArr);
}
else
printf("error:failed to allocate memory");
}
归并排序
void msort(int arr[],int tempArr[],int left,int right)
{
//如果只有一个元素,那么就不需要继续划分
//只有一个元素的区域,本身就是有序的,只需要被归并即可
if(left<right)
{
int mid=(left+right)/2;//找中间点
msort(arr,tempArr,left,mid);//递归划分左半区域
msort(arr,tempArr,mid+1,right);//递归划分右半区域
merge(arr,tempArr,left,mid,right);//合并已排序的部分
}
}
合并
void merge(int arr[],int tempArr[],int left,int mid,int right)
{
//标记左半区第一个未排序的元素
int l_pos=left;
//标记右半区第一个未排序的元素
int r_pos=mid+1;
//临时数组和下标
int pos=left;
//合并
while(l_pos<=mid&&r_pos<=right)
{
if(arr[l_pos]<arr[r_pos])//左半区第一个剩余元素更小
tempArr[pos++]=arr[l_pos++];
else//右半区第一个剩余元素更小
tempArr[pos++]=arr[r_pos++];
}
//合并左半区剩余元素
while(l_pos<=mid)
tempArr[pos++]=arr[l_pos++];
//合并右半区剩余元素
while(r_pos<=right)
tempArr[pos++]=arr[r_pos++];
//把临时数组中合并的元素复制回原来的数组
while(left<=right)
{
arr[left]=tempArr[left];
left++;
}
}
模板
#include<bits/stdc++.h>
using namespace std;
//辅助函数,打印数组
void print_arr(int arr[],int n)
{
for(int i=0;i<n;i++)
{
printf("%d ",arr[i]);
}
putchar('\n');
}
//合并
void merge(int arr[],int tempArr[],int left,int mid,int right)
{
//标记左半区第一个未排序的元素
int l_pos=left;
//标记右半区第一个未排序的元素
int r_pos=mid+1;
//临时数组和下标
int pos=left;
//合并
while(l_pos<=mid&&r_pos<=right)
{
if(arr[l_pos]<arr[r_pos])//左半区第一个剩余元素更小
tempArr[pos++]=arr[l_pos++];
else//右半区第一个剩余元素更小
tempArr[pos++]=arr[r_pos++];
}
//合并左半区剩余元素
while(l_pos<=mid)
tempArr[pos++]=arr[l_pos++];
//合并右半区剩余元素
while(r_pos<=right)
tempArr[pos++]=arr[r_pos++];
//把临时数组中合并的元素复制回原来的数组
while(left<=right)
{
arr[left]=tempArr[left];
left++;
}
}
//归并排序
void msort(int arr[],int tempArr[],int left,int right)
{
//如果只有一个元素,那么就不需要继续划分
//只有一个元素的区域,本身就是有序的,只需要被归并即可
if(left<right)
{
int mid=(left+right)/2;//找中间点
msort(arr,tempArr,left,mid);//递归划分左半区域
msort(arr,tempArr,mid+1,right);//递归划分右半区域
merge(arr,tempArr,left,mid,right);//合并已排序的部分
}
}
//归并排序入口
void merge_sort(int arr[],int n)
{
//分配一个辅助数组
int *tempArr=(int*)malloc(n*sizeof(int));
if(tempArr)//辅助函数分配成功
{
msort(arr,tempArr,0,n-1);
free(tempArr);
}
else
printf("error:failed to allocate memory");
}
int main(int argc,char const*argv[])
{
int arr[]={9,5,7,3,12,4,2,1};
int n=8;
print_arr(arr,n);
merge_sort(arr,n);
print_arr(arr,n);
return 0;
}
题目描述
猫猫 TOM 和小老鼠 JERRY 最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。
最近,TOM 老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中 ai>aj 且 i<j 的有序对。知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目。注意序列中可能有重复数字。
Update:数据已加强。
输入格式
第一行,一个数 n,表示序列中有 n个数。
第二行 n 个数,表示给定的序列。序列中每个数字不超过 10^9。
输出格式
输出序列中逆序对的数目。
输入输出样例
输入 #1复制
6 5 4 2 6 3 1
输出 #1复制
11
说明/提示
对于 25% 的数据,n≤2500
对于 50% 的数据,n≤4×10^4。
对于所有数据,n≤5×10^5
请使用较快的输入输出
应该不会 𝑂(𝑛^2) 过 50 万吧 by chen_zhe
#include<bits/stdc++.h>
using namespace std;
int n,a[10000010],b[10000010];
long long s;
void msort(int left,int right)
{
if(left==right)
return ;
int mid=(left+right)/2;
int l_pos=left;
int r_pos=mid+1;
int pos=left;
msort(left,mid);//递归划分左半区域
msort(mid+1,right);//递归划分右半区域
while(l_pos<=mid&&r_pos<=right)
{
if(a[l_pos]<=a[r_pos])//左半区第一个剩余元素更小
b[pos++]=a[l_pos++];
else//右半区第一个剩余元素更小
{
b[pos++]=a[r_pos++];
s+=mid-l_pos+1;
}
}
//合并左半区剩余元素
while(l_pos<=mid)
b[pos++]=a[l_pos++];
//合并右半区剩余元素
while(r_pos<=right)
b[pos++]=a[r_pos++];
for(int i=left;i<=right;i++)
a[i]=b[i];
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
msort(1,n);
printf("%lld",s);
return 0;
}