树和二叉树.docx

上传人:b****7 文档编号:8789601 上传时间:2023-02-01 格式:DOCX 页数:23 大小:22.68KB
下载 相关 举报
树和二叉树.docx_第1页
第1页 / 共23页
树和二叉树.docx_第2页
第2页 / 共23页
树和二叉树.docx_第3页
第3页 / 共23页
树和二叉树.docx_第4页
第4页 / 共23页
树和二叉树.docx_第5页
第5页 / 共23页
点击查看更多>>
下载资源
资源描述

树和二叉树.docx

《树和二叉树.docx》由会员分享,可在线阅读,更多相关《树和二叉树.docx(23页珍藏版)》请在冰豆网上搜索。

树和二叉树.docx

树和二叉树

第六章树和二叉树

6.1树的类型定义

数据对象D:

D是具有相同特性的数据元素的集合。

数据关系R:

若D为空集,则称为空树;

否则:

(1)在D中存在唯一的称为根的数据元素root,

(2)当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1,T2,…,Tm,其中每一棵子集本身又是一棵符合本定义的树,称为根root的子树。

基本操作:

查找:

Root(T);Value(T,cur_e);Parent(T,cur_e);

LeftChild(T,cur_e);RightSibling(T,cur_e);

TreeEmpty(T);TreeDepth(T);

TraverseTree(T,Visit());

插入:

InitTree(&T);CreateTree(&T,definition);

Assign(T,cur_e,value);

InsertChild(&T,&p,i,c);

删除:

ClearTree(&T);DestroyTree(&T);

DeleteChild(&T,&p,i);

DestroyTree(&T);

有向树:

1)有确定的根;

2)树根和子树根之间为有向关系

有序树和无序树的区别在于:

子树之间是否存在次序关系?

和线性结构的比较

线性结构树结构

第一个数据元素根结点

(无前驱)(无前驱)

最后一个数据元素多个叶子结点

(无后继)(无后继)

其它数据元素树中其它结点

(一个前驱、一个后继)(一个前驱、多个后继)

基本术语

结点:

数据元素+若干指向子树的分支

结点的度:

分支的个数

树的度:

树中所有结点的度的最大值

叶子结点:

度为零的结点

分支结点:

度大于零的结点

从根到结点的路径:

孩子结点、双亲结点、兄弟结点、

祖先结点、子孙结点

结点的层次:

假设根结点的层次为1,

第l层的结点的子树根结点的层次为l+1

树的深度:

树中叶子结点所在的最大层次

森林:

是m(m≥0)棵互不相交的树的集合

任何一棵非空树是一个二元组

Tree=(root,F)

其中:

root被称为根结点,F被称为子树森林

6.2二叉树的类型定义

二叉树或为空树;或是由一个根结点加上两棵分别称为左子树和右子树的、互不相交的二叉树组成。

二叉树的五种基本形态:

..\..\..\flash\二叉树的建立演示.swf

二叉树的主要基本操作:

查找:

Root(T);Value(T,e);Parent(T,e);

LeftChild(T,e);RightChild(T,e);

LeftSibling(T,e);RightSibling(T,e);

BiTreeEmpty(T);BiTreeDepth(T);

PreOrderTraverse(T,Visit());

InOrderTraverse(T,Visit());

PostOrderTraverse(T,Visit());

LevelOrderTraverse(T,Visit());

插入:

InitBiTree(&T);Assign(T,&e,value);

CreateBiTree(&T,definition);

InsertChild(T,p,LR,c);

删除:

ClearBiTree(&T);DestroyBiTree(&T);

DeleteChild(T,p,LR);

二叉树的重要特性:

性质1:

在二叉树的第i层上至多有2i-1个结点

(i≥1)

性质2:

深度为k的二叉树上至多含2k-1个结点

(k≥1)

性质3:

对任何一棵二叉树,若他含有n0个叶子结点、n2个度为2的结点,则必存在关系式:

n0=n2+1

两类特殊的二叉树:

满二叉树:

指的是深度为k且含有2k-1个结点的二叉树

完全二叉树:

