第-5章-树-数据结构课件_第1页
第-5章-树-数据结构课件_第2页
第-5章-树-数据结构课件_第3页
第-5章-树-数据结构课件_第4页
第-5章-树-数据结构课件_第5页
已阅读5页,还剩351页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

树和森林的概念二叉树二叉树的表示二叉树遍历及其应用线索化二叉树树与森林堆

Huffman树

第5章树树和森林的概念第5章树树和森林的概念两种树:自由树与有根树。

自由树:一棵自由树Tf

可定义为一个二元组

Tf

=(V,E)

其中V={v1,...,vn}

是由n(n>0)个元素组成的有限非空集合,称为顶点集合。E={(vi,vj)|vi,vj

V,1≤i,j≤n}

是n-1个序对的集合,称为边集合,E

中的元素(vi,vj)称为边或分支。树和森林的概念两种树:自由树与有根树。自由树自由树

r是一个特定的称为根(root)的结点,它只有直接后继,但没有直接前驱;根以外的其他结点划分为m(m

0)个互不相交的有限集合T1,T2,…,Tm,每个集合又是一棵树,并且称之为根的子树。每棵子树的根结点有且仅有一个直接前驱,但可以有0个或多个直接后继。有根树: 一棵有根树T,简称为树,它是n(n≥0)

个结点的有限集合。当n=0时,T称为空树;否则,T

是非空树,记作r是一个特定的称为根(root)的结点,它只有直接后继,树的示意图(P.187)树的示意图(P.187)树的特点每棵子树的根结点有且仅有一个直接前驱,但可以有0个或多个直接后继。0层1层3层2层height=3ACGBDEFKLHMIJ树的特点每棵子树的根结点有且仅有一个直接前驱,但可以有0个或0层1层3层2层height=3ACGBDEFKLHMIJ结点结点的度分支结点叶结点子女双亲兄弟祖先子孙结点层次树的度树高度森林术语0层1层3层2层heightACGBDEFKLHMIJ结点子template<classType>classTree{public:Tree();

~Tree();

positionRoot();BuildRoot(constType&value);positionFirstChild

(positionp);positionNextSibling(positionp);positionParent(positionp);

TypeGetData(positionp);

intInsertChild(constpositionp,

constType&value);

int

DeleteChild(positionp,inti);}树的抽象数据类型template<classType>classTr一棵二叉树是结点的一个有限集合,该集合或者为空,或者是由一个根结点加上两棵分别称为左子树和右子树的、互不相交的二叉树组成。5.2二叉树(BinaryTree)

二叉树的定义一棵二叉树是结点的一个有限集合,该集合或者为空,或者是由一个二叉树的五种不同形态LLRR二叉树的五种不同形态LLRR性质1

若二叉树的层次从1开始,则在二叉树的第i层最多有2i-1个结点。(i

≥1)

性质2

深度为k的二叉树最多有2k-1个结点。k

≥0二叉树的性质

性质1若二叉树的层次从1开始,则在二叉树的第i层性质3

对任何一棵二叉树,如果其叶结点有n0个,度为2的非叶结点有n2个,则有

n0=n2+1证明:若设度为1的结点有n1

个,总结点个数为n,总边数为e,则根据二叉树的定义,

n=n0+n1+n2

e=n

-1=2n2+n1=因此,有2n2+n1=n0+n1+n2

-1

n2=n0

-1n0=n2+1性质3对任何一棵二叉树,如果其叶结点有n0个,度定义1

满二叉树(FullBinaryTree)

如果二叉树中所有分支结点的度数都为2,且叶子结点都在同一层次上,则称这类二叉树为满二叉树。定义2

完全二叉树(CompleteBinaryTree)如果一棵具有n个结点的高度为k的二叉树,它的每一个结点都与高度为k的满二叉树中编号为1-n结点一一对应,则称这棵二叉树为完全二叉树。(从上到下从左到右编号)定义1满二叉树(FullBinaryTree)定满二叉树完全二叉树层次h,叶结点仅在两层出现对任一结点,若其右子树的高度为k,则其左子树的高度是

h和h-1

kork+1满二叉树

性质4

具有n(n0)个结点的完全二叉树的高度为

log2(n+1)

23-124-1性质4具有n(n0)个结点的完全二叉树的高性质5

