二叉树的遍历和线索二叉树
二叉树的遍历是指按某条搜索路径访问树中的每个结点,使得每个结点均被访问一次,且只被访问一次。
先序遍历(NLR)
若二叉树为空,则什么也不做;否则,
(1)访问根结点。
(2)先序遍历左子树。
(3)先序遍历右子树。
void PreOrder(BiTree T){
if(T != NULL){
visit(T);
PreOrder(T->lchild);
PreOrder(T->rchild);
}
}
中序遍历(LNR)
若二叉树为空,则什么也不做;否则,
(1)中序遍历左子树;
(2)访问根结点;
(3)中序遍历右子树。
void InOrder(BiTree T){
if(T != NULL){
InOrder(T->lchild);
visit(T);
InOrder(T->rchild);
}
}
后序遍历(LRN)
若二叉树为空,则什么也不做;否则,
(1)后序遍历左子树;
(2)后序遍历右子树;
(3)访问根结点。
void PostOrder(BiTree T){
if(T != NULL){
PostOrder(T->lchild);
PostOrder(T->rchild);
visit(T);
}
}
层次遍历
算法思想:
①初始化一个辅助队列
②根结点入队
③若队列非空,则队头结点出队,访问该结点,并将其左、右孩子插入队尾
④重复③直至队列为空
void LevelOrder(BiTree T){
InitQueue(Q);
BiTree p;
EnQueue(Q,T);
while(!IsEmpty(Q)){
DeQueue(Q,p);
visit(p);
if(p->lchild != NULL)
EnQueue(Q,p->lchild);
if(P->rchild != NULL)
EnQueue(Q,p->rchild);
}
}
由遍历序列构造二叉树(考点)
首先:只给出一种遍历序列无法构造出唯一的二叉树。其次:想构造出唯一的二叉树必须要有中序遍历序列。
关键点:找到树的根结点,并根据中序序列将树划分为左右子树,再根据前序、后序、层序遍历进一步找到左右子树的根结点。
前序+中序遍历序列
①前序遍历序列中第一个元素一定是根结点。
②找出根结点后,就可以在中序遍历序列中找到根结点并将树分为左右子树。
③在前序遍历序列中找到左右子树的前序遍历序列。再分别执行①
后序+中序遍历序列
①后序遍历序列中最后一个元素一定是根结点。
②找出根结点后,就可以在中序遍历序列中找到根结点并将树分为左右子树。
③在后序遍历序列中找到左右子树的后序遍历序列。再分别执行①
层序+中序遍历序列
①层序遍历序列中第一个元素一定是根结点。
②找出根结点后,就可以在中序遍历序列中找到根结点并将树分为左右子树。
③在层序遍历序列中找到左右子树的层序遍历序列。再分别执行①
线索二叉树的基本概念
线索二叉树的作用
传统的二叉链表存储仅能体现一种父子关系,不能直接得到结点在遍历序列中的前驱或后继。为了能够通过二叉树直接得到某个结点在遍历序列中的前驱和后继,引入了线索二叉树。
其实就是将二叉树转为其对应序列的双链表(一部分),让遍历二叉树变为遍历单链表,简化遍历过程的同时也使得可以直接从任意某个结点开始寻找其前驱或后继!!
线索二叉树的实现
利用n个结点的二叉树中的n+1个空指针域来存放指向其前驱或后继的指针。
规定:
若无左子树,令lchild指向其前驱结点;若无右子树,令rchild指向其后继结点。
还需要增加两个标志域ltag,rtag标识指向左/右孩子还是指向前序/后继线索。
ltag == 0 :lchild域指向左孩子
ltag == 1:lchild域指向前驱
rtag == 0:rchild域指向右孩子
rtag == 1:rchild域指向后继
typedef struct ThreadNode{
ElemType data;
struct ThreadNod *lchild,*rchild;
int ltag,rtag;
}ThreadNode,*ThreadTree;
三种线索二叉树
中序线索二叉树
先序线索二叉树
后序线索二叉树
二叉树的线索化(构造线索二叉树)
手算线索化二叉树
①确定线索二叉树类型——中序、先序、后序
②按照对应遍历规则得到遍历序列
③将n+1个空链域连上前驱、后继