树中所含的n个结点和满二叉树中编号为1至n的结点一一对应

性质4:

具有n个结点的完全二叉树的深度为

log2n+1

性质5:

若对含n个结点的二叉树从上到下且从左至右进行1至n的编号,则对二叉树中任意一个编号为i的结点:

(1)若i=1,则该结点是二叉树的根,无双亲,

否则,编号为i/2的结点为其双亲结点;

(2)若2i>n,则该结点无左孩子,

否则,编号为2i的结点为其左孩子结点;

(3)若2i+1>n,则该结点无右孩子结点,

否则,编号为2i+1的结点为其右孩子结点。

6.3二叉树的存储结构

一、二叉树的顺序存储表示

classBiTree

{

private:

ArraySqBiTree;

}

显然,这种顺序存储结构仅适用于完全二叉树。

因为,在最坏的情况下,一个深度为k且只有k个结点的单支树(树中不存在度为2的结点)却需要长度为2k-1的一维数组。

二、二叉树的链式存储表示

1.二叉链表

template

classBiTreeNode//二叉树的结点

{

protected:

BiTreeNode*lchild;

//指向左子树的指针

BiTreeNode*rchild;

//指向右子树的指针

public:

Elem*data;

//constructor

TreeNode(constElem&item,

BiTreeNode*lptr=NULL,

BiTreeNode*rptr=NULL);

//virtualdestructor.neededforAVLtreeclass

virtual~TreeNode(void);

//accessmethodsforthepointerfields

BiTreeNode*Left(void)const;

BiTreeNode*Right(void)const;

voidAssignLeft(TreeNode*p);

voidAssignRight(TreeNode*p);

//BinSTreeneedsaccesstoleftandright

friendclassBinSTree;

};

2.三叉链表

protected:

BiTreeNode*lchild;

//指向左子树的指针

BiTreeNode*rchild;

//指向右子树的指针

BiTreeNode*parent;

//指向双亲的指针

3.双亲链表

protected:

BiTreeNode*parent;

//指向双亲的指针

charLRTag;//指示左右的标志

4.线索链表

6.4二叉树的遍历

一、问题的退出

顺着某一条搜索路径巡访二叉树中的结点,使得每个结点均被访问一次,而且仅被访问一次。

“访问”的含义可以很广,如:

输出结点的信息等。

对“二叉树”而言,可以有三条搜索路径:

1.先上后下的按层次遍历;

2.先左(子树)后右(子树)的遍历;

3.先右(子树)后左(子树)的遍历。

二、先左后右的遍历算法

先(根)序的遍历算法:

若二叉树为空树,则空操作;否则,

(1)访问根结点;

(2)先序遍历左子树;

(3)先序遍历右子树。

中(根)序的遍历算法:

若二叉树为空树,则空操作;否则,

(1)中序遍历左子树;

(2)访问根结点;

(3)中序遍历右子树。

后(根)序的遍历算法:

若二叉树为空树,则空操作;否则,

(1)后序遍历左子树;

(2)后序遍历右子树;

(3)访问根结点。

 

三、算法的递归描述

//preorderrecursivescanofthenodesinatree.

template

voidPreorder(TreeNode*t,

voidvisit(Elem&item))

{

if(t!

=NULL)

{

visit(t->data);//访问结点

Preorder(t->Left(),visit);//遍历左子树

Preorder(t->Right(),visit);//遍历右子树

}

}

四、中序遍历算法的非递归描述

//returnaddressoflastnodeontheleftbranch//fromt,stackingnodesontheway.usedfor

//iterativeinorderscan.templateTreeNode

*GoFarLeft(TreeNode*t,

Stack*>&S){if(t==NULL)returnNULL;while(t->Left()!

=NULL)

{

S.Push(t);

t=t->Left();

}

returnt;

}

//inorderiterativescan

template

voidInorder_I(TreeNode*t,

voidvisit(Elem&c))

{

Stack*>S;

t=GoFarLeft(t,S);

//continueuntiltisNULL

while(t!

=NULL)

{

visit(t->data);

if(t->Right()!

=NULL)

t=GoFarLeft(t->Right(),S);

elseif(!

S.StackEmpty())

t=S.Pop();

else

t=NULL;//wearedone

}

}

