一、学习内容
(一) 树的定义
- 有且仅有一个称之为根的结点
- 出根节点以外的其余结点可分为m(m>0)个互不相交的有限集T1,T2……,Tm,其中每个集合本身又是一棵树,并且称为根的字数
(二) 基本术语
- 结点:树中的一个独立单元
(1) 统计二叉树中的节点个数
int NodeCout(BiTree T)
{
if(T == NULL) return 0;
else return NodeCout(T->lchild)+NodeCout(T->rchild)+1;
}
- 结点的度:结点拥有的子树数称为结点的度
- 树的度:树内各结点度的最大值
- 叶子(终端结点):度为0的结点
- 非终端结点:度不为0的结点
- 双亲和孩子:结点的子树的根称为该结点的孩子,相应地,该结点称为孩子的双亲。
- 兄弟:同一个双亲的孩子之间互称兄弟
- 祖先:从根到该结点的所有结点
- 子孙:以某结点为根的子数中的任一结点都称为该节点的子孙
10. 堂兄弟:双亲在同一层的结点互为堂兄弟
11. 层次:结点的层次从根开始定义,根为第一层,根的子孙为第二层
12. 树的深度:树中结点的最大层次
(1) 计算二叉树的深度
int Depth(BiTree T)
{
if(T == NULL) return 0;
else
{
m = Depth(T->lchild);
n = Depth(T->rchild);
if(m>n) return (m+1)
else return(n+1);
}
}
13. 有序树和无序树:将树中结点的各子树看成从左至右是有次序的(即不能互换),则称为该树为有序树,否则称为无序树
14. 森林:m(m>=0)棵互不相交的树的集合
(三) 二叉树
- 定义:
(1) 有且仅有一个称之为根的结点
(2) 除根节点以外的起浴结点分为两个互不相交的子集T1和T2,分别称为T的左子树和右子树,且T1和T2本身又都是二叉树
- 性质:
(1) 在二叉树的第i层上至多有2^(i-1)个结点(i>=1)
(2) 深度为k的二叉树之多为2^k-1个结点(k>=1)
(3) 对任何一棵二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0=n2+1
- 分类:
(1) 满二叉树:深度为k且含有2^k-1个结点的二叉树
(2) 完全二叉树:深度为k的,又n个结点的二叉树,当且仅当其每一个结点都与深度为k的满二叉树中编号从1至n的结点一一对应时,称之为完全二叉树。(从左到右是满的树)
- 存储结构
(1) 顺序存储:具有封装性
#define MAXTSIZE 100
typedef TElemType SqBiTree[MAXTSIZE];
SqBiTree bt;//bt为含MAXTSIZE个TElemType类型元素的数组
(2) 链式存储:
Typedef struct BiTNode{
TElemType data;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
- 顺序
(1) 先序:根->左子树->右子树
(1) 建立二叉链表
void CreateBiTree(BiTree &T)
{
cin >> ch;
if(ch == ‘#’) T = NULL;
else
{
T = new BiTNode;
T->data = ch;
CreateBiTree(T->lchild);
CreateBiTree(T->rchild);
}
}
(2) 复制二叉树
void Copy(BiTree T,BiTree &NewT)
{
if(T == NULL)//空树,递归结束
{
NewT = NULL;
Return;
}
else
{
NewT = new BiTNode;
NewT->data = T->data;//复制根节点
Copy(T->lchild,NewT->lchild);//复制左子树
Copy(T->rchild,NewT->rchild);//复制右子树
}
}
(2) 中序:左子树->根->右子树
(1) 递归遍历:
void InOrderTraverse(BiTree T)
{
if(T)
{
InOrderTraverse(T->lchild);
cout << T->data;
InOrderTraverse(T->rchild);
}
}
(2) 非递归遍历:
void InorderTraverse(BiTree T)
{
if(p)//p非空
{
Push(S,p);//根指针进栈
p = p->lchild;
}
else//p为空
{
Pop(S,q);//退栈
cout << q->data;//访问根节点
p = q->rchild;//遍历右子树
}
}
(3) 后序:左子树->右子树->根
(4) 层次:
void LevelOrder(Tree T)
{
queue
Q.push(T.root);//根结点入队
int k;
while (!Q.empty())
{
k = Q.front();//获取队头元素的值,给k
Q.pop();//队头元素出队
if (T.tn[k].n != 0)//叶子结点
{
for (int i = 0; i < T.tn[k].n; i++)
{
Q.push(T.tn[k].a[i]);
}
}
else
{
if (Q.empty())
{
cout << k;
}
}
}
}
- 复制二叉树
void Copy(BiTree T,BiTree &NewT)
{
if(T == NULL)//空树,递归结束
{
NewT = NULL;
Return;
}
Else
{
NewT = new BiTNode;
NewT->data = T->data;//复制根节点
Copy(T->lchild,NewT->lchild);//复制左子树
Copy(T->rchild,NewT->rchild);//复制右子树
}
}
(四) 哈夫曼树(最优哈夫曼树)
- 定义:带权路径长度最短的二叉树
- 基本术语
(1) 路径(l):从树中一个结点到另一个结点之间的分支构成这两个结点之间的路径
(2) 路径长度:路径上的分支数目
(3) 树的路径长度:从树根到每一结点的路径长度之和
(4) 权(w):赋予某个实体的一个凉,是对实体的某个或某些属性的数值化描述
(5) 结点的带权路径长度:从该节点到树根之间的路径长度与结点上权的乘积
(6) 树的带权路径长度:树中所有叶子节点的带权路径长度之和,通常记为WPL=w(k)*l(k)(k = 1、2、……、n)
- 构造过程
① 从给定的n个结点中选择两个权值最小的结点构成一棵新二叉树,并划去这两个结点,其根节点的权值为左右子树权值之和,并记下该结点
② 重复直到构成完整的树
- 交换哈夫曼树同层次的叶子结点可得到最有非哈夫曼树
- 其他树的WPL值一定大于等于哈夫曼树