参考资料:《数据结构(C语言版)严蔚敏著》
版权说明:未经作者允许,禁止转载。如引用本文内容,需标明作者及出处。如本文侵犯了您的权益,请联系我删除并致歉。
文章说明:如文章中出现错误,请联系我更改。如您对文章的内容有任何疑问,也欢迎来与我讨论。
本文正在施工中...请稍等...
二叉树的链式表示
使用链表来表示二叉树,则结点结构中至少含有3个域:数据域、左指针域和右指针域。有时,为了便于找到结点的双亲,还可在结点结构中增加一个指向其双亲节点的指针域。利用这两种结构所得二叉树的存储结构分别称为二叉链表和三叉链表。
二叉链表
描述如下:
typedef struct BiTNode{
ElemType elem;
struct BiTNode *lchild, *rchlid; //左右孩子指针
}BiTNode, *BiTree;
二叉链表上基本操作的实现
Status CreateBiTree(BiTree &T){
scanf(&ch);
if(ch==' ') T=NULL;
else{
if(!(T=(BiTNide *)malloc(sizeof(BiTNode)))) exit(OVERFLOW);
T->data=ch;
CreateBiTree(T->lchild);
CreateBiTree(T->rchild);
}
return OK;
}
先序遍历二叉树:
(1) 访问根结点
(2) 先序遍历左子树
(3) 先序遍历右子树
Status PreOrderTraverse(BiTree T, Status (* Visit)(ElemType e)){
if(T){
if(Visit(T->elem))
if(PreOrderTraverse(T->lchild, Visit))
if(PreOrderTraverse(T->rchlid, Visit)) return OK;
return ERROR;
}
return OK;
}
中序遍历二叉树:
(1) 中序遍历左子树
(2) 访问根结点
(3) 中序遍历右子树
Status InOrderTraverse(BiTree T, Status (* Visit)(ElemType e)){
if(T){
if(InOrderTraverse(T->lchild, Visit))
if(Visit(T->elem))
if(InOrderTraverse(T->rchlid, Visit)) return OK;
return ERROR;
}
return OK;
}
Status InOrderTraverse(BiTree T, Status(* Visit)(ElemType)){
InitStack(S); Push(S, T);
while(!StackEmpty(S)){
while(GetTop(S, p) && p) Push(S, p->lchild);
Pop(S, p);
if(!StackEmpty(S)){
Pop(S, p); if(!Visit(p->data)) return ERROR;
Push(S, p->rchild);
}
}
return OK;
}
Status InOrderTraverse(BiTree T, Status (*visit)(ElemType e)){
InitStack(S); p=T;
while(p || !StackEmpty(S)){
if(p) { Push(S, p); p=p->lchild; }
else{
Pop(S, p); if(!Visit(p->data)) return ERROR;
p=p->rchild;
}
}
return OK;
}
后序遍历二叉树:
(1) 后序遍历左子树
(2) 后序遍历右子树
(3) 访问根结点
Status PostOrderTraverse(BiTree T, Status (* Visit)(ElemType e)){
if(T){
if(PostOrderTraverse(T->lchild, Visit))
if(PostOrderTraverse(T->rchlid, Visit))
if(Visit(T->elem)) return OK;
return ERROR;
}
return OK;
}
层序遍历二叉树
由二叉树的中序遍历序列和先序遍历序列(或后序遍历序列,或层序遍历序列)可唯一确定一棵二叉树。
线索二叉树
遍历二叉树是以一定规则将二叉树中结点排列成一个线性序列,这实质上是对一个非线性结构进行线性化操作,使每个结点在这些线性序列中有且仅有一个直接前驱和直接后继。因此,为了方便得到结点的直接前驱和直接后继信息,可以在二叉链表中再附加两个指针域,分别指示结点在按序遍历时得到的直接前驱和直接后继的信息。但这样做,会使结构的存储密度大大降低。我们想到,在有n个结点的二叉链表中必定有n+1个空链域,尝试用这些空链域来存放结点的直接前驱和直接后继的信息。我们在二叉链表结构中增加两个标志域LTag和RTag,描述如下:
typedef enum PointerTag{ Link, Thread }; //Link==0:指针,Thread==1:线索
typedef struct BiTNode{
ElemType elem;
struct BiTNode *lchild, *rchlid; //左右孩子指针
PointerTag LTag, RTag; //左右标志
}BiThrNode, *BiThrTree;
规定:若结点有左孩子,则LTag=0,lchild指向其左孩子; 否则,LTag=1,lchild指向其直接前驱。若结点有右孩子,则RTag=0,rchlid指向其右孩子;否则,RTag=1,rchild指向其直接后继。
以这种结点结构构成的二叉链表作为二叉树的存储结构,叫做线索链表,其中指向结点直接前驱和直接后继的指针,叫做线索。加上线索的二叉树称之为线索二叉树。对二叉树按序遍历使其成为线索二叉树的过程叫做线索化。
Status InOrderTraverse_Thr(BiThrTree T, Status (*Visit)(ElemType e)){
p=T->lchild;
while(p!=T){
while(p->LTag==Link) p=p->lchild;
if(!Visit(p->data)) return ERROR;
while(p->RTag==Thread && p->rchild!=T){
p=p->rchild; Visit(p->data);
}
p=p->rchild;
}
return OK;
}
Status InOrderThreading(BiThrTree &Thrt, BiThrTree T){
if(!(Thrt=(BiThrTree)malloc(sizeof(BiThrNode)))) exit(OVERFLOW);
Thrt->LTag=Link; Thrt->RTag=Thread;
Thrt->rchild=Thrt;
if(!T) Thrt->lchild=Thrt;
else{
Thrt->lchild=T; pre=Thrt;
InThreading(T);
pre->rchild=Thrt; pre->RTag=Thread;
Thrt->rchild=pre;
}
return OK;
}
void InThreading(BiThrTree p){
if(p){
InThreading(p->lchild);
if(!p->lchild) { p->LTag=Thread; p->lchild=pre; }
if(!pre->rchild) { pre->RTag=Thread; pre->rchild=p; }
pre=p;
InThreading(p->rchild);
}
}