先序遍历
- 先序遍历的实现
先序遍历:根结点->左子树->右子树
void preorder(node* root)
{
if(root == NULL)
{
return; //到达空树,递归边界
}
//访问根结点root,例如将其数据域输出
printf("%d\n", root->data);
//访问左子树
preorder(root->lchild);
//访问右子树
preorder(root->rchild);
}
- 先序遍历的性质
序列的第一个肯定是根结点。
A -> B -> C -> D -> E -> F -> G -> H -> K
中序遍历
- 中序遍历的实现
中序遍历:左子树->根结点->右子树
void inorder(node* root)
{
if(root == NULL)
{
return; //到达空树,递归边界
}
//访问左子树
inorder(root->lchild);
//访问根结点root,例如将其数据域输出
printf("%d\n", root->data);
//访问右子树
inorder(root->rchild);
}
- 中序遍历的性质
B -> D -> C -> A -> E -> H -> G -> K -> F
后序遍历
- 后序遍历的实现
后序遍历:左子树->右子树->根结点
void postorder(node* root)
{
if(root == NULL)
{
return; //到达空树,递归边界
}
//访问左子树
postorder(root->lchild);
//访问右子树
postorder(root->rchild);
//访问根结点,例如将其数据域输出
printf("%d\n", root->data);
}
- 后序遍历的性质
D -> C -> B -> H -> K -> G -> F -> E -> A
无论先序遍历还是后序遍历,都必须知道中序遍历才能唯一确定一棵树。
层序遍历
层序遍历:按层次的顺序从根结点向下逐层进行遍历,且对同一层的结点为从左到右遍历。
层次遍历相当于对二叉树从根结点开始的广度优先搜索
- 将根结点root加入队列q
- 取出队首结点,访问它
- 如果该结点有左孩子,将左孩子入队
- 如果该结点有右孩子,将右孩子入队
- 返回2,直到队列为空
void LayerOrder(node* root)
{
queue<node*> q; //注意队列里是存地址
q.push(root); //将根结点地址入队
while(!q.empty())
{
node* now = q.front(); //取出队首元素
q.pop();
printf("%d", now->data); //访问队首元素
if(now->lchild != NULL)
q.push(now->lchild); //左子树非空
if(now->rchild != NULL)
q.push(now->rchild); //右子树非空
}
}
node*型变量:可以通过访问地址去修改原元素。
计算每个结点所处的层次:
struct node{
int data; //数据域
int layer; //层次
node* lchild; //左指针域
node* rchild; //右指针域
};
//层序遍历
void LayerOrder(node* root)
{
queue<node*> q; //注意队列是存地址
root->layer = 1; //根结点的层号是1
q.push(root); //将根结点地址入队
while(!q.empty())
{
node* now = q.front(); //取出队首元素
q.pop();
printf("%d ", 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);
}
}
}
给定一颗二叉树的先序遍历和中序遍历,重建这棵二叉树:
//当前先序序列区间为[preL, preR],中序序列区间为[inL, inR],返回根结点地址
node* create(int preL, int preR, int inL, int inR)
{
if(preL > preR)
{
return NULL; //先序序列长度小于等于0时,直接返回
}
node* root = new node; //新建一个新的结点,用来存放当前二叉树的根节点
root->data = pre[preL]; //新结点的数据域为根结点的值
int k;
for(k = inL; k <= inR; k++)
{
if(in[k] == pre[preL]) //在中序序列中找到in[k] == pre[L]的结点
{
break;
}
}
int numLeft = 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; //返回根结点地址
}