五、遍历算法的应用举例:

1、统计二叉树中叶子结点的个数

//先序遍历

template

voidCountLeaf(TreeNode*t,

int&count)

{

if(t!

=NULL)

{

if(t->Left()==NULL&&

t->Right()==NULL)count++;

CountLeaf(t->Left(),count);

CountLeaf(t->Right(),count);

}

}

2、求二叉树的深度(后序遍历)

template

intDepth(TreeNode*t)

{

intdepthLeft,depthRight,depthval;

if(t==NULL)

depthval=0;

else

{

depthLeft=Depth(t->Left());

depthRight=Depth(t->Right());

depthval=1+(depthLeft>depthRight?

depthLeft:

depthRight);

}

returndepthval;

}

 

3、复制二叉树

//生成一个二叉树的结点

templateTreeNode*GetTreeNode(Elemitem,

TreeNode*lptr=NULL,TreeNode*rptr=NULL){TreeNode*p;p=newTreeNode(item,lptr,rptr);

if(p==NULL){

exit

(1);

}

returnp;

}

template

TreeNode

*CopyTree(TreeNode*t)

{

TreeNode*newlptr,*newrptr,*newnode;

if(t==NULL)returnNULL;

if(t->Left()!

=NULL)

newlptr=CopyTree(t->Left());

elsenewlptr=NULL;

if(t->Right()!

=NULL)

newrptr=CopyTree(t->Right());

elsenewrptr=NULL;

newnode=

GetTreeNode(t->data,newlptr,newrptr);

returnnewnode;

}

 

4、建立二叉树的存储结构

TreeNode*crtTree(char*str,int&i)

{//建立由字符串str[i..n]定义的二叉树,str[i]为根

TreeNode*t;

charCh=str[i];

if(Ch=='')t=NULL;

else

{

t=GetTreeNode(Ch);//creattherootnode

i++;

t->AssignLeft(crtTree(str,i));

i++;

t->AssignRight(crtTree(str,i));

}

returnt;

}

建表达式的树

由先缀表示式建树

由原表达式建树

a+bc(de/f)g

TreeNode*crtTree(char*str)

