文章目录
先序遍历
遍历过程
- 访问根节点
- 先序遍历其左子树
- 先序遍历其右子树
示意图
代码实现
void PreOrderTraversal(BinTree BT)
{
// 判断节点是否为空节点
if(BT){
// 这是要对节点中数据进行的操作
printf("%d", BT->Data);
// 递归遍历子节点
PreOrderTraversal(BT->Left);
PreOrderTraversal(BT->Right);
}
}
中序遍历
遍历过程
- 中序遍历其左子树
- 访问根节点
- 中序遍历其右子树
示意图
代码实现
void InOrderTraversal(BinTree BT){
if(BT){
InOrderTraversal(BT->Left);
print("%d", BT->Data);
InOrderTraversal(BT->Right);
}
}
后序遍历
遍历过程
- 后序遍历其为左子树
- 后序遍历其为右子树
- 访问根节点
示意图
代码实现
void PostOrderTraversal(BinTree BT){
if(BT){
PostOrderTraversal(BT->Left);
PostOrderTraversal(BT-Right);
printf("%d", BT->Data);
}
}
先序、中序和后序遍历总结
- 先序、中序和后序遍历过程:遍历过程中经过节点的路线一样,只是访问各个节点的时机不同。
- 在下图↓中,入口到出口的曲线上用
⊗
、✰
和△
三种符号分别标记出了先序、中序和后序访问各节点的时刻
中序遍历非递归遍历算法
遍历过程
- 遇到一个节点,就把它压栈,并去遍历它的左子树
- 当左子树遍历结束后,从栈顶弹出这个节点并访问它
- 然后按其右指针再去中序遍历该节点的右子树
代码实现
void InOrderTraversal(BinTree BT){
BinTree T = BT;
// 创建并初始化堆栈 S*
Stack S = CreatStack(MaxSize);
while(T || !IsEmpty(S)){
// 一直向左并将沿途结点压入堆栈
while(T){
Push(S, T);
T = T->Left;
}
if(!IsEmpty(S)){
// 结点弹出堆栈
T = Pop(S);
// (访问)打印结点
printf("%d", T->Data);
// 转向右子树
T = T->Right;
}
}
}
层序遍历
遍历过程
- 从队列中取出一个元素
- 访问该元素所指的结点
- 若该元素所指结点的左、右子结点非空,则将其左、右子结点的指针顺序入队
示意图
代码实现
void LevelOrderTraversal(BinTree BT){
Queue Q;
BinTree T;
// 若是空树则直接返回
if(!BT) return;
// 创建并初始化队列 Q
Q = CreatQueue(MaxSize);
AddQ(Q, BT);
while(!IsEmptyQ(Q)){
T = DeleteQ(Q);
// 访问取出队列的结点
printf("%d", T->Data);
if(T->Left) Add(Q, T->Left);
if(T->Right) Add(Q, T->Right);
}
}
总结
二叉树遍历的核心问题:二维结构的线性化
- 从结点访问其左、右子结点
- 访问左子结点后,右子结点怎么办?
- 需要一个存储结构保存暂时不访问的结点
- 存储结构:堆栈、队列