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