二叉树
存储结构
typedef struct TreeNode *BinTree;
typedef BinTree Postion;
struct TreeNode{
ElementType Data;
BinTree Left;
BinTree Right;
}
二叉树的遍历
先序遍历
遍历过程:
①访问根结点
②先序遍历其左子树
③先序遍历其右子树
void PreOrderTraversal(BinTree BT)
{
if(BT){
printf("%d", BT->Data);
PreOrderTraversal(BT->Left);
PreOrderTraversal(BT->Right);
}
}
A (B D F E) (C G H I)
先序遍历 => A B D F E C G H I
中序遍历
遍历过程:
①中序遍历其左子树
②访问根结点
③中序遍历其右子树
void InOrderTraversal(BinTree BT)
{
if(BT){
InOrderTraversal(BT->Left);
printf("%d", BT->Data);
InOrderTraversal(BT->Right);
}
}
(D B E F) A (G H C I)
中序遍历 => D B E F A G H C I
后序遍历
遍历过程为:
①后序遍历其左子树
②后序遍历其右子树
③访问根结点
void PostOrderTraversal(BinTree BT)
{
if(BT){
PostOrderTraversal(BT->Left);
PostOrderTraversal(BT->Right);
printf("%d", BT->Data);
}
}
(D E F B) (H G I C) A
后序遍历 => D E F B H G I C A
层序遍历
二叉树遍历的核心问题:二维结构的线性化
从结点 访问其左、右子节点,访问左儿子后,右儿子节点怎么办?
需要一个存储结构保存暂时不访问的结点。
存储结构:堆栈、队列
队列实现
遍历从根结点开始,首先将根节点入队,然后开始执行循环:节点出队、访问该节点、其左右儿子入队。
层序的基本过程:先根节点入队,然后:
①从队列中取出一个元素
②访问该元素所指节点
③若该元素所指的左、右孩子节点非空,则将其左、右孩子的指针顺序入队
void LevelOrderTraversal(BinTree BT)
{
Queue Q;
BinTree T;
if(!BT) return; // 若是空树则直接返回
Q = CreateQueue(MaxSize); // 创建并初始化队列Q
AddQ(Q, BT);
while(!IsEmpty(Q)){
T = DeleteQ(Q);
printf("%d\n", T->Data); // 访问取出队列的节点
if(T->Left) AddQ(Q, T->Left);
if(T->Right) AddQ(Q, T->Right);
}
}
遍历应用的例子
例:遍历二叉树的应用:输出二叉树中的叶子结点
· 在二叉树的遍历算法中增加检测结点的“左右子树是否都为空”。
void ProOrderPrintLeaves(BinTree BT)
{
if(BT){
if(!BT->Left && !BT->Right)
printf("%d ", BT->Data);
ProOrderPrintLeaves(BT->Left);
ProOrderPrintLeaves(BT->Right);
}
}
例:求二叉树的高度
int PostOrderGetHeight(BinTree BT)
{
int HL, HR, MaxH=0;
if(BT){
HL = PostOrderGetHeight(BT->Left);
HR = PostOrderGetHeight(BT->Right);
return (MaxH+1);
}
else return 0;
}
例:二元运算表达式树及其遍历
三种遍历可以得到三种不同的访问结果:
先序遍历:++abc+defg
中序遍历:a+bc+de+fg
后序遍历:abc*+def+g+
先序和中序遍历序列来确定一颗二叉树
分析: 根据先序遍历序列第一个结点确定根结点 根据根结点在中序遍历序列中分割出左右两个子序列 对左子树和右子树分别递归使用相同的方法继续分解
例:先序序列:a b c d e f g h i j
中序序列:c b e d a h g i j f