1. 二叉树的存储结构
#define MAXSIZE 100
typedef struct BiTNode{
TElemType data;
struct BiTNode *left ,*right;
}BiTNode, * BiTree;
2. 二叉树的递归遍历
2.1 先序递归遍历
【算法步骤】
1. 访问根结点
2. 先序遍历左子树
3. 先序遍历右子树
【算法描述】
------------先序遍历-----------
void PreOrderTraverse(BiTree T){
if(T){
cout << T -> data; //访问根节点
PreOrderTraverse(T -> left);
PreOrderTraverse(T -> right);
}
}
2.2 中序递归遍历
【算法步骤】
1. 中序遍历左子树
2. 访问根结点
3. 中序遍历右子树
【算法描述】
------------中序遍历-----------
void InOrderTraverse(BiTree T){
if(T){ //当前树不空
InOrderTraverse(T -> left); //中序遍历左子树
cout << T -> data; //访问根节点
InOrderTraverse(T -> right);
}
}
2.3 后序递归遍历
【算法步骤】
后序遍历的递归算法思路:
1. 后序遍历左子树
2. 后序遍历右子树
3. 访问根结点
【算法描述】
------------后序遍历-----------
void PostOrderTraverse(BiTree T){
if(T){
PostOrderTraverse(T -> left); //后序遍历左子树
PostOrderTraverse(T -> right);
cout << T -> data;
}
}
3. 二叉树的非递归遍历
Q1.为何用到栈?
A. 由于栈的特性 —— 后进先出
Q2. 利用顺序栈还是链栈?
A. 设计到频繁的插入和删除操作,因此用到链栈。
3.1 先序非递归遍历
【算法步骤】
1. 从根结点开始,先访问根结点,输出根结点的数据域的值
2. 将根结点压入栈,以便于后续弹栈遍历右子树
3. 遍历左子树且不断输出子树根结点,并将结点压入栈
4. 从栈顶弹出无左子树的结点,开始遍历右子树
【算法描述】
void PreOrderTraverse_S(BiTree T){
LinkStack S = new LinkStack; //创建链栈
InitStack(S); //初始化链栈
BiTNode p = T; //指向根节点
BiTNode q = new BiTNode;
while(p || StackEmpty(S)){
if(p){
cout << p -> data; //先访问根节点
Push(S,p); //便于后继遍历右子树 - 根节点入栈
p = p -> left; //遍历左子树
}
else{
Pop(S,q); //弹出栈顶元素,并置为 q;
p = q -> right; //遍历右子树
}
}
}
3.2 中序非递归遍历
【算法步骤】
中序遍历的非递归算法思路:
1. 从根结点开始,遇到结点则将结点压栈
2. 当遇到无左子树的结点时,将此结点弹栈且访问它并遍历它的右子树
3. 若该结点为叶子结点,则继续弹栈,开始遍历它的父节点的右子树
【算法描述】
------------中序非递归遍历-----------
void InOrderTraverse_s(BiTree T){
InitStack(S); //创建一个空栈
BiTNode * p = T; //指向根结点
BiTNode * q = new BiTNode;
while(p || StackEmpty(s)){
if(p){
Push(S,p);
p = p -> left;
}
else{
Pop(S,q);
cout << q -> data; //当前遍历完左子树的根节点
p = q -> right; //遍历右子树
}
}
}
3.3 后续非递归遍历
【算法步骤】
后序遍历的非递归算法思路:
1. 从根结点开始,沿其左子树一直往下搜索且压栈,直至出现没有左子树的结点
2. 将此结点的 visit 域置为true,表面该结点第一次出现在栈顶
3. 取栈顶元素并弹栈,若该栈顶元素第一次出现在栈顶则压栈,并将其 visit 域置为false,开始遍历右子树
4. 若该栈顶元素第二次出现在栈顶则访问该结点,并将 p 指针置空以便继续弹栈,操作其父节点。
【算法描述】
void PostOrderedTraverse_S(BiTree T){
LinkStack S = new LinkStack;
InitStack(S);
BiTNode * p = T; //指向根结点
BiTNode * q = new BiTNode; //取出栈顶元素
BiTnode * t = new BiTNode; //指向栈顶元素
while(p || StackEmpty(S)){
//首先把左子树遍历到底
while(p){
Push(S,p);
p -> vist = true;
p = p -> left;
}
if(StackEmtpy(S)){
t = GetTop(S); //指向栈顶元素
Pop(S,q); //取出栈顶元素
if(t -> vist == true) { //如果栈顶元素是第一次访问的
t -> vist = false; //再次访问栈顶元素 - 为了访问右子树
p = q -> right; //访问该结点的右子树
Push(S,p); //把右子树进栈 - 为了访问根节点
}
else { //如果当前结点不是第一次访问过的,说明他已经访问完他的左右子树
cout << t -> data; //访问根节点
p = NULL; //指针域置空
}
}
}