树的学习.docx

上传人:b****5 文档编号:29384650 上传时间:2023-07-22 格式:DOCX 页数:107 大小:725.40KB
下载 相关 举报
树的学习.docx_第1页
第1页 / 共107页
树的学习.docx_第2页
第2页 / 共107页
树的学习.docx_第3页
第3页 / 共107页
树的学习.docx_第4页
第4页 / 共107页
树的学习.docx_第5页
第5页 / 共107页
点击查看更多>>
下载资源
资源描述

树的学习.docx

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

树的学习.docx

树的学习

树和二叉树

树形结构是非线性数据结构,其特点是数据元素只有一个前驱,但可以有零个或多个后继。

树,由结点和通向结点的分支组成,结点分层,除了第一层外,每个结点只有一个前驱,却可能有多个后继。

树是包含n(n>=0)个结点的有限结合。

树的递归定义刻画了树的固有特性,即一颗非空树是由若干棵子树构成的,而子树又可由若干棵更小的子树构成。

树的逻辑表示方法

1),二元组表示法

2),树形表示法

3),嵌套集合表示法

4),凹入表示法

5),广义表表示法

树的基本术语:

1),结点;2),结点的度;3),树的度;4),叶子结点;5),分支结点;6),双亲和孩子;7),兄弟和堂兄弟;8),路径;9),祖先和子孙;10),结点的层数;11),树的高度;12),有序树和无序树;13),森林

这些定义最好是记下来,反正我是没记下来,就没有都列举出来,书上应该都有的!

介绍几个概念:

结点(Node):

树中的元素,包含数据项及若干指向其子树的分支。

结点的度(Degree):

结点拥有的子树数。

叶子(Leaf):

度为零的结点,也称端结点。

孩子(Child):

结点子树的根称为该结点的孩子结点。

双亲(Parent):

孩子结点的上层结点,称为这些结点的双亲。

兄弟(Sibling):

同一双亲的孩子。

结点的层次:

从根结点开始算起,根为第一层。

深度(Depth):

树中结点的最大层次数。

森林(Forest):

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

二叉树

是n个结点的有限集,或者是空集,或者是由一个根节点及两颗互不相交的,分别称作这个根的左子树和右子树的二叉树组成。

 

树与二叉树的区别:

1),树的结点可以有任意有限棵子树,而二叉树的任一结点至多只有两颗子树;

2),树中各子树没有子树之间的次序,而二叉树中将两颗子树明确地规定为左子树和右子树,并且当二叉树中一颗子树为空时,另一颗子树非空时,也要明确地指出它们的左右次序。

二叉树的性质

二叉树具有下列重要性质:

性质1:

在二叉树的第i层上至多有2i-1个结点(i>=1)。

采用归纳法证明此性质。

当i=1时,只有一个根结点,2i-1=20=1,命题成立。

现在假定对于所有的j,1<=j

由归纳假设可知,第i-1层上至多有2i-2个结点。

由于二叉树每个结点的度最大为2,故在第i层上最大结点数为第i-1层上最大结点数的二倍,

即2×2i-2=2i-1。

命题得到证明。

性质2:

深度为k的二叉树至多有2k-1个结点(k>=1).

