例题1:
给中序遍历和后序遍历求前序遍历。
#include<bits/stdc++.h>
using namespace std;
string zhong,hou;
//https://ac.nowcoder.com/acm/contest/21763/1011
void deal(int l1,int r1,int l2,int r2)
{
if(l1>r1) return;
char gen=hou[r2];
int pos;
for(int i=l1;i<=r1;i++)//找到中序遍历中的根节点
{
if(gen==zhong[i])
{
pos=i;
break;
}
}
printf("%c",gen);//一开始遍历根节点
deal(l1,pos-1,l2,l2+pos-1-l1);//先遍历左子树
deal(pos+1,r1,l2+pos-l1,r2-1);//再遍历右子树
}
int main()
{
cin>>zhong>>hou;
int len=zhong.size();
deal(0,len-1,0,len-1);
}
例题2:FBI树
#include<bits/stdc++.h>
using namespace std;
//https://ac.nowcoder.com/acm/contest/21763/1013
string s;
void deal(int l,int r)
{
int mid=(l+r)/2;
if(l==r)
{
if(s[l]=='1') printf("I");
else printf("B");
return;
}
deal(l,mid);//先遍历左子树
deal(mid+1,r);//再遍历右子树
int vis1=0,vis0=0;
for(int i=l;i<=r;i++)//最后遍历根
{
if(s[i]=='1') vis1=1;
if(s[i]=='0') vis0=1;
}
if(vis1==1&&vis0==1) printf("F");
else if(vis1==0&&vis0==1) printf("B");
else if(vis1==1&&vis0==0) printf("I");
}
int main()
{
int n;
cin>>n;
int len=pow(2,n);
cin>>s;
deal(0,len-1);
}
写法2:
#include<bits/stdc++.h>
using namespace std;
//https://ac.nowcoder.com/acm/contest/21763/1013
string s;
char deal(int l,int r)
{
int mid=(l+r)/2;
if(l==r)
{
if(s[l]=='1')
{
printf("I");
return 'I';
}
else {
printf("B");
return 'B';
}
}
char zuo=deal(l,mid);//先遍历左子树
char you=deal(mid+1,r);//再遍历右子树
int vis1=0,vis0=0;
//for(int i=l;i<=r;i++)//最后遍历根
//{
// if(s[i]=='1') vis1=1;
// if(s[i]=='0') vis0=1;
//}
if(zuo!=you||zuo=='F'||you=='F')
{
printf("F");
return 'F';
}
else if(zuo==you&&zuo=='B')
{
printf("B");
return 'B';
}
else
{
printf("I");
return 'I';
}
}
int main()
{
int n;
cin>>n;
int len=pow(2,n);
cin>>s;
deal(0,len-1);
}
例题3:表达式计算
#include<bits/stdc++.h>
using namespace std;
string s;
int trans(int l,int r)
{
int num=0;
for(int i=l;i<=r;i++) num=num*10+s[i]-'0';
return num;
}
int calc(int l,int r)
{
int cnt=0;//统计括号
int pos1=-1,pos2=-1,pos3=-1;//记录+- */ ^的位置
for(int i=l;i<=r;i++)
{
if(s[i]=='(') cnt++;
if(s[i]==')') cnt--;
if(cnt==0)
{
//尤其注意,这里pos记录的都是最后一个符号,必须是最后一个符号,就是这个符号
//是要最后处理的,把前面的同类符号处理完再来算这个
//不然要出错,比如:64/32/2,如果不是最后一个符号,那他先算32/2=16,然后
//64/16返回4
if(s[i]=='+'||s[i]=='-') pos1=i;
if(s[i]=='*'||s[i]=='/') pos2=i;
if(s[i]=='^') pos3=i;
}
}
if(pos1==-1&&pos2==-1&&pos3==-1)//如果没找到运算符,说明被括号包围了,或者本身就没有运算符
{
if(cnt==0&&s[l]=='(')//括号刚好匹配,没有多余的括号
{
return calc(l+1,r-1);
}
if(cnt>0)//左边括号多了
{
return calc(l+1,r);
}
if(cnt<0)//右括号多了
{
return calc(l,r-1);
}
//数字本身
return trans(l,r);
}
if(pos1!=-1) //先考虑加减 因为优先级最低
{
if(s[pos1]=='+') return calc(l,pos1-1)+calc(pos1+1,r);
if(s[pos1]=='-') return calc(l,pos1-1)-calc(pos1+1,r);
}
else if(pos2!=-1) //考虑乘除
{
if(s[pos2]=='*') return calc(l,pos2-1)*calc(pos2+1,r);
if(s[pos2]=='/') return calc(l,pos2-1)/calc(pos2+1,r);
}
//else if(pos3!=-1) // 考虑^
//{
//if(s[pos3]=='^')
return pow(calc(l,pos3-1),calc(pos3+1,r));
//}
}
int main()
{
cin>>s;
cout<<calc(0,s.size()-1);
}
例题四(较难)
给先序遍历和后续遍历求中序遍历
条件:若只有一个子树,则该子树为左子树。
vector<int> v;
//https://ac.nowcoder.com/acm/contest/21763/1012
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param n int 二叉树节点数量
* @param pre intvector 前序序列
* @param suf intvector 后序序列
* @return intvector
*/
void deal(int pl,int pr,int sl,int sr,vector<int>& pre, vector<int>& suf)
{
if(pl==pr)//树叶
{
v.push_back(pre[pl]);
return;
}
int x=pre[pl+1];//先序遍历中左子树的根
int pos=-1;//记录后续遍历中左子树的根在哪,以此来区分左右子树
//这里题目的条件:若某节点只有一个子节点,则此处将其看作左儿子节点。这个条件保证了
//分界线一定存在,即一定可以分开左右子树,右子树也可以不存在。
for(int i=sl;i<=sr;i++) //遍历后序遍历找到分界线
{
if(suf[i]==x)
{
pos=i;
break;
}
}
//接下来开始递归
deal(pl+1,pl+1+pos-sl,sl,pos,pre,suf);//先遍历左子树
v.push_back(pre[pl]);//遍历根节点
if(pos+1<=sr-1)//判断右子树是否存在
deal(pl+1+pos-sl+1,pr,pos+1,sr-1,pre,suf);//遍历右子树
}
vector<int> solve(int n, vector<int>& pre, vector<int>& suf) {
deal(0,n-1,0,n-1,pre,suf);
return v;
}
};
通过以上例题可以知道递归函数,优先执行的先写。