分治算法总结

在这里插入图片描述

典型例题

归并排序的递归和非递归、快速排序和随机化快速排序

#include<iostream>
#include<stdlib.h>
#include<ctime>
using namespace std;
int a[10000]={0};
int aa[10000]={0};
int b[10000]={0};
int N;
clock_t startTime,endTime;

void Merge(int *a,int *b,int left,int i,int right){
	//放a到b
	int mid=i++;
	int bj=left;
	while(left<=mid || i<=right){
		if(left>mid){
			for(;i<=right;){
				b[bj++]=a[i++];
			}
		}
		if(i>right){
			for(;left<=mid;){
				b[bj++]=a[left++];
			}
		}
		if(a[left]<a[i]){
			b[bj++]=a[left++];
		}else{
			b[bj++]=a[i++];
		}
	}
	
}
void Copy(int *a,int *b,int left,int right){
	for(;left<=right;left++){
		a[left]=b[left];
	} 
}
void MergeSort(int *a,int *b,int left,int right){
	if(left<right){ 
		int i=(left+right)/2;
		MergeSort(a,b,left,i);
		MergeSort(a,b,i+1,right);
		Merge(a,b,left,i,right);	//将a放到b  也是归并的主要步骤 
		Copy(a,b,left,right);	//从b再放回a  和上一步可以合并 
	}
}
void Printa(){	//打印a数组   查看排序结果 
	for(int i=0;i<N;i++){	
		cout<<a[i]<<" ";
	}
	cout<<endl;
}
void Printb(){	//打印b数组 用于测试 
	for(int i=0;i<N;i++){
		cout<<b[i]<<" ";
	}
	cout<<endl;
}
void clearab(){	//将a恢复至最初未排序状态 
	for(int i=0;i<N;i++){
		a[i]=aa[i];
		b[i]=0;
	}
}
void MergePass(int *x,int *y,int s){	//非递归的主要代码  
	int i=0;
	while(i<N-2*s){
//		cout<<"***";
		Merge(x,y,i,i+s-1,i+2*s-1);
		i+=2*s;
	}
	if(i+s<N){
		Merge(x,y,i,i+s-1,N-1);
	}else{
		for(int j=i;j<N;j++){
			y[j]=x[j];
		}
	}
}
void MergeSort_n(int *a,int *b){	//非递归归并排序 
	int s=1;//当前序列长度
	while(s<N){
		MergePass(a,b,s);
		s+=s;
		MergePass(b,a,s);
		s+=s;
	} 
}
/*1 13 2 5 69 37 45 27
1 2 5 13 
1 2 5 13 27 37 45 69*/
void Swap(int& a,int& b){	//交换两者 
	int x=a;
	a=b;
	b=x;
}
int Partition(int *a,int p,int r){	//随机化快速排序 
	int i=p,j=r+1; //第一个是本身  最后一个从最后加一开始减少 
	int x=a[p];
	while(true){
		while(a[++i]<x && i<r);
		while(a[--j]>x);
		if(i>=j) break;
		Swap(a[i],b[j]);
	}
	a[p]=a[j];
	a[j]=x;
	return j;
}
int random(int p,int r){	//获得p到r之间的随机值 
	return p+(rand()%(r+1));
}
int RandomizedPartition(int *a,int p,int r){	//随机化得到一个中间标记 
	int i = random(p,r);
	swap(a[i],a[p]);	//放到第一个以便用普通的Partition来进行获得标记 
	return Partition(a,p,r);	
}
void QuickSort(int *a,int p,int r){	//普通快排 
	if(p<r){
		int q=Partition(a,p,r);
		QuickSort(a,p,q-1);
		QuickSort(a,q+1,r);
	}
} 
void RandomQuickSort(int *a,int p,int r){	//随机化快排 
	if(p<r){
		int q=RandomizedPartition(a,p,r);
		QuickSort(a,p,q-1);
		QuickSort(a,q+1,r);
	}
} 

