1. 二叉树 定义结点类型
typedef struct node
{
int data;
struct node* lchild;
struct node* rchild;
} Tnode;
2. 二叉树的先序遍历:根节点——左子树——右字树
递归遍历:
void PreOrder(Tnode* root)
{
if(root==NULL)
return ;
cout<<root->val<<endl;
Preorder(root->lchild);
Preorder(root->rchild);
}
非递归遍历:先序遍历时,每当我们压入一个结点,我们压入结点前对其进行访问
void PreOrder(Tnode *root)
{
if(root==NULL)
return ;
stack<Tnode *>s;
Tnode *now=root;
while(!s.empty() || now)
{
while(now)
{
cout<<now->val<<"->";
s.push(now);
now=now->lchild;
}
now=s.top();
s.pop();
now=now->rchild;
}
cout<<endl;
}
3. 二叉树的中序遍历:左子树——根节点——右字树
递归遍历:
void InOrder(Tnode* root)
{
if(root==NULL)
return ;
Preorder(root->lchild);
cout<<root->val<<endl;
Preorder(root->rchild);
}
非递归遍历:中序时我们需要在遍历完左子树后访问根节点,再去遍历右子树
void InOrder(Tnode *root)
{
if(root==NULL)
return ;
stack<Tnode *>s;
Tnode *now=root;
while(!s.empty() || now)
{
while(now)
{
s.push(now);
now=now->lchild;
}
now=s.top();
cout<<now->val<<"->";
s.pop();
now=now->rchild;
}
cout<<endl;
}
4. 后序遍历:左子树——右字树——根节点
递归遍历:
void PostOrder(Tnode* root)
{
if(root==NULL)
return ;
Preorder(root->lchild);
Preorder(root->rchild);
cout<<root->val<<endl;
}
非递归遍历:后序遍历时由于访问完左右子树后才能访问根结点,因此需要将根结点在栈内保留到左右子树被访问后,但同时会出现一个问题,当右子树弹出后遇到根结点又会将右子树结点压入栈中,造成死循环,因此我们需要在定义一个变量last代表最后一个访问的结点,当last与栈顶结点的右子树结点相同时,则不再将右子树结点压入栈中。
void PostOrder(Tnode *root)
{
if(root==NULL)
return ;
stack<Tnode *>s;
Tnode *now=root;
Tnode *last=NULL;
while(!s.empty() || now)
{
while(now)
{
s.push(now);
now=now->lchild;
}
now=s.top();
if(now->rchild && last!=now->rchild)
now=now->rchild;
else if(now->rchild ==NULL || last ==now->rchild)
{
cout<<<now->val<<"->";
last=now;
s.pop();
now=NULL;
}
}
}
5. 给定中序和前序,求层序(后序都是一样的,主要是建树的过程)。
首先我们在上面介绍了前序,中序,后序遍历的特性。所以我们基本的思路就是先找到当前树的根节点,然后划分为左子树,右子树,然后进入左子树重复上面的过程,然后进入右子树重复上面的过程。最后就可以还原一棵树了。给个例子介绍一下:
前序遍历: GDAFEMHZ
中序遍历: ADEFGHMZ
画树求法:
第一步,根据前序遍历的特点,我们知道根结点为G
第二步,观察中序遍历ADEFGHMZ。其中root节点G左侧的ADEF必然是root的左子树,G右侧的HMZ必然是root的右子树。
第三步,观察左子树ADEF,左子树的中的根节点必然是大树的root的leftchild。在前序遍历中,大树的root的leftchild位于root之后,所以左子树的根节点为D。
第四步,同样的道理,root的右子树节点HMZ中的根节点也可以通过前序遍历求得。在前序遍历中,一定是先把root和root的所有左子树节点遍历完之后才会遍历右子树,并且遍历的左子树的第一个节点就是左子树的根节点。同理,遍历的右子树的第一个节点就是右子树的根节点。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
using namespace std;
typedef long long LL;
const int INF=0x3f3f3f3f;
const int maxn=50;
int n,m,s,d;
int a[maxn],b[maxn];
struct Node
{
int l,r;
}node[maxn];
int buildtree(int la,int ra,int lb,int rb)
{
if(la>ra)
return 0;
int root=b[lb];
int len1,len2;
len1=la;
while(a[len1]!=root)
len1++;
len2=len1-la;
node[root].l=buildtree(la,len1-1,lb+1,lb+len2);
node[root].r=buildtree(len1+1,ra,lb+len2+1,rb);
return root;
}
void bfs(int root)
{
queue<int>q;
vector<int>v;
q.push(root);
while(!q.empty())
{
int w=q.front();
q.pop();
if(w==0)
break;
v.push_back(w);
if(node[w].l!=0)
q.push(node[w].l);
if(node[w].r!=0)
q.push(node[w].r);
}
int len=v.size();
for(int i=0;i<len;i++)
printf("%d%c",v[i],i==len-1?'
':' ');
return;
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
for(int i=0;i<n;i++)
scanf("%d",&b[i]);
buildtree(0,n-1,0,n-1);
int root=b[0];
bfs(root);
return 0;
}
6. 给后序和中序遍历,求层序遍历。
思路和上面是一样的,主要是掌握建树的过程。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
using namespace std;
typedef long long LL;
const int INF=0x3f3f3f3f;
const int maxn=50;
int n,m,s,d;
int a[maxn],b[maxn];
struct Node
{
int l,r;
}node[maxn];
int buildtree(int la,int ra,int lb,int rb)
{
if(la>ra)
return 0;
int root=a[rb];
int len1,len2;
len1=la;
while(b[len1]!=root)
len1++;
len2=len1-la;
node[root].l=buildtree(la,len1-1,lb,lb+len2-1);
node[root].r=buildtree(len1+1,ra,lb+len2,rb-1);
return root;
}
void bfs(int root)
{
queue<int>q;
vector<int>v;
q.push(root);
while(!q.empty())
{
int w=q.front();
q.pop();
if(w==0)
break;
v.push_back(w);
if(node[w].l!=0)
q.push(node[w].l);
if(node[w].r!=0)
q.push(node[w].r);
}
int len=v.size();
for(int i=0;i<len;i++)
printf("%d%c",v[i],i==len-1?'
':' ');
return;
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)//先给的是后序
scanf("%d",&a[i]);
for(int i=0;i<n;i++)
scanf("%d",&b[i]);
buildtree(0,n-1,0,n-1);
int root=a[n-1];
bfs(root);
return 0;
}
7. 给定二叉树,给出S型打印:
void S_LevelOrderPrint(TreeNode t)
{
stack<TreeNode> s1;
stack<TreeNode> s2;
s1.push(t);
while(!s1.empty() || !s2.empty())
{
if(!s1.empty())
{
while(!s1.empty())
{
TreeNode tn = s1.top();
cout<<tn.val<<"";
s1.pop();
if(tn.right != null)
s2.push(tn.right);
if(tn.left != null)
s2.push(tn.left);
}
}
else
{
while(!s2.empty())
{
TreeNode tn = s2.top();
cout<<tn.val<<" ";
s2.pop();
if(tn.left != null)
s1.push(tn.left);
if(tn.right != null)
s1.push(tn.right);
}
}
}
}