树和Binary

【1】树的类型定义【2】二叉树的类型定义【3】二叉树的存储结构【4】二叉树的遍历【5】线索二叉树【6】树和森林的表示方法【7】树和森林的遍历【8】哈夫曼树与哈夫曼编码

【1】树的类型定义

树的基本术语

结点:数据元素+若干指向子树的分支,数据元素A+指向B,C,D的3个分支
结点的度:分支的个数,刚才讲的根节点A有3个子树,结点的度是3
树的度:树中所有节点的度的最大值,树上面结点最多子树的个数,树的度是3
叶子结点:度为0的结点,这个结点是没有子树的,这个结点对整个树来说是特殊的,叫叶子结点,除了叶子结点外,其他的结点的度是大于0的,反过来叫他分支结点
分支结点:度大于0的结点
对于树来说没说的多的是跟结点,叶子结点,分支结点
孩子结点:根和子树根的关系,是父子关系
 
双亲结点 ,反过来,根对于子树根来说是双亲结点
兄弟结点 :由相同的根的子树,这些根的关系是兄弟关系
堂兄弟关系:
祖先结点  
子孙结点
结点的层次:
树的深度:树中叶子结点所在的最大层次
森林:是m>=0棵互不相交的树的集合
Tree=(ROOT,F);root称为根结点,F称为子树森林,3棵树构成的一个森林,森林里的第一棵树,第二棵树,第三棵树,森林加上这个根就是一个树,反过来,森林就是树的集合,
树的基本操作,3大类:查找 插入 删除 
查找分特定查找和关系查找




数的特性操作,看数是否空树,以及求树的深度

有向树

树是根以下的有向树,

【2】二叉树的类型定义

Binary Tree

二叉树的主要基本操作
查找插入删除
查找:
查找可以是特定的查找
Root(T);//查根
Value(T,e);//查某一个结点它的值为e的某个结点
1:也可以按关系查找
Parent(T,e);//找元素的双亲
LeftChild(T,e);//找元素的左孩子,也就是左子树根
RightChild(T,e);//找它的右子树根
LeftSibling(T,e);//如果它本身是右子树根,它存在左兄弟
RightSibling(T,e);//如果它本身是左子树根,存在右兄弟
2:对树的状态的一些操作
BitreeEmpty(T);//看树是不是空树
BitreeDepth(T);//求二叉树的深度
3://对二叉树的4种遍历的操作
PreOrderTraverse(T,Visit());
InOrderTraverse(T,Visit());
PostOrderTraverse(T,Visit());
LevelOrderTraverse(T,Visit());


插入:
InitBiTree();//初始化
Assign(T,&e,value);//改变二叉树上某个结点的值
CreateBiTree(&T,definition);//根据给定的定义也就是给出一根节点,给出左子树根,右子树根,可以构造一棵二叉树
InsertChild(T,p,LR,c);//在某个结点上插入一棵以c为结点的二叉树,插入作为这个结点的左子树或者右子树,LR是左右标志


删除
ClearBitree(&T);//把二叉树清空
DestroyBiTree(&T);//销毁结构
DeleteChild(T, p, LR);//删除某个结点的左子树,右子树
//对于二叉树和树一样,咩有删除一个结点的操作,要删除就删除一子树


二叉树的重要性
性质1:在二叉树的第i层上至多有2的i - 1个结点(i >= 1)
i = 1, 成立,只有一个根节点,2的0次方 = 1
i在某一层满足第二个条件,最多是2的k - 1次方,每个结点最多有2个子树根
性质2:深度为h的二叉树,它的结点数最多是2的h次方 - 1个结点
深度为h的二叉树,每一层都取最大的
性质3:对任何一棵二叉树,若他含有n0个叶子结点,n2个度为2个结点,则必存在关系式,n0 = n2
+ 1
性质3; 二叉树上的结点只有3种,度为0的,度为1的,度为2的,这个特性告诉我们,不管二叉树上有多少个度为0,2,1,一定满足这个关系
度为1的节点个数,度为2个的结点个数整个和当然是整个二叉树结点数目n
度为2个结点产生2个分支,度为1个结点产生1个分支,度为0个结点不产生分支