{

TreeNode*t;

Stack*>SD;

StackSP;

SP.Push();

p=str;ch=*p;

while(!

SP.StackEmpty()){

if(ch是字母){建叶子结点t;SD.Push(t);

else{

switch(ch){

case(:

SP.Push(ch);break;

case):

{

c=SP.Pop();

while(c!

=()

{建二叉树t;SD.Push(t);c=SP.Pop();}

break;}

defult:

{

while(!

SP.Gettop(c)&&(precede(c,ch)))

{c=SP.Pop();建二叉树t;SD.Push(t);}

if(ch!

=)SP.Push(ch);

elsec=SP.Pop();

break;

}//defult

}//switch

}//else

if(ch!

=){p++;ch=*p;}

}//while

t=SD.Pop();returnt;

}//crtTree

由表达式的先缀和中缀表示式建树

abcdefg

abcdefg

6.5线索二叉树

一、何谓线索二叉树?

在存储结构中保存遍历所得“前驱”和“后继”的信息

线索链表:

对二叉链表的结点增加两个标志域,并作如下规定:

若该结点的左子树不空,则lchild域的指针指向其左子树,且左标志域的值为0;否则,lchild域的指针指向其“前驱”,且左标志的值为1.

若该结点的右子树不空,则rchild域的指针指向其右子树,且右标志域的值为0;否则,rchild域的指针指向其“后继”,且右标志的值为1.

线索链表的结点类:

template

classThrNode

{

protected:

PointerTagltag;

PointerTagrtag;

ThrNodelchild;

TheNoderchild;

}

 

线索链表的遍历算法:

for(p=firstNode(T);p;p=Succ(p))

Visit(p);

中序线索化链表的遍历算法:

..\..\..\flash\中序线索化二叉树演示.swf

..\..\..\flash\寻找中序线索化二叉树指定结点的前趋演示.swf

※中序遍历的第一个结点?

※在中序线索化链表中结点的后继?

..\..\..\flash\寻找中序线索化二叉树指定结点的后继演示.swf

template

voidInOrderTraverse_Thr(ThrNode*T,voidVisit(Elem&item))

{

//t指向头结点,头结点的左链lchild指

//向根结点,头结点的右链rchild指向中

//序遍历的最后一个结点。

//中序遍历二叉线索链表表示的二叉树T。

p=T->Left();//p指向根结点

while(p!

=T)

{//空树或遍历结束时,p==T

while(p->LTG()==Link)p=p->Left();

Visit(p->data);

//访问其左子树为空的结点

while(p->RTG()==Thread&&p->Right()!

=T)

{

p=p->Right();Visit(p->data);

//访问后继结点

}

p=p->Right();//p进至其右子树根

}

}//InOrderTraverse_Thr

如何建立线索链表?

在中序遍历过程中保存当前访问结点的“前驱”和“后继”信息

template

ThrNode*InOrderThreading(ThrNode*T)

{

//中序遍历二叉树T,并对其进行中序线

//索化,Thrt指向线索化之后的头结点。

ThrNode*Thrt;

Thrt=GetThrNode(,Link,Thread);

//建头结点

Thrt->AssignRight(Thrt);//右指针回指

if(T==NULL)Thrt->AssignLeft(Thrt);

//若二叉树空,则左指针回指

else

{

Thrt->AssignLeft(T);pre=Thrt;

InThreading(T);//中序遍历进行中序线索化

pre->AssignRight(Thrt);

pre->AssignRTag(Thread);

//最后一个结点线索化

Thrt->AssignRight(pre);

}

returnThrt;

}//InOrderThreading

附设指针pre,并始终保持指针pre指向当前访问的、指针p所指结点的前驱

template

voidInThreading(ThrNode*p)

{

if(p)

{

InThreading(p->Left());//左子树线索化

if(!

p->Left())

{

p->AssignLTag(Thread);

p->AssignLeft(pre);

}//建前驱线索

if(!

pre->Right())

{

pre->AssignRTag(Thread);

pre->AssignRight(p);

}//建后继线索

pre=p;//保持pre指向p的前驱

InThreading(p->Right());//右子树线索化

}

}//InThreading

 

6.6树和森林的表示方法

树的三种存储结构

一、双亲表示法:

#defineMAX_TREE_SIZE100

结点结构:

typedefstructPTNode{

Elemdata;

intparent;//双亲位置域

}PTNode;

树结构:

typedefstruct{

PTNodenodes[MAX_TREE_SIZE];

intr,n;//根结点的位置和结点个数

}PTree;

二、孩子链表表示法:

孩子结点结构:

typedefstructCTNode{

intchild;

structCTNode*next;

}*ChildPtr;

双亲结点结构

typedefstruct{

Elemdata;

ChildPtrfirstchild;//孩子链的头指针

}CTBox;

树结构:

typedefstruct{

CTBoxnodes[MAX_TREE_SIZE];

intn,r;//结点数和根结点的位置

}CTree;

三、树的二叉链表(孩子-兄弟)存储表示法

template

classCSNode

{

protected

CSNode*firstchild,

CSNode*nextsibling;

public

Elemdata;

……

};

森林和二叉树的对应关系

设森林F=(T1,T2,…,Tn);

T1=(root,t11,t12,…,t1m);

二叉树B=(LBT,Node(root),RBT);

..\..\..\flash\树、森林与二叉树的转换演示.swf

则由森林转换成二叉树的转换规则为:

若F=Φ,则B=Φ;

否则,

由ROOT(T1)对应得到Node(root);

由(t11,t12,…,t1m)对应得到LBT;

由(T2,T3,…,Tn)对应得到RBT.

由二叉树转换为森林的转换规则为:

若B=Φ,则F=Φ;

否则,

由Node(root)对应得到ROOT(T1);

由LBT对应得到(t11,t12,…,t1m);

由RBT对应得到(T2,T3,…,Tn)

由此,树的

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1