int main(){
	cin>>N;
	for(int i=0;i<N;i++){
		cin>>a[i];
		aa[i]=a[i];
	}
	
	startTime = clock();//计时开始
	cout<<"\nMergeSort(递归的合并排序):"<<endl;
	for(int i=0;i<100000;i++){
		MergeSort(a,b,0,N-1);
		//Printa();
		clearab();
	} 
	endTime = clock();//计时结束
	Printa();
	cout << "递归合并排序" <<(double)(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl;
	
	
	startTime = clock();//计时开始
	cout<<"\nMergeSort_n(非递归的合并排序):"<<endl;
	for(int i=0;i<100000;i++){
		MergeSort_n(a,b);
	
		clearab();
	}
	endTime = clock();//计时结束
	Printa();
	cout << "非递归合并排序" <<(double)(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl;
	
	startTime = clock();//计时开始
	cout<<"\nQuickSort(快速排序):"<<endl;
	for(int i=0;i<100000;i++){
		QuickSort(a,0,N-1);
		clearab();
	} 
	endTime = clock();//计时结束
	Printa();
	cout << "快速排序" <<(double)(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl;
	
	startTime = clock();//计时开始
	cout<<"\nRandomQuickSort(随机化快速排序):"<<endl;
	for(int i=0;i<100000;i++){
		RandomQuickSort(a,0,N-1);
		clearab();
	}
	endTime = clock();//计时结束
	Printa();
	cout << "随机化快速排序" <<(double)(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl;
} 

大整数乘法(暂只是等长度的两个整数)

#include<iostream>
#include<string>
#include<cstdlib>
#include<string.h>
#include<algorithm>
using namespace std;

string addStrings(string num1, string num2);
string func(string s1,string s2);
int check(string s);
string n_10(string s,int num);
string subStrings(string num1,string num2,int flag);

int main(){
	string s1,s2;
	cin>>s1;
	cin>>s2;
	string s;
	s=func(s1,s2);
	cout<<s;
}

int check(string s){ 	//每次分半 

	if(s.size()>4){
			return s.size()/2;		
	}
		
	else
		return 0;
}
string subStrings(string num1,string num2,int flag){	//相减 
	int end1=num1.size() -1;
    int end2=num2.size()-1;
    int value1=0;
    int value2=0;
    int next=0;
    string result;
    while(end1>=0 || end2>=0){
    	if(end1>=0){
            value1=num1[end1--]-'0';
        }
        else{
            value1=0;
        }
        if(end2>=0){
            value2=num2[end2--]-'0';
        }else{
            value2=0;
        }
        int sub=0;
        if(next){	//被借了一位 
        	value1--;
        	next=0;//?这里可能 
		}
        if(value1>=value2){
        	sub=value1-value2;
		}else{
			next=1; //借位
			sub=value1+10-value2; 
		}  
		result+=(sub+'0');
		
	}     
	
	if(next){		
		if(flag==-1){
			return subStrings(num2,num1,1);
		}
		return 	subStrings(num2,num1,-1);
	}
	
	if(flag == -1){
		result+='-';
		
	} 

	reverse(result.begin(),result.end());	//倒置 
    return result;  
	
}
string addStrings(string num1, string num2) {
	
	if(num1[0]=='-' || num2[0]=='-'){		//两个负的相乘 
		string num3;
		if(num1[0]=='-'){
			num3=num1.substr(1,num1.length()-1);

			return subStrings(num3,num2,-1); 
		}else{
			num3=num2.substr(1,num2.length()-1);
			return subStrings(num3,num1,-1); 
		}
	}
    int end1=num1.size() -1;
    int end2=num2.size()-1;
    int value1=0;
    int value2=0;
    int next=0;    
    string result;
    while(end1>=0||end2>=0){
        if(end1>=0){
            value1=num1[end1--]-'0';
        }
        else{
            value1=0;
        }
        if(end2>=0){
            value2=num2[end2--]-'0';
        }else{
            value2=0;
        }
        int sum=value1+value2+next;
        
		if(sum>9){
        	next=1;
            sum-=10;
        }else{
            next=0;
        }
        result+=(sum+'0');//将int型 sum转变为字符串		//345  987
        						//sum=2  进位next=1 然后循环 
    }
    if(next){		//最后一个进位 
        result+='1';		//假设最后21 倒过来就是12 
    }
    reverse(result.begin(),result.end());	//倒置 
    return result;  
}
string n_10(string s,int num){ //乘以10的num次方 即10^n  字符串形式 即补0 
	for(int i=0;i<num;i++){
		s=s+'0';
	}
	return s;
 } 
string func(string s1,string s2) {//两数相乘算法
	if(s1[0]=='-' && s2[0]=='-'){
		s1=s1.substr(1,s1.length()-1);
		s2=s2.substr(1,s2.length()-1);
	}

	int num1;//s1一半 
	int num2;//s2一半 
	if(check(s1)||check(s2)){
		
		bool flagfu = false;
		if(s1[0]=='-'){
			s1=s1.substr(1,s1.length()-1);	//最后结合 
			flagfu = true; 
		}else if(s2[0]=='-'){
			s2=s2.substr(1,s2.length()-1);	//最后结合 
			flagfu = true; 
		}
		
		num1=check(s1);
		
		string a(begin(s1),end(s1)-num1);
		string b(end(s1)-num1,end(s1));
		num2=check(s2);

		string c(begin(s2),end(s2)-num2);
		string d(end(s2)-num2,end(s2));

		string ac,ad,bc,bd,abdc,mid;
		ac=func(a,c);

		bd=func(b,d);

		if(a[0]=='-' && b[0]!='-'){
			a=a.substr(1,a.length()-1);
		}
		string asb = subStrings(a,b,1);
		if(c[0]=='-' && d[0]!='-'){
			c=c.substr(1,c.length()-1);
		}
		string dsc = subStrings(d,c,1);
		abdc=func(asb,dsc);
		mid = addStrings(abdc,ac);
		mid = addStrings(mid,bd);
			
		ac=n_10(ac,num1+num2);
		mid=n_10(mid,num1);
		string pre=addStrings(ac,mid);
		string final = addStrings(pre,bd);
		if(flagfu){
			final='-'+final;
		}
		return final;
	}
	else
	{
		int x1,x2;
		
		if(s1!=""){
			x1=stoi(s1);	//转换成整数 
		}else{
			x1=0;
		}
		if(s2!=""){
			x2=stoi(s2);
		}else{
			x2=0;
		}
		int sum=x1*x2;
		char z[1000]={0};
		memset(z,0,1000);
		itoa(sum,z,10);
		return z;
	}
	 

}
 

线性时间选择(油管铺设问题)

#include<iostream>
#include<fstream>
#include<cmath>
using namespace std;
int N;
int arrx[10000];
int arr[10000];
int mycmp(const void*a,const void *b){
	return *(int *)a-*(int *)b;
}
void myswap(int *a,int x,int y){
	int temp = a[x];
	a[x] = a[y];
	a[y] = temp;
}
void Print(){
	for(int i=0;i<N;i++){
		cout<<arr[i]<<" ";
	}
}
int partition(int p,int r,int x){
	int pos;
	for(int i = p;i<=r;i++){
		if(arr[i]==x){
			pos=i;
			break;
		}
	} 
	myswap(arr,p,pos);
	int i=p,j=r+1; //第一个是本身  最后一个从最后加一开始减少 
	x=arr[p];
	while(true){
		while(arr[++i]<x && i<r);
		while(arr[--j]>x);
		if(i>=j) break;
		myswap(arr,i,j);
	}
	arr[p]=arr[j];
	arr[j]=x;
	
//	cout<<"*******"<<endl; 
//	Print();
	return j;
} 
int Select(int p,int r,int k){
	if(r-p<75){
		qsort(arr+p,r-p+1,sizeof(int),mycmp);
		return arr[p+k-1];
	}
	for(int i=0;i<=(r-p-4)/5;i++){ //(r-p+1)/5-1个组 
		int s = p+5*i;
		qsort(arr+s,5,sizeof(int),mycmp);
		myswap(arr,p+i,s+2);
	}
	int x = Select(p,p+(r-p-4)/5,(r-p+1)/10);	//基准值 
	int i = partition(p,r,x);	//分裂点位置 即当前基准值的位置 
	int j = i-p+1;	//当前基准值是第几个元素 
	if(k<=j)return Select(p,i,k);
	else return Select(i+1,r,k-j);
}
int cal(int mid){
	int sum=0;
	for(int i=0;i<N;i++){
		sum+=fabs(mid-arr[i]);
	}
	return sum;
}
int main(){
	ifstream in;
	ofstream out;
	in.open("input.txt");
	if(in.is_open()){
		in>>N;
		for(int i=0;i<N;i++){
			in>>arrx[i]>>arr[i];
		}
	}
	int mid = Select(0,N-1,N/2);
//	cout<<mid;
//	Print();
	out.open("output.txt");
	if(out.is_open()){
		out<<cal(mid);
	}
	return 0;
}

循环赛日程表

#include<iostream>
#include<cmath>
using namespace std;
int N;
int arr[1000][1000];
void func(int n);
void Print();
int main(){
	cin>>N;
	func(N);
	Print();
	return 0;
}
void func(int n){
	if(n<=2){
		arr[1][1]=arr[2][2]=1;
		arr[1][2]=arr[2][1]=2;
		return;
	}
	func(n/2);
	//rightdown;
	for(int i=n/2+1;i<=n;i++){
		for(int j = n/2+1;j<=n;j++){
			arr[i][j]=arr[i-n/2][j-n/2];
		}
	}
	//leftdown;
	for(int i=n/2+1;i<=n;i++){
		for(int j = 1;j<=n/2;j++){
			arr[i][j]=arr[i-n/2][j]+pow(2,n/4);
		}
	}
	//rightup;
	for(int i=1;i<=n/2;i++){
		for(int j = n/2+1;j<=n;j++){
			arr[i][j]=arr[i+n/2][j-n/2];
		}
	}
}
void Print(){
	for(int i=1;i<=N;i++){
		for(int j=1;j<=N;j++){
			cout<<arr[i][j]<<" ";
		}
		cout<<endl;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值