两类特殊的二叉树
满二叉树:指的是深度为k且含有2k - 1个结点的二叉树,意思是二叉树上面不存在唯一的结点,除了叶子节点外,每个结点都有2棵子树,最后一层是叶子结点,其他都是分支结点,每一层都取它的最大的数。
编号后引出完全二叉树
完全二叉树:树中所含的n个结点和满二叉树中编号为1至n的结点一一对应,
如果这个完全2叉树只有5个结点,这5个结点应该和编号1,2,3,4,5一一对应
完全2叉树的特性,上面每一层都是满的,只有最后一层不满,不满的左边能有结点尽量有结点,右边有左边没有不是完全2叉树
完全2叉树有2个重要特性
性质5:若对含n个结点的二叉树从上到下且从左到右进行1至n的编号,则对二叉树中任意一个编号为i的结点
(1)若i = 1;则该结点是二叉树的根,无双亲,否则,编号为i / 2的结点为其双亲结点
(2)若2i > n, 则该结点无左孩子, 否则,编号为2i的结点为其左孩子结点
(3)若2i + 1 > n, 则该结点无右孩子结点,否则,编号为2i + 1的结点为其右孩子结点


【3】二叉树的存储结构
(1):二叉树的顺序存储表示
#define MAX_TREE_SIZE 100//二叉树的最大结点数
typedef TElemType SqBiTree[MAXTREE_SIZE];//0号单元存储根结点
SqBiTree bt;
//把二叉树的结点存储在一维数组,一维数组的最大值设定为100,
(2):二叉树的链式存储表示
 1:二叉链表 
 2:三叉链表
 3:双亲链表
 4:线索链表


 1;二叉链表//每个结点里面还有2个指针域,一个数据域,2个指针域
 typedef struct BiTNode
{
TElemType data;
struct BiTNode *lchild, *rchild;//左右孩子指针
 }BiTNode,*BiTree;
2:三叉链表
typedef struct BiTNode
{
TElemType data;
struct BiTNode *lchild, *rchild;//左右孩子指针
struct TriTNode *parent;
}TriTNode, *TriTree;
3:双亲链表:

/*结点里面一指针,一左右标志,一数据域,整个二叉树所有的结点放在一维数组里面,加上结点的数目,
加上根节点的位置,构成了整个二叉树的这样一个表示方法,这表示方法我们成为双亲链表*/
typedef struct BPTNode
{
TElemType data;
int *parent;//指向双亲的指针
char LRTag;//左,右孩子标志域

}BPTNode;
typedef struct BPTree
{
BPTNode nodes[MAX TREE SIZE];
int num_node;//结点数目
int root;//根结点的位置
}BPTree;

4:线索链表 没有讲

【4】二叉树的遍历(讨论5个问题)

1:问题的提出

顺着某一条搜索路径巡访二叉树中的结点,使得每个结点均被访问一次,而且仅被访问一次,遍历是任何类型均有的操作,对线性结构而言,只有一条

搜索路径(因为每个结点均只有一个后继),故不需要讨论。而二叉树是非线性结构,每个结点有两个后继,则存在如何遍历即按什么样的搜索路径遍历的问题

二叉树有什么搜索路径呢?答案:有3条搜索路径第一条:先上后下的按层次遍历,先访问根节点,在访问根节点的子树,左子树右子树,在访问子树的子树,一层一层往下遍历。第二条:先左子树后右子树的遍历,对左子树遍历和根结点(根节点只有一个,访问就行了)遍历和右子树的总和。第三条:先右子树后左子树的遍历,

2:先左后右的遍历算法(分3法)

(1)先(根)序的遍历算法

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

A:访问根节点

B:先序遍历左子树

C:先序遍历右子树

(2)中(根)序的遍历算法

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

A:中序遍历左子树

B:访问根节点

C:中序遍历右子树


(3)后(根)序的遍历算法

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

A:后序遍历左子树

B:后序遍历右子树

C:访问根节点

3:算法的递归描述

//BiTree T 是指向二叉树的根节点的指针T,
void Preorder(BiTree T,void(*visit)(TELemType& e))
{//先序遍历二叉树,用C语言,有两种形式,一种是递归形式,一种是非递归形式,下面是递归形式
if (T)
{//如果二叉树不为空
visit(T->data);//先访问根结点
Preorder(T->lchild.visit);//遍历左子树
Preorder(T->rchild.visit);//遍历右子树
}
}


4:中序遍历算法的非递归描述