如将一棵有n个结点的完全二叉树自顶向下,同一层自左向右连续给结点编号1,2,…,n,则有以下关系:(1)若i==1,则i

为根,无双亲若i>1,则i的双亲为i/2(2)若n>=2*i,则结点i的左子女为2*i;

(3)若n>=2*i+1,则结点i的右子女为2*i+112348567910性质5如将一棵有n个结点的完全二叉树自顶向下,同一层自左(4)若结点编号i为奇数,且i!=1,则它的左兄弟为结点i-1。(5)若结点编号i为偶数,且i!=n,则它的右兄弟为结点i+1。(6)结点i所在层次为log2i+112348567910(4)若结点编号i为奇数,且i!=1,则它的左兄弟为结点i-template<classType>classBinaryTree

{public:BinaryTree();

//构造函数

BinaryTree(BinTreeNode<Type>*lch,BinTreeNode<Type>*rch,Typeitem);

//构造以item为根,lch和rch为左、右

//子树的二叉树

intIsEmpty();

//判二叉树空否?

BinTreeNode<Type>*Parent();

//双亲

二叉树的抽象数据类型template<classType>classBi

BinTreeNode<Type>*LeftChild();

//取左子女结点地址

BinTreeNode<Type>*RightChild();

//取右子女结点地址

intInsert(constType&item);//插入

intFind(constType&item)const;//搜索

TypeGetData()const;//取得结点数据

BinTreeNode<Type>*GetRoot()const;

//取根结点地址}BinTreeNode<Type>*LeftCh0123456789完全二叉树01378945625.3二叉树的存储表示顺序表示0123456789完全二叉树013780123567891113一般二叉树的顺序表示13026537811101235678911130261430极端情形:只有右单支的二叉树02614300261430极端情形:只有右单支的二叉树0261430leftChilddatarightChilddataleftChildrightChild二叉链表二叉树的链表表示

leftChilddatarightChilddleftChilddataparentrightChildparentdataleftChildrightChild三叉链表leftChilddataparentri二叉树链表表示的示例ABCDFErootAABBCCDDFFEErootroot

二叉链表三叉链表二叉树链表表示的示例ABCDFEroot二叉链表的静态结构ABCDFErootdataparentleftChildrightChild012345A-11-1B023C1

-1-1D145E3-1-1F3-1-1二叉链表的静态结构ABCDFErootdataparentemplate<classType>classBinaryTree;

template<classType>ClassBinTreeNode{friendclassBinaryTree<Type>;private:Type

data;

BinTreeNode<Type>*leftChild;

BinTreeNode<Type>*rightChild;

public:BinTreeNode():leftChild(NULL),rightChild(NULL){}二叉树的类定义template<classType>classBi

BinTreeNode(Typeitem,BinTreeNode<Type>*left=NULL, BinTreeNode<Type>*right=NULL):data(item),leftChild(left),rightChild(right){}TypeGetData

()const{returndata;

}BinTreeNode<Type>*GetLeft()const{returnleftChild;

}

BinTreeNode<Type>*GetRight()const{returnrightChild;

}

voidSetData(constType&item)

{data=item;

}

BinTreeNode(Typeitem,

voidSetLeft(BinTreeNode<Type>*L)

{leftChild=L;

}voidSetRight(BinTreeNode<Type>*R)

{rightChild=R;

}};template<classType>class

BinaryTree{

private:

BinTreeNode<Type>*root;

Type

RefValue;

void

CreateBinTree(ifstream&in,

BinTreeNode<Type>*¤t);

voidSetLeft(BinTreeNode

BinTreeNode<Type>*Parent(BinTreeNode<Type>*subTree,BinTreeNode<Type>*current);

int

Insert(BinTreeNode<Type>*&subTree,

constType

&item);

//插入

voidTraverse(BinTreeNode<Type>*subTree,

ostream&out)const

//遍历

int

Find(BinTreeNode<Type>*subTree,

constType&item)const

//搜索

voiddestroy(BinTreeNode<Type>*subTree);

//删除…}BinTreeNode<Type>*Parent

树的遍历:按某种次序访问树中的结点,要求每个结点访问一次且仅访问一次。设访问根结点记作V,遍历根的左子树记作L,遍历根的右子树记作R

5.4二叉树遍历

树的遍历:按某种次序访问树中的结点,要求每个则可能的遍历次序有:

VLRVRLLVRRVLLRV

RLV

前序

镜像中序

镜像

后序

镜像则可能的遍历次序有:前序中序遍历(InorderTraversal)--/+*abcdef遍历结果:

a+b*c

-

d

-

e/fLVR中序遍历(InorderTraversal)--/+*a中序遍历二叉树算法的框架是:若二叉树为空,则空操作;否则中序遍历左子树(L);访问根结点(V);中序遍历右子树(R)。中序遍历二叉树算法的框架是:二叉树递归的中序遍历算法template<classType>voidBinaryTree<Type>::InOrder(BinTreeNode<Type>*subTree){

if(subTree!=NULL){

InOrder(subTree->leftChild);

cout<<subTree->data;InOrder(subTree->rightChild

);

}}二叉树递归的中序遍历算法前序遍历(PreorderTraversal)--/+*abcdef遍历结果:

-+a*b

-

cd/efVLR前序遍历(PreorderTraversal)--/+*前序遍历二叉树算法的框架是:若二叉树为空,则空操作;否则访问根结点(V);前序遍历左子树(L);前序遍历右子树(R)。前序遍历二叉树算法的框架是:二叉树递归的前序遍历算法template<classType>voidBinaryTree<Type>::PreOrder(BinTreeNode<Type>*subTree){

if(subTree!=NULL){

cout<<subTree->data;PreOrder(subTree->leftChild);PreOrder(subTree->rightChild);

}}二叉树递归的前序遍历算法后序遍历(PostorderTraversal)--/+*abcdef遍历结果:

abcd

-*+ef/-

LRV后序遍历(PostorderTraversal)--/+后序遍历二叉树算法的框架是:若二叉树为空,则空操作;否则后序遍历左子树(L);后序遍历右子树(R);访问根结点(V)。后序遍历二叉树算法的框架是:二叉树递归的后序遍历算法template<classType>voidBinaryTree<Type>::PostOrder(BinTreeNode<Type>*subTree){

if(subTree!=NULL){

PostOrder(subTree->leftChild);PostOrder(subTree->rightChild);

cout<<subTree->data;

}}二叉树递归的后序遍历算法template<classType>voidBinaryTree<Type>::InOrder(){InOrder(root);}template<classType>voidBinaryTree<Type>::PreOrder(){PreOrder(root);}template<classType>voidBinaryTree<Type>::PostOrder(){PostOrder(root);}template<classType>关于树的性质:1.对于一棵具有n个结点的树,该树中所有结点的度数之和为:

2.假定一棵三叉树的结点个数为50,则它的最小高度为,最大高度为。3.在一棵二叉树中,假定度为2的结点有5个,度为1的结点有6个,则叶子结点数有个n-14496关于树的性质:n-144961.利用二叉树后序遍历计算二叉树结点个数template<classType>intBinaryTree<Type>::Count(BinTreeNode<Type>*t)const{

if(t==NULL)return0;

else

return

1+Count(t->leftChild)+Count(t->rightChild);}应用二叉树遍历的实例

1.利用二叉树后序遍历计算二叉树结点个数template以递归方式建立二叉树。输入结点值的顺序必须对应二叉树结点前序遍历的顺序。并约定以输入序列中不可能出现的值作为空结点的值以结束递归,此值在RefValue中。例如用“@”或用“-1”表示字符序列或正整数序列空结点。2.利用二叉树前序遍历建立二叉树以递归方式建立二叉树。2.利用二叉树前序遍历建立二叉树如图所示的二叉树的前序遍历顺序为:ABC@@DE@G@@F@@@ABCDEGF@@@@@@@@如图所示的二叉树的前序遍历顺序为:ABCDEGF@@@@@@

template<classType>voidBinaryTree<Type>::CreateBinTree(ifstream&in,BinTreeNode<Type>*&

subTree){//私有函数:以递归方式建立二叉树。//输入结点值的顺序必须对应二叉树结点前//序遍历的顺序。并约定以输入序列中不可//能出现的值作为空结点的值以结束递归,//此值在RefValue中。例如用“@”或用“-1”//表示字符序列或正整数序列空结点。

Typeitem;

if(!in.eof()){template<classType>

in>>item;

//读入根结点的值

if(item!=RefValue){

subTree=newBinTreeNode<Type>

(item);

//建立根结点

if(subTree==NULL)

{

cerr<<“存储分配错!”<<endl;exit(1);}CreateBinTree(in,subTree->leftChild);CreateBinTree(in,subTree->rightChild);

}elsesubTree=NULL;//封闭叶结点

}}in>>item; //读入根结点的二叉树遍历的非递归算法1)后序遍历的非递归算法structSTKNode

{

BinTreeNode<Type>*ptr;}senuntag{L,R};//tag=L,表示从左子树退回还要遍历右子树;//tag=R,表示从右子树退回要访问根结点。

二叉树遍历的非递归算法1)后序遍历的非递归算法struct算法思想:将栈s初始化,然后令指针p指向二叉树的根结点,即p=T.

如果指向根结点的指针不为空,先将tag置L;再将tag和根结点一起送入栈中;然后将指针指向该结点的左子树根结点;继续遍历。如果指向根结点的指针为空,则将栈顶存放的数据项出栈,有两种情况:若tag=L,则改变tag的值,将tag置R;再把tag和弹出的结点重新入栈;然后将指针指向该结点的右子树根结点,继续遍历。若tag=R,则访问弹出的结点,并将弹出的指针置为空直到栈为空并且指针为空时,遍历结束。算法思想:template<classT>voidBinaryTree<T>::PostOrder(void(*visit)(BinTreeNode<T>*p){Stack<stkNode<T>>S;stkNode<T>w;BinTreeNode<T>*p=root;//p是遍历指针

do{ while(p!=NULL){ w.ptr=p;w.tag=L;S.Push(w); p=p->leftChild;} } intcontinue1=1; //继续循环标记,用于Rwhile(continue1&&!S.IsEmpty()){ S.Pop(w);p=w.ptr; switch(w.tag){ //判断栈顶的tag标记

caseL:w.tag=R;S.Push(w); continue1=0; p=p->rightChild;break; caseR:visit(p);break; } }}while(!S.IsEmpty()); //继续遍历其他结点

cout<<endl;};template<classT>另一版本实现:voidpostorder(BinTreeNode<Type>*T){stack<STKNode<Type>>s(10);

STKNode<Type>Cnode;

BinTreeNode<Type>*p=T;do{while(p!=NULL){Cnode.ptr=p;Cnode.tag=L;s.push(Cnode);

p=p->leftchild;}

Cnode=s.pop();p=Cnode.ptr;

第-5章-树--数据结构课件while(Cnode.tag==R){cout<<p->data;if(!s.IsEmpty()){Cnode=s.pop();p=Cnode.ptr;}elsereturn;}

Cnode.tag=R;s.push(Cnode);

p=p->rightchild;}while(p!=NULL||!s.IsEmpty())}while(Cnode.tag==R)aLbLaLbRaLdLbRaLdRbRaLbRaLaLaReLcLaReRcLaRcLaRcRaRaRabcdeaLbLbRdLdRbRaLaReLeRcLcRaRabcdpostorder算法分析

时间复杂性入、出栈:O(n)访问结点:O(n)总的时间复杂度:O(n)空间复杂性O(k),k为树的高度postorder算法分析时间复杂性O(n)访问结点:O(二叉树遍历的非递归算法(cont.)2)中序遍历的非递归算法栈中:用以存放待访问的根结点指针,以备在访问该结点的左子树之后再访问该结点及其右子树。二叉树遍历的非递归算法(cont.)2)中序遍历的非递归算法算法思想

将栈s初始化,令指针p指向二叉树的根结点,即p=T.如果指向根结点的指针不为空或栈非空,则:(1)如果指向根结点的指针非空,则将根结点指针进栈,然后将指针指向该结点的左子树根结点,继续遍历

(2)如果指向根结点的指针为空,则将栈顶存放的数据项出栈,有两种情况:若从左子树返回,则应该访问当前层根结点,然后将指针指向该结点的右子树根结点,继续遍历;若从右子树返回,则表明当前层遍历结束,应该继续退栈。(3)当指针为空并且栈为空时,遍历结束。算法思想将栈s初始化,令指针p指向二叉树的根结点,即p=Tvoidinorder(BinTreeNode<Type>*T){stack<BinTreeNode<Type>*>s(10);

BinTreeNode<Type>*p=T;while(p||!s.IsEmpty()){while(p!=NULL){s.push(p);

p=p->leftchild;}if(!s.IsEmpty()){p=s.pop();cout<<p->data;

p=p->rightchild;

}elsereturn;}}voidinorder(BinTreeNode<Typacdebaadaa左空退栈访问左空退栈访问退栈访问左空ec退栈访问cc右空退栈访问栈空结束abcde利用栈的中序遍历非递归算法acdebada左空退栈左空退栈退栈左空e退栈访问cc右空退inorder算法分析

时间复杂性入、出栈:访问结点:总的时间复杂度:O(n)O(n)O(n)空间复杂性O(k),k为树的高度inorder算法分析时间复杂性O(n)O(n)O(n)空二叉树遍历的非递归算法(cont.)3)前序遍历的非递归算法需要栈吗?栈中结点的pop和push二叉树遍历的非递归算法(cont.)3)前序遍历的非递归算法访问p->data后,将p入栈,遍历左子树;遍历完左子树返回时,栈顶元素p出栈,再先序遍历p的右子树。访问p->data后,将p->rchild入栈,遍历左子树;遍历完左子树返回时,栈顶元素p->rchild出栈,遍历以该指针为根的子树。

