< >C++归并排序法和逆序对 2021-06-07

//归并排序 
#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;
    }
};

Guess you like

Origin blog.csdn.net/lybc2019/article/details/117654608