分治与递归(算法分析与设计)

1.分治法基本模板

divide-and-comquer(P)
{
	if(|P|<=n0)
		adhoc(P);
	divide P into smaller subinstances P1,P2,...,Pk;
	for(i=1;i<=k;i++)
		yi=divide-and-comquer(Pi);
	return merge(y1,...,yk);
}

a.一般是递归出口

b.将原问题分割成若干子问题,子问题与原问题相同,规模略小

c.合并子问题的解(不是所有分治都有这个)

2.递归与非递归的转换记录

a.尾递归转非递归(一般先写好递归版,再用栈模拟)(本质:还是自顶而下

尾递归在原问题转换成若干子问题之后,不再合并子问题的解,递归是最后的语句,递归之后不再有操作返回值或局部变量的表达式。

1.循环外压栈初始变量

2.循环以栈空为条件

3.循环内先出栈,恢复局部变量值

4.递归出口处,仍然编写递归出口处代码,由continue代替return来打断余下操作

5.用恢复的局部变量值操作

6.遇到递归处,改成压栈当前局部变量

7.出循环

b.线性(一般)递归转非递归

若用栈模拟递归,保存当前局部变量用以代替递归,但是递归之后,又需要用这些改变后的局部变量(或递归返回值)做子问题的合并,这个对我来说比较难做。所以换个方向,思考记录如下:
1.尾递归转非递归的本质还是自顶而下的处理问题,所以可以用栈轻易模拟

2.非尾递归可以自底而上,来转化递归

尾递归转非递归: 3.棋盘覆盖,4.快速排序

非尾递归转非递归:5.strassen矩阵乘法,6.合并排序

3.棋盘覆盖

a.递归版

#include
#include 
using namespace std;
vector< vector > a;
static int tile=1;
void chessBoard(int startx,int starty,int msize,int x,int y)
{
	if(msize==1)
	{
		return;
	}
	else
	{
		int g=tile++;//只能用局部变量来赋值,直接用静态变量,递归返回后,余下伪特殊方块的赋值就出问题了。 
		int tempx=(x-startx)/(msize/2);
		int tempy=(y-starty)/(msize/2);
		if(tempx==0&&tempy==0)
		{
			chessBoard(startx,starty,msize/2,x,y);
		}
		else
		{
			a[startx+msize/2-1][starty+msize/2-1]=g;
			chessBoard(startx,starty,msize/2,startx+msize/2-1,starty+msize/2-1);
			
		}
		
		if(tempx==0&&tempy==1)
		{
			chessBoard(startx,starty+msize/2,msize/2,x,y);
		}
		else
		{
			a[startx+msize/2-1][starty+msize/2]=g;
			chessBoard(startx,starty+msize/2,msize/2,startx+msize/2-1,starty+msize/2);
			
		}
		
		if(tempx==1&&tempy==0)
		{
			chessBoard(startx+msize/2,starty,msize/2,x,y);
		}
		else
		{
			a[startx+msize/2][starty+msize/2-1]=g;
			chessBoard(startx+msize/2,starty,msize/2,startx+msize/2,starty+msize/2-1);
			
		}
		
		if(tempx==1&&tempy==1)
		{
			chessBoard(startx+msize/2,starty+msize/2,msize/2,x,y);
		}
		else
		{
			a[startx+msize/2][starty+msize/2]=g;
			chessBoard(startx+msize/2,starty+msize/2,msize/2,startx+msize/2,starty+msize/2);
		}
	}
} 

int main()
{
	//初始化棋盘a,特殊元素赋值0,其余元素赋值-1 
	int n;
	cout<<"please input n!"<>n;
	vector temp;
	for(int j=0;j>x>>y;
	a[x][y]=0;
	//特殊元素赋值0,伪特殊元素均大于0,未被标记的均为-1 
	chessBoard(0,0,n,x,y);
	for(int i=0;i

b.非递归版

#include
#include 
#include
using namespace std;
typedef struct Node
{
	public:
		int startx;
		int starty;
		int msize;
		int x;
		int y;
};
vector< vector > a;//存放棋盘 
stack s;//存放临时变量 

void chessBoard(int startx,int starty,int msize,int x,int y)
{
	Node temp;//临时变量 
	int g=1; 
	temp.startx=startx;
	temp.starty=starty;
	temp.msize=msize;
	temp.x=x;
	temp.y=y;
	s.push(temp);//初始状态压栈 
	
	while(!s.empty())//栈空为循环终止判断条件 
	{
		Node temp2=s.top();//出栈,恢复局部变量 
		s.pop();
		if(temp2.msize==1)//递归出口处,return用continue代替,打断余下操作 
		{
			continue;	
		}
		if((temp2.x-temp2.startx)temp2.msize/2)
		{
			temp.startx=temp2.startx;
			temp.starty=temp2.starty+temp2.msize/2;
			temp.msize=temp2.msize/2;
			temp.x=temp2.x;
			temp.y=temp2.y;
			s.push(temp);
		}
		else
		{
			temp.startx=temp2.startx;
			temp.starty=temp2.starty+temp2.msize/2;
			temp.msize=temp2.msize/2;
			temp.x=temp2.startx+temp2.msize/2-1;
			temp.y=temp2.starty+temp2.msize/2;
			s.push(temp);
			if(a[temp2.startx+temp2.msize/2-1][temp2.starty+temp2.msize/2]==-1)
				a[temp2.startx+temp2.msize/2-1][temp2.starty+temp2.msize/2]=g;	
		}
		if((temp2.x-temp2.startx)>temp2.msize/2&&(temp2.y-temp2.starty)temp2.msize/2&&(temp2.y-temp2.starty)>temp2.msize/2)
		{
			temp.startx=temp2.startx+temp2.msize/2;
			temp.starty=temp2.starty+temp2.msize/2;
			temp.msize=temp2.msize/2;
			temp.x=temp2.x;
			temp.y=temp2.y;
			s.push(temp);
		}
		else
		{
			temp.startx=temp2.startx+temp2.msize/2;
			temp.starty=temp2.starty+temp2.msize/2;
			temp.msize=temp2.msize/2;
			temp.x=temp2.startx+temp2.msize/2;
			temp.y=temp2.starty+temp2.msize/2;
			s.push(temp);
			if(a[temp2.startx+temp2.msize/2][temp2.starty+temp2.msize/2]==-1)
				a[temp2.startx+temp2.msize/2][temp2.starty+temp2.msize/2]=g;
		}
		g++;
	}
	return;
} 

int main()
{
	int n;
	cout<<"please input n!"<>n;
	vector temp;
	for(int j=0;j>x>>y;
	a[x][y]=0;
	chessBoard(0,0,n,x,y);
	
	for(int i=0;i

4.快速排序(随机快速排序:随机在left~right之间选择一个主元,再将主元与最左(右)元素互换位置,其他一切照旧)(按各主元对称的序列,快排效果最好)

a.递归版

#include
#include
using namespace std;
int qSortOne(vector &p,int left,int right)
{
	int a=p[left];
	while(leftp[left])
		{
			left++;
		}
		p[right]=p[left];
		p[left]=a;
	}	
	return left;	
}
void qSort(vector &w,int left,int right)
{
	if(left a;
	int temp;
	while(cin>>temp)
	{
		a.push_back(temp);
	}	
	qSort(a,0,a.size()-1);
	for(int i=0;i

b.非递归版

#include
#include
#include
using namespace std;
typedef struct Node
{
	int left;
	int right;
};
stack s;
int qSortOne(vector &p,int left,int right)
{
	int a=p[left];
	while(leftp[left])
		{
			left++;
		}
		p[right]=p[left];
		p[left]=a;
	}	
	return left;	
}
void qSort(vector &w,int left,int right)
{
	Node temp;
	temp.left=left;
	temp.right=right;
	s.push(temp);
	while(!s.empty())
	{
		Node temp1=s.top();
		s.pop();
		if(temp1.left a;
	int temp;
	while(cin>>temp)
	{
		a.push_back(temp);
	}	
	qSort(a,0,a.size()-1);
	for(int i=0;i

5.strassen矩阵乘法

a.非递归版

#include
#include
using namespace std;
int main()
{
	int n;
	cout<<"please input n!"<>n;
	vector< vector > A;//A作为乘数矩阵A,和存储结果矩阵C 
	vector< vector > B;
	cout<<"please input matrix A!"< temp2;
		for(int j=0;j>temp1;
			temp2.push_back(temp1);
		}
		A.push_back(temp2);
	}
	cout<<"please input matrix B!"< temp2;
		for(int j=0;j>temp1;
			temp2.push_back(temp1);
		}
		B.push_back(temp2);
	}	
	cout<<"count matrix C!"< M;
		for(int j=0;j

6.合并排序

a.递归版

#include
#include
#include
using namespace std;
int random(int s,int e)
{
	return s+rand()%(e-s+1);
}
void mergeD(vector &a,vector &b,int l,int mid,int r)
{
	int i=l;
	int j=mid+1;
	while(i<=mid&&j<=r)
	{
		if(a[i] &a,vector &b,int l,int r)
{
	for(int i=l;i<=r;i++)
	{
		a[i]=b[i-l];
	}
}
void mergeSort(vector &d,int l,int r)
{
	if(l b;
		mergeD(d,b,l,i,r);
		copyD(d,b,l,r);
	}
}
int main()
{
	vector data;
	int temp;
	cin>>temp;
	for(int i=0;i
b.非递归版
#include
#include
#include
#include
using namespace std;
int random(int s,int e)
{
	return s+rand()%(e-s+1);
}
void mergeD(vector &a,vector &b,int l,int mid,int r)
{
	int i=l;
	int j=mid+1;
	while(i<=mid&&j<=r)
	{
		if(a[i] &a,vector &b,int l,int r)
{
	for(int i=l;i<=r;i++)
	{
		a[i]=b[i-l];
	}
}
//尾递归转非递归用栈模拟(本质上还是自顶而下)
//线性递归转非递归用栈模拟比较困难,那么就换种思路,自底而上 
void mergeSort(vector &d)
{
	int size=2;//排序小组大小 
	int n=d.size(); 
	int left;
	int right;
	while(size<=n)
	{
		for(left=0;left+size-1<=n-1;left=left+size)
		{
			right=left+size-1;
			vector b;
			mergeD(d,b,left,(right+left)/2,right);
			copyD(d,b,left,right);
		}
		
		if(right b;
			mergeD(d,b,left,left+size/2-1,right);
			copyD(d,b,left,right);
		}
		size=size*2;
	}
	size=size/2;
	if(size!=n) 
	{
		left=0;
		right=n-1;
		vector b;
		mergeD(d,b,left,left+size-1,right);
		copyD(d,b,left,right);
	}
}
int main()
{
	vector data;
	int temp;
	cin>>temp;
	for(int i=0;i

7.线性时间选择(在序列中找出第k小的数(中位数等等))

a.寻找第k小元素(随机划分线性时间选择)

#include
#include
#include
using namespace std;
int random(int start,int end)//产生一个(start,end)之间的随机整数 
{
    return start+rand()%(end-start+1);//rand()产生一个随机整数 
}
int qSortOne(vector &p,int left,int right)//随机划分一次(一次快排划分) 
{
	int i=(int)(random(left,right));
	int a=p[left];
	p[left]=p[i];
	p[i]=a;
	a=p[left];
	while(leftp[left])
		{
			left++;
		}
		p[right]=p[left];
		p[left]=a;
	}	
	return left;	
}
void findK(vector &w,int left,int right,int k)
{
	if(left<=right)
	{
		int start=qSortOne(w,left,right);
		if(start>k)//只递归一边 
		{
			findK(w,left,start-1,k);
		}
		else if(start a;
	int temp;
	int k;
	cout<<"please input k!"<>k;
	cout<<"please input array a[],end by ctrl+z!"<>temp)
	{
		a.push_back(temp);
	}	
	findK(a,0,a.size()-1,k);
	for(int i=0;i

b.寻找第k小元素(选择划分基准线性时间选择)

#include
#include
#include
#include
using namespace std;
int random(int start,int end)
{
    return start+rand()%(end-start+1);
}
//比较元素已然确定,就不需要再在函数内部选了 
int Partition(vector &d,int left,int right,int k)
{
	int i = left-1,j = right + 1;
	while(true)
	{
		while(d[++i]k);
		if(i>=j)
		{
			break;
		}
		swap(d[i],d[j]);
	}	
	return j;
}
//冒泡排序,用于对小组内元素排序 
void Bubble(vector &d,int left,int right)
{
	bool exchange;
	for(int i=0;i<=right-left;i++)
	{
		exchange=false;
		for(int j=left;jd[j+1])
			{
				swap(d[j],d[j+1]);
				exchange=true;
			}
		}
		if(!exchange)
		{
			return;
		}
	}
}
int Select(vector &d,int left,int right,int k)
{ 
	if(left-right<75)//如果排序个数小于75个,就直接排序,返回第k大小的元素值 
	{
		Bubble(d,left,right);
		return d[left+k-1];
	}
	int i;
	//如果排序个数大于75个,再用找中位数的中位数的方法来减少运算次数
	for(i=0;i<=(right-left-4)/5;i++) 
	{
		Bubble(d,left+i*5,left+i*5+4);//各小组内部排序 
		swap(d[left+i*5+2],d[left+i]);//将各小组的中位数都移到数组最左端 
	} 
	i--;
	if((left+i*5+4) data;
	int n;
	cout<<"please input the size of array data[]!"<>n;
	for(int i=0;i>k;
	cout<<"the number is: "<
8.最接近点对问题

a.O(n^2)暴力法

#include
#include
#include
#include
#include
using namespace std;
typedef struct Node
{
	int x;
	int y;
};
vector d;
int random(int s,int e)
{
	return s+rand()%(e-s+1);
}
double dis(int a,int b)
{
	return sqrt(pow(d[b].x-d[a].x+0.0,2)+pow(d[b].y-d[a].y+0.0,2));	
}
bool cmpxy(Node a,Node b) 
{
	if(a.x!=b.x)
	{
		return a.x temt;
	if(left+1==right)//只有两个元素,直接返回 
	{
		return dis(right,left);
	}
	else if(left+2==right)//只有三个元素,按中位数分后,有一边只有一个元素,所以也是直接计算,返回结果 
	{
		double d1=dis(right,left);
		double d2=dis(right,left+1);
		double d3=dis(right-1,left);
		return min(min(d1,d2),d3);
	}
	double d1=Count(left,(left+right)/2);//以x坐标排序中位线划分左区 
	double d2=Count((left+right)/2+1,right);//以x坐标排序中位线划分右区 
	double dx=min(d1,d2);
	for(int i=left;i<=right;i++)//没有按《算法设计与分析》中描写一样,这里是直接用暴力,将整个[-dx,dx]区间的数给囊括了 
	{
		if(fabs(d[(left+right)/2].x-d[i].x)d3)					   //所以这个算法的复杂度是O(n^2),而不是算法设计与分析》中的n*logn 
            {
            	dx=d3;
            }    
        }
    }
    return dx;
}
int main()
{
	int num;
	cin>>num;
	Node temp;
	for(int i=0;i






你可能感兴趣的:(数据结构与基础算法)