9.2.1 先序遍历:
void preorder(node *root)
{
if(root==NULL) //到达空树,递归边界
return ;
cout << root->data; //读出root结点的数据,相当于访问根结点
preorder(root->lchild); //访问左子树
preorder(root->rchild); //访问右子树
}
9.2.2 中序遍历:
void preorder(node *root)
{
if(root==NULL) //到达空树,递归边界
return ;
preorder(root->lchild); //访问左子树
cout << root->data; //相当于访问根结点
preorder(root->rchild); //访问右子树
}
2.中序遍历的性质:
9.2.3 后序遍历:
1.后序遍历的实现:
void preorder(node *root)
{
if(root==NULL) //到达空树,递归边界
return ;
preorder(root->lchild); //访问左子树
preorder(root->rchild); //访问右子树
cout << root->data; //相当于访问根结点
}
2.后序遍历序列的性质:
9.2.4 层序遍历:
void LayerOrder(node *root)
{
queue<node*> q; //注意队列存放的是地址
q.push(root); //将根结点入队
while(!q.empty())
{
node *top;
top=q.front(); //取出队首元素
q.pop();
cout << top.data;
if(top->lchild!=NULL) //如果左孩子不为空,则将左孩子放到队列中
q.push(top->lchild);
if(top->rchild!=NULL) //如果右孩子不为空,则将右孩子放到队列中
q.push(top->rchild);
}
return ;
}
统计每个结点所处的层次
struct node
{
int data; //数据域
node *lchild; //左指针域
node *rchild; //右指针域
int layer; //层次
};
//层序遍历法:
void LayerOrder(node *root)
{
queue<node*> q; //存放队列地址
root->layer=1; //root是一结构类型的指针,所以访问其中成员的话用->
q.push(root); //将根结点入队
while(!q.empty())
{
node *now=q.front(); //取出队首元素
q.pop();
cout << now->data; //访问队首元素
if(now->lchild!=NULL) //如果左子树不为空,则遍历左子树
{
now->lchild->layer=now->layer+1; //左子树的层号为当前层号+1
q.push(now->lchild);
}
if(now->rchild!=NULL) //如果右子树非空
{
now->rchild->layer=now->layer+1; //右子树层号为当前层号+1
q.push(now->rchild);
}
}
}
给定一颗二叉树的先序遍历和中序遍历序列,重建这个二叉树:
给出下面一个具体的例子:
node *create(int preL, int preR, int inL, int inR) //当前先序序列的区间为[preL,preR],中序序列的区间为[inL,inR]
{
if(preL>preR) //先序长度小于0时,则递归结束
return NULL;
node *root=new node; //创建一个新的结点,用来存放当前二叉树的新结点
root->data=pre[preL]; //新结点的数据域为根结点的数据域
int k;
for(k=inL; k<=inR; k++)
{
if(pre[preL]==in[k]) //在中序序列中找到先序序列中根结点的数值,就退出循环
{
break;
}
}
int numLeft=k-inL; //左子树的结点数为k-inL
//左子树的先序区间是[preL+1,preL+numLeft],左子树的中序区间是[inL,k-1],返回左子树的根结点,赋值给root的左指针
root->lchild=create(preL+1,preL+numLeft,inL,k-1);
//右子树的先序区间是[preL+numLeft+1,preR],右子树的中序区间是[k+1,inR],返回右子树的根结点,赋值给root的右指针
root->rchild=create(preL+numLeft+1,preR,k+1,inR);
return root; //返回结点地址
}
pat A1020
解题思路:
参考代码:
#include<iostream>
#include<queue>
using namespace std;
struct node
{
int data;
node *lchild;
node *rchild;
};
/*
1.按照后序和中序找到二叉树
2.按照层序输出
*/
int n,num=0;
const int maxn=31;
int houxu[maxn],zhongxu[maxn];
node *create(int PostL, int PostR, int inL, int inR)
{
if(PostL>PostR)
return NULL;
node *root=new node;
root->data=houxu[PostR];
int k;
for(k=inL; k<=inR; k++)
{
if(zhongxu[k]==houxu[PostR])
{
break;
}
}
int numl=k-inL;
root->lchild=create(PostL,PostL+numl-1,inL,k-1);
root->rchild=create(PostL+numl,PostR-1,k+1,inR);
return root;
}
void layer(node *root)
{
queue<node*> q;
q.push(root);
while(!q.empty())
{
node *top=q.front();
q.pop();
//num表示当前的个数,先输入一个数字,然后num++,如果num不超过n,则输出一个空格,当num为最后一个数字时,就不用再输入空格了
cout << top->data;
num++;
if(num<n)
cout << " ";
//注意不能是if-else语句,本身的含义是分别判断左右子树是否为空,若为空,则不加入队列中,否则加入到队列中
if(top->lchild!=NULL)
q.push(top->lchild);
if(top->rchild!=NULL)
q.push(top->rchild);
}
}
int main()
{
cin >> n;
for(int i=0; i<n; i++)
cin >> houxu[i];
for(int i=0; i<n; i++)
cin >> zhongxu[i];
node *root;
root=create(0,n-1,0,n-1);
layer(root);
return 0;
}
注意事项:
在create函数中,如果最后没有返回root,则会出现段错误,因为函数不结束,就会溢出
9.2.5二叉树的静态实现:
struct node
{
typename data; //数据域
int lchild; //左子树
int rchild; //右子树
}Node[maxn]; //结点数组,maxn为结点上限个数
//查找,root为根结点在数组中的下标
void search(int root, int x, int newdata)
{
if(root=-1) //用-1来代替NULL
return ; //空树,死胡同(递归边界)
if(Node[root].data==x) //找到数据域为x的结点,把它修改成newdata
Node[root].data=newdata;
search(Node[root].lchild, x, newdata); //往左子树搜索x
search(Node[root].rchild, x, newdata); //往右子树搜索x
}
//插入,root为根结点在数组中的下标
void insert(int &root, int x)
{
//记得加引用
if(root=-1) //空树,说明查找失败,也即插入位置(递归边界)
{
root=newNode(x); //给root赋以新的结点
return ;
}
if(由二叉树性质x应该插在左子树)
{
insert(Node[root].lchild,x); //往左子树搜索
}
else
{
insert(Node[root].rchild,x); //往右子树搜索
}
}
//二叉树的建立,函数返回根结点root的下标
int Create(int data[], int n)
{
int root=-1; //新建根结点,将root值设为-1
for(int i=0; i<n; i++)
{
insert(root,data[i]); //将data[0]~data[n-1]插入二叉树中
}
return root; //返回二叉树根结点下标
}
//关于二叉树的先序遍历,中序遍历,后序遍历,层序遍历也做相应的转换
//先序遍历
void preorder(int root)
{
if(root==-1)
return ; //到达空树,递归边界
//访问根结点root,将数据域,例如将其数据域输出
printf("%d\n",Node[root].data);
//访问左子树
preorder(Node[root].lchild);
//访问右子树
preorder(Node[root].rchild);
}
//中序遍历
void inorder(int root)
{
if(root==-1)
return ; //到达空树,递归边界
//访问左子树
inorder(Node[root].lchild);
printf("%d\n",Node[root].data); //输出数字
//访问右子树
inorder(Node[root].rchild);
}
//后序遍历
void postorder(int root)
{
if(root=-1)
return ;
printf("%d\n",Node[root].data); //输出
postorder(Node[root].lchild);
postorder(Node[root].rchild);
}
//层序遍历
void LayerOrder(int root)
{
queue<int> q; //此处队列里存放结点下标
q.push(root); //将根结点地址入队
while(!q.empty())
{
int now=q.front(); //取出队首元素
q.pop(); //弹出
printf("%d ", Node[now].data); //访问队首元素
if(Node[now].lchild!=-1) //左子树非空
q.push(Node[now].lchild); //将左子树压入队列
if(Node[now].rchild!=-1) //右子树非空
q.push(Node[now].rchild); //将右子树压入队列
}
}
类似于图中走迷宫,只要遇到岔路口就继续深入下去,一直到遍历完所有的岔路口,不碰到死胡同不回头