//归并排序
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <algorithm>
#define N 10000000
using namespace std;
int arr[N] = {7, 1, 4, 2, 8, 3, 6, 5};
int tmp[N];
//拷贝arr数组到tmp数组里
void Arr_cpy(int arr[],int length,int l){
for(int k=0;k<length;k++) tmp[k]=arr[k+l];
}
//归并
void merge(int arr[],int l,int mid,int r){
Arr_cpy(arr,r-l+1,l);
int i=l,j=mid+1;
for(int k=l;k<=r;k++){
if(i>mid) {
arr[k]=tmp[j-l];j++;
}
else if(j>r){
arr[k]=tmp[i-l];i++;
}
else if(tmp[i-l]<tmp[j-l]){
arr[k]=tmp[i-l];i++;
}
else {
arr[k]=tmp[j-l];j++;
}
}
}
//归并排序算法
void MergeSort1(int arr[],int l,int r){
if(l>=r) return;
int mid=l+(r-l)/2;
MergeSort1(arr,l,mid);
MergeSort1(arr,mid+1,r);
if(arr[mid]>arr[mid+1])
merge(arr,l,mid,r);
}
//插入排序
void InsertionSort(int arr[],int l, int r){
for(int i=r-1;i>=l;i--){
int t=arr[i];
int j;
for(j=i;j+1<=r && t>arr[j+1];j++)
arr[j]=arr[j+1];
arr[j]=t;
}
}
//用插入排序优化的归并排序算法
void MergeSort2(int arr[],int l,int r){
if(r-l<=15){
InsertionSort(arr,l,r);
return;
}
int mid=l+(r-l)/2;
MergeSort2(arr,l,mid);
MergeSort2(arr,mid+1,r);
if(arr[mid]>arr[mid+1])
merge(arr,l,mid,r);
}
//arr数组打印函数
void prin(){
for(auto i:arr) cout<<i<<" ";
cout<<endl;
}
//打印归并排序递归调用过程
void MergeSort_prin(int arr[],int l,int r,int depth){
for(int i=0;i<depth;i++) cout<<"--";
cout<<"mergesort arr["<<l<<","<<r<<"]"<<endl;
if(l>=r) return;
int mid=l+(r-l)/2;
MergeSort_prin(arr,l,mid,depth+1);
MergeSort_prin(arr,mid+1,r,depth+1);
for(int i=0;i<depth;i++) cout<<"--";
cout<<"merge arr["<<l<<","<<mid<<"] and arr["<<mid+1<<","<<r<<"]"<<endl;
merge(arr,l,mid,r);
for(int i=0;i<depth;i++) cout<<"--";
cout<<"after mergesort arr["<<l<<","<<r<<"]:";
prin();
}
//自底向上的归并排序
void MergeSort3(int arr[],int l,int r){
Arr_cpy(arr,r-l+1,l);
int n=r-l+1;
// 使用插入排序优化
// 遍历一遍,对所有 arr[i, i + 15] 的区间,使用插入排序法
for(int i=0;i<n;i+=16)
InsertionSort(arr,i,min(n-1,i+15));
// 遍历合并的区间长度
// 注意,sz 从 16 开始
for(int sz=16;sz<n;sz+=sz){
// 遍历合并的两个区间的起始位置 i
// 合并 [i, i + sz - 1] 和 [i + sz, i + sz + sz - 1]
for(int i=0;i+sz<n;i+=sz+sz)
if(arr[i+sz-1]>arr[i+sz])
merge(arr,i,i+sz-1,min(i+sz+sz-1,n-1));
}
}
//测试输出归并排序递归调用过程
void TestMergeSort_prin(){
clock_t startTime,endTime;
srand(time(NULL));
cout<<"n="<<N<<":"<<endl;;
for(int i=0;i<N;i++) arr[i]=rand()%100;
startTime = clock();
MergeSort1(arr,0,N-1);
endTime = clock();
cout<<"MergeSort1: "<<(endTime - startTime)/1000.0<<" s"<<endl;
for(int i=0;i<N;i++) arr[i]=rand()%100;
startTime = clock();
MergeSort2(arr,0,N-1);
endTime = clock();
cout<<"MergeSort2: "<<(endTime - startTime)/1000.0<<" s"<<endl;
for(int i=0;i<N;i++) arr[i]=rand()%100;
startTime = clock();
MergeSort3(arr,0,N-1);
endTime = clock();
cout<<"MergeSort3: "<<(endTime - startTime)/1000.0<<" s"<<endl;
}
int main(int argc, char *argv[])
{
//MergeSort1(arr,0,N-1);
//MergeSort3(arr,0,N-1);
//prin();
TestMergeSort_prin();
//MergeSort_prin(arr,0,N-1,0);
return 0;
}
剑指 Offer 51. 数组中的逆序对
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
示例 1:
输入: [7,5,6,4]
输出: 5
限制:
0 <= 数组长度 <= 50000
class Solution {
public:
int reversePairs(vector<int>& nums) {
vector<int> tmp(nums);
return sort(nums,0,nums.size()-1,tmp);
}
int sort(vector<int>& nums,int l,int r,vector<int>& tmp){
if(l>=r) return 0;
int res=0;
int mid=l+(r-l)/2;
res+=sort(nums,l,mid,tmp);
res+=sort(nums,mid+1,r,tmp);
if(nums[mid]>nums[mid+1])
res+=merge(nums,l,mid,r,tmp);
return res;
}
int merge(vector<int>& nums,int l,int mid,int r,vector<int>& tmp){
copy(nums.begin()+l,nums.begin()+r+1,tmp.begin()+l);
int i=l,j=mid+1,res=0;
for(int k=l;k<=r;k++){
if(i>mid) nums[k]=tmp[j++];
else if(j>r) nums[k]=tmp[i++];
else if(tmp[i]<=tmp[j]) nums[k]=tmp[i++];
else{
res+=mid-i+1;nums[k]=tmp[j++];
}
}
return res;
}
};