算法思想两种方法:假设p是要遍历树的根指针,若p

!=

NULL访问p->data后,将p入栈,遍历左子树;遍历完左子树返回template<classT>voidBinaryTree<T>::PreOrder(void(*visit)(BinTreeNode<T>*t)){stack<BinTreeNode<T>*>S;BinTreeNode<T>*p=root;S.Push(NULL); while(p!=NULL){ visit(p); //访问结点

if(p->rightChild!=NULL)S.Push(p->rightChild);//预留右指针在栈中

if(p->leftChild!=NULL)p=p->leftChild; //进左子树

elseS.Pop(p); //左子树为空

}};template<classT>cabcdedcc访问a进栈c左进b访问b进栈d左进空退栈d访问d左进空退栈c访问c左进e访问e左进空栈空结束利用栈的前序遍历非递归算法cabcdedc访问访问退栈退栈访问利用栈的前序遍历非递归算遍历顺序abcdef--+/*层次序遍历二叉树的算法层次序遍历二叉树就是从根结点开始,按层次逐层遍历遍历顺序abcdef--+/*层次序遍历二叉树的算法层次序遍这种遍历需要使用一个先进先出的队列,在处理上一层时,将其下一层的结点直接进到队列(的队尾)。在上一层结点遍历完后,下一层结点正好处于队列的队头,可以继续访问它们。算法是非递归的。这种遍历需要使用一个先进先出的队列,在处理上一层时,将其下一abcdeQa访问a,进队Qa出队访问b,进队访问c,进队bcQb出队访问d,进队cdQc出队访问e,进队deQd出队eQe出队abcdeQa访问a,进队Qa出队bcQb出队cdQc出队层次序遍历的(非递归)算法template<classT>voidBinaryTree<T>::levelOrder(void(*visit)(BinTreeNode<T>*t)){if(root==NULL)return;Queue<BinTreeNode<T>*>Q;BinTreeNode<T>*p=root;visit(p);Q.EnQueue(p); while(!Q.IsEmpty()){Q.DeQueue(p);if(p->leftChild!=NULL){visit(p->leftChild);Q.EnQueue(p->leftChild);}if(p->rightChild!=NULL){visit(p->rightChild);Q.EnQueue(p->rightChild);}}};

层次序遍历的(非递归)算法template<classT二叉树的建立通过算法递归地实现——已知一棵二叉树的前序序列和中序序列,可以唯一地确定一棵二叉树;——已知一棵二叉树的中序序列和后序序列,可以唯一地确定一棵二叉树;由广义表建立二叉树的建立通过算法递归地实现由前序序列和中序序列,建立二叉树的递归算法private:BinTreeNode<Type>*CreateBT(stringpres,ins){intInpos;

string

Prestemp,Instemp;if(pres.length()==0)T=NULL;else{

temp=new

BinTreeNode;

temp->data=pres.ch[0];Inspos=0;

while

(Ins.ch[Inpos]!=T->data)Inpos++;

由前序序列和中序序列,建立二叉树的递归算法private:

prestemp=pres(1,Inpos);

Instemp=ins(0,Inpos-1);

temp->leftchild=CreateBT(prestemp,Instemp);prestemp=pres(Inpos+1,pres.length()-Inpos-1);

Instemp=Ins(Inpos+1,pres.length()-Inpos-1);

temp->rightchild=CreateBT(prestemp,Instemp);returntemp;}}prestemp=pres(1,Inpos);由广义表建立二叉树HADBFCEFA(B(C,F(H)),D(E(,F)))广义表由广义表建立二叉树HADBFCEFA(B(C,F(H)),D二叉树对应的广义表有如下规定:每棵树的根结点作为由子树构成的表的名字而放在表的前面;每一个结点的左右子树用“,”分开,若只有右子树而没有左子树,则逗号不能省略;在广义表后面加一特殊符号‘@’作为结束标志。A(B(C,F(H)),D(E(,F)))@二叉树对应的广义表有如下规定:A(B(C,F(H)),D(E算法思想:遇到字母,则表明是结点的值,为它建立新结点;若该结点不是整个树的根,还应该作为左子女(k=1)或右子女(k=2)链接到其双亲结点;遇到“(”,则表明子表开始,把刚刚建立的结点的指针进栈(为了括号内孩子结点指向双亲结点用,并置k=1)遇到“)”,则表明子表结束,应退栈遇到“,”,表示以左孩子为根的子树已处理完毕,应接着处理以右孩子为根的子树,k=2A(B(C,F(H)),D(E(,F)))@算法思想:A(B(C,F(H)),D(E(,F)))@voidCreateBT(BTreeNode*BT,char*a)//a为广义表表示{BinTreeNode*s[10];//作为存储二叉树中根结点指针的栈使用

inttop=-1;BT=NULL;BinTreeNode*p;intk;//k=1,处理左子树;k=2,处理右子树

istrstreamins(a);//把字符串a定义为输入字符串流对象inscharch;ins>>ch;while(ch!=‘@’)具体算法:voidCreateBT(BTreeNode*BT,c{switch(ch){case’(’:top++;s[top]=p;k=1;break;case‘)’:top--;break;case‘,’:k=2;break;default:p=newBinTreeNode;p->data=ch;p->leftchild=p->rightchild=NULL;if(BT==NULL)BT=p;else{if(k==1)s[top]->leftchild=p;elses[top]->rightchild=p;}}//switchendins>>ch;}//whileend}A(B(C,F(H)),D(E(,F)))@{switch(ch)A(B(C,F(H)),D(E(,二叉树的计数由前知:由二叉树的前序序列和中序序列可唯一地确定一棵二叉树。有n个结点的不同的二叉树有多少种?二叉树的计数由前知:由二叉树的前序序列和中序序列可唯一地确定612345789前序排列:123456789中序排列:325416879612375849前序排列:123456789中序排列:435217689612345789前序排列:12345678问题:固定前序排列,选择所有可能的中序排列,可能构造多少种不同的二叉树?如果我们能够做到结点编号的前序排列正好是1,2,3,…,n,那么,这棵二叉树有多少中序排列,就能确定多少棵不同的二叉树。当二叉树的前序排列为1,2,3,…,n时,可能有多少种中序排列?问题:固定前序排列,选择所有可能的中序排列,可能构造多少可得5种不同的二叉树。它们的前序排列均为

123,中序序列可能是123,132,213,231,321。123123123123123若用表示进栈表示出栈例如,有3个数据{1,2,3}可得5种不同的二叉树。它们的前序排列均为123,中序序

有0个,1个,2个,3个结点的不同二叉树如下:b0=1b1=1b2=2b3=5求解不同的二叉树棵数设bn表示有n个结点的不同的二叉树棵数。当n很小时,有0个,1个,2个,3个结点的不同二叉树如下:计算具有n个结点的不同二叉树的棵数Catalan函数bibn-i-11计算具有n个结点的不同二叉树的棵数Catalan函数bi5.5线索二叉树5.5线索二叉树线索(Thread):指示前驱和后继的指针线索化二叉树(ThreadedBinaryTree):加了线索的二叉树线索(Thread):指示前驱和后继的指针线索化二叉树(T两种方法:1)原有二叉树的结构中,增加两个链域;2)利用空链域

如果结点有左孩子,则其leftchild指示其左孩子;否则指示其前驱如果结点有右孩子,则其rightchild指示其右孩子;否则指示其后继设置两个标志:LeftThreadRightThread两种方法:如果结点有左孩子,则其leftchild指示其左线索化二叉树及其二叉链表表示LeftThread=0,LeftChild为左子女指针LeftThread=1,LeftChild为前驱线索RightThread=0,RightChild为右子女指针RightThread=1,RightChild为后继指针LeftChildRightChilddataLeftThreadRightThread线索化二叉树及其二叉链表表示LeftThread=0,中序线索化二叉树的例子中序线索化二叉树的例子带表头结点的中序穿线链表原来的线索化二叉树成为表头结点的左子树带表头结点的中序穿线链表原来的线索化二叉树成为表头结点的左子template<classType>classThreadNode

{

friendclassThreadTree<Type>; private:

intleftThread,rightThread;ThreadNode<Type>*leftChild,*rightChild;

Typedata; public:

ThreadNode(constTypeitem)

:data(item),leftChild(NULL),rightChild(NULL),leftThread(0),rightThread(0){}};中序线索化二叉树的类定义template<classType>classThreadTree;

template<classType>classThtemplate<classType>classThreadTree{

private:ThreadNode<Type>*root;//根

InThread(ThreadNode<Type>*current,

ThreadNode<Type>*&pre

);//建树public:ThreadTree():root(NULL){};//构造函数

ThreadNode<Type>*

First(ThreadNode<Type>*current);

ThreadNode<Type>*

Last(ThreadNode<Type>*current);

template<classType>classTh

ThreadNode<Type>*Next(ThreadNode<Type>*current);ThreadNode<Type>*Prior(ThreadNode<Type>*current);…………}ThreadNode<Type>*if(current->rightThread==1)

后继为current->rightChildelse

//current->rightThread!=1

后继为当前结点右子树的中序下的第一个结点(最左下)

寻找当前结点在中序下的后继ABDECFHIKGJif(current->rightThread==1)if(current->leftThread==1)

前驱为current->leftChildelse

//current->leftThread==0

前驱为当前结点左子树

中序下的最后一个结点(最右下)

寻找当前结点在中序下的前驱ABDECFHIKGJLif(current->leftThread==1通过中序遍历建立中序线索化二叉树template<classType>voidThreadTree<Type>::InThread(ThreadNode<Type>*current,ThreadNode<Type>*&pre){if(current!=NULL){ InThread(current->leftChild,pre);

//递归,左子树线索化

if(current->leftChild==NULL){

current->leftChild=pre;

current->leftThread=1;

}//建立当前结点的前驱线索

通过中序遍历建立中序线索化二叉树template<clasif(pre!=NULL&&pre->rightChild==NULL){

pre->rightChild=current;

pre->rightThread=1;}//建立前驱结点的后继线索

pre=current; //前驱跟上当前指针

InThread(current->rightChild,pre);

//递归,右子树线索化

}}if(pre!=NULL&&template<classT>voidThreadTree<T>::createInThread(ThreadNode<T>*current,ThreadNode<T>*&pre){//通过中序遍历,对二叉树进行线索化

if(current==NULL)return;createInThread(current->leftChild,pre);

//递归,左子树线索化

if(current->leftChild==NULL){ //建立当前结点的前驱线索

current->leftChild=pre;current->ltag=1;}template<classT>if(pre!=NULL&&pre->rightChild==NULL) //建立前驱结点的后继线索

{pre->rightChild=current;pre->rtag=1;} pre=current; //前驱跟上,当前指针向前遍历

createInThread(current->rightChild,pre); //递归,右子树线索化};if(pre!=NULL&&pre->r0A00B00C00D00E0rootpre==NULLcurrent0A00B00A0

1B00C00D00E0rootpre==NULLcurrent0A01B00A0

1B00C0

1D00E0rootprecurrent0A01B00A0

1B00C0

1D1

0E0rootprecurrent0A01B00A0

1B00C0

1D1

1E0rootprecurrent0A01B00A0

1B00C0

1D1

1E1

rootprecurrent0A01B00A0

1B00C1

1D1

1E1

rootpre后处理0A01B0在中序线索化二叉树中部分成员函数的实现template<classType>

ThreadNode<Type>*

ThreadTree<Type>::First(ThreadNode<Type>*current){//函数返回以*current为根在线索化二叉树中//的中序序列下的第一个结点

ThreadNode<Type>*p=current;

while(p->leftThread==0)p=p->leftChild;

//最左下的结点

returnp;}在中序线索化二叉树中部分成员函数的实现template<classType>ThreadNode<Type>*ThreadTree<Type>::Next(ThreadNode<Type>*current){//函数返回在线索化二叉树中结点*current在//中序下的后继结点

ThreadNode<Type>*p=current->rightChild;

if(current->rightThread==0)returnFirst(p);

//rightThread==0,表示有右子女

else

returnp; //rightThread==1,直接返回后继线索}

template<classType>template<classType>voidThreadTree<Type>::Inorder(){//线索化二叉树的中序遍历

ThreadNode<Type>*p;for(p=First();p!=NULL;p=Next())

cout<<p->data<<endl;}template<classType>void前序线索化二叉树前序序列

ABDCE前序线索化二叉树前序序列在前序线索化二叉树中寻找当前结点的后继在前序线索化二叉树中在前序线索化二叉树中寻找当前结点的前驱在前序线索化二叉树中后序线索化二叉树后序序列

DBECA在后序线索化二叉树中寻找当前结点的后继后序线索化二叉树后序序列在后序线索化二叉树中遍历二叉树,并将其中序线索化遍历二叉树,并将其中序线索化template<classType>voidThreadTree<Type>::CreateInThread

(){

ThreadNode<Type>*pre;

root=newThreadNode<Type>;//创建根结点

root→leftThread=1;root→rightThread=0;if(this==NULL){//空二叉树

root→leftChild=root;

root→rightChild=root;}else{

current=root→leftChild=this;

root→leftThread=0;

pre=root;

InThread(current,pre);

pre→rightChild=root;pre→rightThread=1;}}template<classType>voidtemplate<classType>voidThreadTree<Type>::InThread(ThreadNode<Type>*current,ThreadNode<Type>*&pre){if(current!=NULL){ InThread(current->leftChild,pre);

//递归,左子树线索化

if(current->leftChild==NULL){

current->leftChild=pre;

current->leftThread=1;

}//建立当前结点的前驱线索

if(pre!=NULL&&pre->rightChild==NULL){

pre->rightChild=current;

pre->rightThread=1;}//建立前驱结点的后继线索

pre=current; //前驱跟上当前指针

InThread(current->rightChild,pre);//递归,右子树线索化

}}template<classType>中序线索化二叉树的操作插入删除中序线索化二叉树的操作插入插入将值为r的新结点插入到中序线索二叉树中作为右子女插入作为左子女插入原则:必须修改原有的前驱,后继线索,使整个原有的中序序列不但能够保留,而且新结点插入后也能正确地排入这个序列sr插入将值为r的新结点插入到中序线索二叉树中原则:必须修改原有srs无右子女s有右子女以该右子女为根的子树成为r的右子树作为右子女插入srs无右子女以该右子女为根的子树成为r的右子树作为右子女插作为左子女插入srs无左子女s有左子女作为左子女插入srs无左子女前序线索化二叉树前序序列

ABDCE前序线索化二叉树前序序列在前序线索化二叉树中寻找当前结点的后继在前序线索化二叉树中在前序线索化二叉树中寻找当前结点的前驱在前序线索化二叉树中后序线索化二叉树后序序列

DBECA在后序线索化二叉树中寻找当前结点的后继后序线索化二叉树后序序列在后序线索化二叉树中树的存储表示树的广义表表示5.6树与森林ABCDEFG叶结点分支结点根结点广义表原子结点子表结点表头结点树的存储表示树的广义表表示5.6树与森林ABCDEFG叶结父指针表示法ABCDEFGdataparentABCDEFG-10001130123456父指针表示法ABCDEFGdataparentABABCDEFG适用于:等数量的链域ABCDEFG每个结点包含的指针个数相等,等于树的度(degree)子女指针表示法

datachild1child2child3childdABCDEFG适用于:等数量的链域ABCDEFG子女链表表示无序树情形链表中各结点顺序任意,有序树必须自左向右链接各个子女结点。ABCDEFG123∧45∧6∧∧∧∧∧ABCDEFG012345

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论