深度为k的二叉树的最大的结点数`为二叉树中每层上的最大结点数之和,由性质1得到每层上的最大结点数:

EkI=1(第i层上的最大结点数)=EkI=12i-1=2k–1

性质3:

对任何一棵二叉树,如果其终端结点数为n0,度为2的结点数为n2,则n0=n2+1。

设二叉树中度为1的结点数为n1,二叉树中总结点数为N,因为二叉树中所有结点均小于或等于2,所以有:

N=n0+n1+n2(6-1)

再看二叉树中的分支数,除根结点外,其余结点都有一个进入分支,设B为二叉树中的分支总数,则有:

N=B+1。

由于这些分支都是由度为1和2的结点射出的,所有有:

B=n1+2*n2

N=B+1=n1+2×n2+1(6-2)

由式(6-1)和(6-2)得到:

n0+n1+n2=n1+2*n2+1

n0=n2+1

性质4:

具有n个结点的完全二叉树的深度为【log2n】+1。

符号【x】表示不大于x的最大整数。

假设此二叉树的深度为k,则根据性质2及完全二叉树的定义得到:

2k-1-1

2k-1<=n<2k

取对数得到:

k-1<=log2n

所以有:

k=【log2n】+1。

性质5:

如果对一棵有n个结点的完全二叉树的结点按层序编号(从第1层到第【log2n】+1层,每层从左到右),则对任一结点i(1<=i<=n),有:

(1)如果i=1,则结点i无双亲,是二叉树的根;如果i>1,则其双亲是结点【i/2】。

(2)如果2i>n,则结点i为叶子结点,无左孩子;否则,其左孩子是结点2i。

(3)如果2i+1>n,则结点i无右孩子;否则,其右孩子是结点2i+1。

二叉树的存储结构

1.顺序存储结构

它是用一组连续的存储单元存储二叉树的数据元素。

因此,必须把二叉树的所有结点安排成为一个恰当的序列,结点在这个序列中的相互位置能反映出结点之间的逻辑关系,用编号的方法:

#defineMAX-TREE-SIZE100

typedefTElemTypeSqBiTree[MAX-TREE-SIZE];

SqBiTreebt;

从树根起,自上层至下层,每层自左至右的给所有结点编号缺点是有可能对存储空间造成极大的浪费,在最坏的情况下,一个深度为h且只有h个结点的右单支树确需要2h-1个结点存储空间。

而且,若经常需要插入与删除树中结点时,顺序存储方式不是很好!

或:

#defineMaxSize树中结点的最大数

typedefstruct{

intdata[MaxSize];

intnode;

}SqBitree;

SqBitreeBT;

BT就是一维数组,用它来存储一颗二叉树,每个数组元素存储二叉树的一个结点的数据信息。

2.链式存储结构

二叉树存储的链式结构可以使用二叉链表,它的每个结点有一个数据域和两个指针域,一个指针指向左孩子,另一个指针指向右孩子。

二叉链表的结点结构描述如下:

typedefstructnode{

chardata;

structnode*lchild,*rchild;

}BinNode,*BinTree;

给出一颗二叉树的二叉链表存储结构就是给出指向根结点的BinTree型头指针Root.

在二叉链表中,容易找到一个结点的左右孩子,但是不易找结点的双亲。

为了方便查找孩子和双亲,还可以使用三叉链表,其链表结点结构描述如下:

typedefstructnode{

chardata;

structnode*lchild,*rchild,*parent;

}BinList,*BinTree;

3.二叉树二叉链表的生成算法

1,非递归的朴素生成算法

根据二叉树的二叉链表存储结构,使用一种有辅助数组的创建二叉树的二叉链表的算法。

该算法利用了二叉树的性质5,对任意二叉树,先按满二叉树对其进行编号,然后按编号输入数据,构建二叉链表。

算法思想:

把非完全二叉树及诶单按对应的完全二叉树进行编号,此时结点的编号并不连续。

s[i]中应该存放编号为i的结点的地址指针。

/*

样例输入:

1A2B3C4D5E7F00

样例输出:

ABDECF

*/

#include

#include

typedefstructnode{

chardata;

structnode*lchild,*rchild;

}BinNode,*BinTree;

BinTreecreate(){

inti,j;

charx;

BinTrees[120],t=NULL,q;//t=NULL,定义指向根结点的指针

scanf("%d%c",&i,&x);

while(i!

=0&&x!

=0){//结束条件

q=(BinTree)malloc(sizeof(BinNode));//产生一个新结点

q->data=x;//赋结点值

q->lchild=NULL;//赋左孩子值

q->rchild=NULL;//赋有孩子值

s[i]=q;//用数组第i个单元存放指向此结点的指针

if(i==1)t=q;//若是第1个,将t指向它为根

else{//否则,为子树,计算子树的位置j

j=i/2;

if((i%2)==0)//j为偶数,是左子树

s[j]->lchild=q;

else//j为奇数,是右子树

s[j]->rchild=q;

}

scanf("%d%c",&i,&x);

}

returnt;//返回一个指向根的指针

}

voidprint(BinTreep){//先序输出二叉树

if(p!

=NULL){

printf("%c",p->data);

print(p->lchild);

print(p->rchild);

}

}

intmain(){

BinTreeroot;

root=create();//指针变量root指向一棵建立好的二叉树的二叉链表

print(root);

return0;

}

------------------------------------------------------------------------------------------------------------------------------

2,构造二叉链表的递归算法

根据二叉树的扩展先序序列,使用递归方法构造二叉链表

该算法中输入的数据是二叉树的扩展先序序列,即在先序序列中加入虚结点以示空指针的位置。

算法思想:

算法的输入是二叉树的扩展先序序列,首先输入一个根节点,若输入的是空格""字符,表示该二叉树为空树,即T=NULL;否则把输入的字符赋给T->data,之后,依次递归地建立它的左子树T->lchild和右子树T->rchild.

样例输入:

ABDECF

样例输出:

ABDECF

*/

#include

#include

typedefstructNode{

chardata;

structNode*lchild,*rchild;

}BinNode,*BinTree;

voidCreateBin(BinTree*T){

charch;

if((ch=getchar())=='')

*T=NULL;

else{

*T=(BinTree)malloc(sizeof(BinNode));

(*T)->data=ch;

CreateBin(&((*T)->lchild));

CreateBin(&((*T)->rchild));

}

}

voidprint(BinTreep){//先序输出二叉树

if(p!

=NULL){

printf("%c",p->data);

print(p->lchild);

print(p->rchild);

}

}

intmain()

{

BinTreeroot;

CreateBin(&root);

print(root);

return0;

}

------------------------------------------------------------------------------------------------------------------------------

一,二叉树的递归遍历算法:

假如以L、D、R分别表示遍历左子树、遍历根结点和遍历右子树,遍历整个二叉树则有DLR、LDR、LRD、DRL、RDL、RLD六种遍历方案。

若规定先左后右,则只有前三种情况,分别规定为:

DLR——先(根)序遍历,

LDR——中(根)序遍历,

LRD——后(根)序遍历。

1、先序遍历二叉树的操作定义为:

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

(1)访问根结点;

(2)先序遍历左子树;

(3)先序遍历右子树。

2、中序遍历二叉树的操作定义为:

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

(1)中序遍历左子树;

(2)访问根结点;

(3)中序遍历右子树。

3、后序遍历二叉树的操作定义为:

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

(1)后序遍历左子树;

(2)后序遍历右子树;

(3)访问根结点。

程序实现:

遍历二叉树是指以一定的顺序访问二叉树中的每个结点,并且每个结点仅被访问一次,所谓访问结点是对节点进行各种操作的简称。

遍历二叉树的过程,就是把二叉树的结点进行排列的过程。

样例输入:

1A2B3C4D5E7F00

样例输出:

ABDECF

DBEACF

DEBFCA

*/

#include

#include

typedefstructnode{

chardata;

structnode*lchild,*rchild;

}BinNode,*BinTree;

BinTreecreate()

{

inti,j;

charx;

BinTrees[120],t=NULL,q;//t=NULL,定义指向根结点的指针

scanf("%d%c",&i,&x);

while(i!

=0&&x!

=0){//结束条件

q=(BinTree)malloc(sizeof(BinNode));//产生一个新结点

q->data=x;//赋结点值

q->lchild=NULL;//赋左孩子值

q->rchild=NULL;//赋有孩子值

s[i]=q;//用数组第i个单元存放指向此结点的指针

if(i==1)t=q;//若是第1个,将t指向它为根

else{//否则,为子树,计算子树的位置j

j=i/2;

if((i%2)==0)//j为偶数,是左子树

s[j]->lchild=q;

else//j为奇数,是右子树

s[j]->rchild=q;

}

scanf("%d%c",&i,&x);

}

returnt;//返回一个指向根的指针

}

voidpreorder(BinTreep){//先序输出二叉树

if(p!

=NULL){

printf("%c",p->data);

preorder(p->lchild);

preorder(p->rchild);

}

}

voidinorder(BinTreep){//中序输出二叉树

if(p!

=NULL){

inorder(p->lchild);

printf("%c",p->data);

inorder(p->rchild);

}

}

voidpostorder(BinTreep){//后序输出二叉树

if(p!

=NULL){

postorder(p->lchild);

postorder(p->rchild);

printf("%c",p->data);

}

}

intmain()

{

BinTreeroot;

root=create();//指针变量root指向一棵建立好的二叉树的二叉链表

preorder(root);puts("");

inorder(root);puts("");

postorder(root);puts("");

return0;

}

------------------------------------------------------------------------------------------------------------------------------

二,二叉树的非递归遍历算法:

为了写出非递归遍历算法,我们可以观察到递归工作栈的状态变化。

(1)当栈顶记录中的指针非空时,应遍历左子树,即指向左子树根的指针进栈。

(2)若栈顶记录中的指针值为空,则应退至上一层,若是从左子树返回,则应访问当前层即栈顶指针上指针所指的根结点;

(3)若是从右子树返回,则表明当前层的遍历结束,应继续退栈。

由此可得以下两个中序遍历二叉树的非递归算法,先序遍历二叉树的非递归算法与此类似,但后序遍历二叉树的非递归算法要相对复杂一点。

程序实现:

/*

样例输入:

ABDECF

样例输出:

ABDECF

DBEACF

DEBFCA

*/

#include

#include

#defineMaxSize100

typedefstructNode{

chardata;

structNode*lchild,*rchild;

}BinNode,*BinTree;

voidCreateBin(BinTree*T){

charch;

if((ch=getchar())=='')

*T=NULL;

else{

*T=(BinTree)malloc(sizeof(BinNode));

(*T)->data=ch;

CreateBin(&((*T)->lchild));

CreateBin(&((*T)->rchild));

}

}

voidVisit(charch){//访问结点值

printf("%c",ch);

}

voidPreOrder2(BinTreeT){//先序遍历二叉树-非递归

inttop=0;

BinTrees[MaxSize];

BinTreep=T;

do{

while(p){

if(top>MaxSize-1)

return;

s[++top]=p;

Visit(p->data);

p=p->lchild;

}

if(top>0){

p=s[top--];

p=p->rchild;

}

}while(p||top>0);

printf("\n");

}

voidInOrder2(BinTreeT){//中序遍历二叉树-非递归

inttop=0;

BinTrees[MaxSize];

BinTreep=T;

do{

while(p){

if(top>MaxSize-1)

return;

s[++top]=p;

p=p->lchild;

}

if(top>0){

p=s[top--];

Visit(p->data);

p=p->rchild;

}

}while(p||top>0);

printf("\n");

}

voidPostOrder2(BinTreeT)

{//后序遍历二叉树-非递归

BinTrees[MaxSize];

BinTreep=T,q;

inttop=0;

while(p||top!

=0){

while(p){

if(top>MaxSize-1)

return;

top++;

s[top]=p;

p=p->lchild;

}

if(top>0){

p=s[top];

if(p->rchild==NULL||p->rchild==q){

Visit(p->data);

q=p;

top--;

p=NULL;

}

else

p=p->rchild;

}

}

printf("\n");

}

intmain()

{

BinTreeroot;

CreateBin(&root);

PreOrder2(root);//先序遍历二叉树-非递归

InOrder2(root);//中序遍历二叉树-非递归

PostOrder2(root);//后序遍历二叉树-非递归

return0;

}

三,二叉树的层次遍历算法:

在层次遍历中先访问的结点,其孩子结点也比后访问的结点的孩子结点先访问,因此,许使用队列这种数据结构实现此算法。

算法思想:

需要使用一个辅助队列,首先让根结点A入队,然后对队列进行操作,如果队列不空,队头结点出队,立即访问之,然后判断它是否有左,右孩子,如有孩子则让孩子结点入队,重复上述操作,直到队列为空为止。

程序实现:

样例输入:

ABD##E##C#F##

样例输出:

ABCDEF

ABCDEF

*/

#include

#include

#defineMaxSize100

typedefstructNode{

chardata;

structNode*lchild,*rchild;

}BinNode,*BinTree;

voidCreateBin(BinTree*T)

{//创建二叉树

charch;

if((ch=getchar())=='#')

*T=NULL;

else{

if(!

(*T=(BinTree)malloc(sizeof(BinNode)))){

exit

(1);

}

(*T)->data=ch;

CreateBin(&((*T)->lchild));

CreateBin(&((*T)->rchild));

}

}

voidlevelorder(BinTreep)

{//层次遍历二叉树

BinTreeq[MaxSize];

intfront=0,rear=0;

if(p!

=NULL){

rear++;

q[rear]=p;

}

while(front!

=rear){

front++;

p=q[front];

printf("%c",p->data);

if(p->lchild!

=NULL){

rear++;

q[rear]=p->lchild;

}

if(p->rchild!

=NULL){

rear++;

q[rear]=p->rchild;

}

}

printf("\n");

}

voidVisit(chare){//访问函数

printf("%c",e);

}

voidLayerOrder(BinTreeT)

{//层次遍历二叉树

BinTreeq[MaxSize];

BinTreep;

intfront=0,rear=0;

if(!

T)

return;

if((rear+1)>MaxSize)

return;

q[rear++]=T;

while(front

p=q[front++];

Visit(p->data);

if(p->lchil

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

当前位置:首页 > 幼儿教育 > 唐诗宋词

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

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