//从指针所指的这个根节点T出发,向左走,走到它的左子树为空的结点返回,走的过程中把那些结点的指针入栈,
BiTNode *GoGarLeft(BiTree T,Stack *S){
if (!T)return NULL;
while (T-.lchild)
{
Push(S,T);
T->T->lchild;
}
return T;


非递归中序遍历的算法
void Inorder l(BiTree T, void(*visit)(Telem Type& e))
{
Stack *S;
t = GoFarLeft(T,S);//找到最左下的结点
while (t)
{
visit(t->data);
if (t->rchild)
t = GoFarLeft(t->rchild, S);
else if (!StackEmpty(S))//栈不空时退栈
t = Pop(S);
else t = NUMLL;//栈空表明遍历结束
}


}
}

5:遍历算法的应用举例

举例1:统计二叉树中叶子结点的个数(先序遍历),二叉树的叶子结点是左右子树都空

分析3种情况,第一种情况是假定二叉树是空树,叶子结点数目等于0

第二种情况,假定二叉树上只有一个根节点,这个根节点本身就是叶子结点,所以叶子结点数目就是1

第三种情况就是这二叉树有子树,根节点不是叶子结点,叶子结点总数是左子树叶子结点和右子树叶子结点的和

C语言递归:

void CountLeaf(BiTree T,int& count)//T是指向根节点的指针,
{
if (T)
{
if ((!T->lchild) && (!T->rchild));//左子树空和右子树空
count++;//计数器累计加
CountLeaf(T->lchild.count);//统计左子树叶子结点个数
CountLeaf(T->rchild.count);//统计右子树叶子结点个数


}
}

举例2:求二叉树的深度(后序遍历)

二叉树深度的定义是:它是叶子结点的最大的层次数,就是树的深度

二叉树为空,深度为0,二叉树有一个根结点,深度为1

int Depth(BiTree T)
{
if (!T)depthval = 0;
else{
depthLeft = Depth(T->lchild);
depthRight = Depth(T->rchild);
depthval + 1
(depthLeft>depthRight ?depthLeft : depthRight);
}return depthval;
}

举例3:复制二叉树(后序遍历)

需要3个值,数据域的值,左指针值和右指针值,首先系统分配一个空间,
如果系统空间不存在了,就不用了。如果这个系统分配成功,这个指针究不空,
就把数据域赋给参数里面的值item,左指针和右指针为空,然后返回新的结点的指针
BiTNode *GetTreeNode(TElemType item, BiTNode *lptr, BiTNode *rptr)
{
if (!(T = BiTNode *)malloc(sizeof(BiTNode))))
exit(1);
T->data = item;
T->lchild = lptr;
T->rchild = rptr;
return T;
}
BiTNode *CopyTree(BiTNode *T)//左右子树不空,先复制左子树,在复制右子树,复制生成一根节点
{
if (!T)
return NULL;
if (T->lchild)
newlptr = CopyTree(T->lchild);
else newlptr = NULL;
if (T->rchild)
newrptr = CopyTree(T->rchild);
else newrptr = NULL;
newnode = GetTreeNode(T->data, newlptr, newrptr);
return newnode;

}

举例4:建立二叉树的存储结构

一般来说就是建立几个二叉树的二叉链表

第一种方法是按给定的先序序列建立二叉链表,根结点数据域data,指向左子树的指针,指向右子树的指针

Status CreateBiTree(BiTree &T)
{
scanf(&ch);
if (ch == '')T = NULL;
else{
if (!(T = (BiTNode *)malloc(sizeof(BiTnode))))
exit(OVERFLOW);
T->DATA = ch;//生成根节点
CreateBiTree(T->lchild);//构建左子树
CreateBiTree(T->rchild);//构建右子树
}
return OK;
}

按给定的表达式建相应的二叉树,表达式有先缀,中缀,后缀表达式

(1)由先缀表示式建树:先序遍历

表达式=(第一操作数)(运算符)(第二操作数)

运算符作为根节点,第一操作数作为左子树,第二操作数作为右子树

【5】线索二叉树,不需要递归和栈了

(何谓线索二叉树):前驱是左子树为空,后继为右子树是空,9个结点的话就是n+1个空指针域,10个空指针域

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

若该结点的左子树不空,

则lchild域的指针指向其左子树,且左标志域的值为0,否则,lchild域的指针指向其前驱,且左标志的值为1

(线索链表的遍历算法)


(如何建立线索链表)

【6】树和森林的表示方法

(1)双亲表示法:每个结点通过

#define MAX_TREE_SIZE 100
:通过一个结点的数据域和双亲域
typedef structurePTNode
{
Elem data;
int parent;//双亲位置域
}PTNode;

(2)孩子链表表示法

(3)树的二叉链表,又叫孩子兄弟链表

【7】树和森林的遍历

【8】哈夫曼树与哈夫曼编码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值