画图、编程
二叉树、哈夫曼树、最小生成树
掌握二叉树的基本概念、性质和存储结构
二叉树的定义
二叉树(Binary Tree)是n(n≥0)个结点所构成的集合,它或为空树(n = 0),或为非空树,对于非空树T:
有且仅有一个称之为根的结点;
除根结点以外的其余结点分为两个互不相交的子集T1和T2,分别称为T的左子树和右子树,且T1和T2本身又都是二叉树。
二叉树的基本特点
结点的度小于等于2
有序树(子树有序,不能颠倒)
性质1: 在二叉树的第i层上至多有2^(i-1)个结点
性质2: 深度为k的二叉树至多有2^(k)-1个结点
性质3: 对于任何一棵二叉树,若2度的结点数有n2个,则叶子数n0必定为n2+1 (即n0=n2+1)
性质4: 具有n个结点的完全二叉树的深度必为[log2n]+1
性质5: 对完全二叉树,若从上至下、从左至右编号,则编号为i 的结点,其左孩子编号必为2i,其右孩子编号必为2i+1;其双亲的编号必为i/2。
二叉树的的存储结构
按满二叉树的结点层次编号,依次存放二叉树中的数据元素。
特点:
结点间关系蕴含在其存储位置中
浪费空间,适于存满二叉树和完全二叉树
typedef struct BiNode{
TElemType data;
struct BiNode *lchild,*rchild; //左右孩子指针
}BiNode,*BiTree;
熟练掌握二叉树的前、中、后序遍历方法
Status PreOrderTraverse(BiTree T){
if(T==NULL) return OK; //空二叉树
else{
cout<<T->data; //访问根结点
PreOrderTraverse(T->lchild); //递归遍历左子树
PreOrderTraverse(T->rchild); //递归遍历右子树
}
}
Status InOrderTraverse(BiTree T){
if(T==NULL) return OK; //空二叉树
else{
InOrderTraverse(T->lchild); //递归遍历左子树
cout<<T->data; //访问根结点
InOrderTraverse(T->rchild); //递归遍历右子树
}
}
Status PostOrderTraverse(BiTree T){
if(T==NULL) return OK; //空二叉树
else{
PostOrderTraverse(T->lchild); //递归遍历左子树
PostOrderTraverse(T->rchild); //递归遍历右子树
cout<<T->data; //访问根结点
}
}
重要结论:
若二叉树中各结点的值均不相同,则:
由二叉树的先序序列和中序序列,或由其后序序列和中序序列均能唯一地确定一棵二叉树,
但由前序序列和后序序列却不一定能唯一地确定一棵二叉树。
了解线索化二叉树的思想
(1)若结点有左子树,则lchild指向其左孩子;
否则, lchild指向其直接前驱(即线索);
(2)若结点有右子树,则rchild指向其右孩子;
否则, rchild指向其直接后继(即线索) 。
熟练掌握:哈夫曼树的实现方法、构造哈夫曼编码的方法
根据给定的n个权值{w1,w2,……wn},构造n棵只有根结点的二叉树。
在森林中选取两棵根结点权值最小的树作左右子树,构造一棵新的二叉树,置新二叉树根结点权值为其左右子树根结点权值之和。
在森林中删除这两棵树,同时将新得到的二叉树加入森林中。
重复上述两步,直到只含一棵树为止,这棵树即哈夫曼树。
了解:森林与二叉树的转换,树的遍历方法
森林与二叉树的转化
用二叉链表来表示树,但链表中的两个指针域含义不同。
左指针指向该结点的第一个孩子;
右指针指向该结点的下一个兄弟结点。
树的遍历方法
6.1.已知一棵二叉树的前序序列为ABECDFGHIJ
,中序序列为EBCDAFHIGJ
,试画出这棵二叉树。
6.2.给定一组权W = {3,5,8,17,26,35,44,67,82,95}
,构造Huffman
树,并计算它的带权外部路径长度。
6.3 画出和下列已知序列对应的树T:
树的先根次序访问序列为GFKDAIEBCHJ;
树的后根次序访问序列为DIAEKFCJHBG。
6.4. 假设用于通信的电文仅由8
个字母组成,字母在电文中出现的频率分别为0.07
, 0.19
, 0.02
, 0.06
, 0.32
, 0.03
, 0.21
, 0.10
。试为这8
个字母设计哈夫曼编码。
6.5. 假设一棵二叉树的先序序列为EBADCFHGIKJ
和中序序列为ABCDEFGHIJK
。请画出该树。
6.6. 编写递归算法,将二叉树中所有结点的左、右子树相互交换。
//数据结构:
typedef struct BiTNode {
TElemType data;
BiTNode *lchild, *rchild;
} BiTNode, *BiTree;
//实现函数如下:
void Exchange(BiTree &bt)
{ BiTree temp;
if(bt)
{ temp = bt -> lchild;
bt -> lchild = bt -> rchild;
bt -> rchild = temp;
Exchange(bt -> lchild);
Exchange(bt -> rchild);
}
}
6.7. 编写递归算法:求二叉树中以元素值为x的结点为根的子树的深度。
//数据结构:
typedef struct BiTNode {
TElemType data;
BiTNode *lchild, *rchild;
} BiTNode, *BiTree;
//实现函数如下:
int Depth(BiTree *T,int x){
if(T){
if(T -> data == x){
return get_Depth(T);
}
else{
m = Depth(T->lchild, x);
n = Depth(T->rchild, x);
return m>n ? m:n;
}
}
else return 0;
}
int get_Depth(BiTree *bt){
if(bt){
m = get_Depth(bt->lchild);
n = get_Depth(bt->rchild);
return m>n?m+1:n+1;
}
else{
return 0;
}
}
6.8. 如果二叉树的后序遍历结果是FDEBGCA
,中序遍历结果是FDBEACG
,画出这棵树的先序线索二叉树。
6.9. 请给出下面二叉树的后序遍历线索化链表。
链表结点如下所示: