一、树的基本概念
(一)树(tree)
顾名思义,看起来像一棵倒挂的树。
它的根朝上,叶朝下。
如下图就是一颗树
(二)树的专业术语
结点的度:该结点子树的度称为
树的度:树中所有结点的度中的最大值
m次数树:度为m的树
分支结点:树中度不为零的结点(非终端结点)
叶子结点:为零的结点
孩子结点:每个结点的后继结点
结点层次和结点深度:从树根开始定义,根结点为第一层,其孩子结点为第二层,依次类推
树的高度和树的深度:树中结点的最大层次
森林:由n(n>0)棵互不相交的树的集合称为森林。
(三)树的性质
树中的结点数等于所有结点的的度数之和加1
度为m的树中的i层最多有
m
i
−
1
m ^ {i-1}
mi−1个结点
高度为h的m次树最多有
m
h
−
1
m
−
1
\frac{m^h-1}{m-1}
m−1mh−1个结点
具有n个结点的m次树的最小高度为大于等于
log
m
(
n
(
m
−
1
)
+
1
)
\log{_m}{(n(m-1)+1)}
logm(n(m−1)+1)的最小整数
(四)树的遍历
先根遍历:首先访问根结点,然后遍历左子树,最后遍历右子树
后根遍历:首先遍历左子树,然后遍历右子树,最后访问根结点
层次遍历:从根结点开始按从上到下、从左到右的次序访问树中
(五)树的种类
无序树:树中任意节点的子结点之间没有顺序关系
有序树:树中任意节点的子结点之间有顺序关系
二叉树:每个节点最多含有两个子树
满二叉树:叶节点除外的所有节点均含有两个子树
完全二叉树:除最后一层外,所有层都是满节点,且最后一层缺右边连续节点的二叉树
哈夫曼树:带权路径最短的二叉树(又称为最优二叉树)
二、二叉树的基本概念
(一)二叉树(Binary tree)
二叉树是树形结构的一个重要类型
二叉树的存储结构及其算法都较为简单
二叉树的每个结点最多只能有两棵子树,且有左右之分
(二)二叉树的性质
叉树的第i层上至多有
2
i
−
1
(
i
≥
1
)
2i-1(i≥1)
2i−1(i≥1)个节点
深度为h的二叉树中至多含有
2
h
−
1
2h-1
2h−1个节点
若在任意一棵二叉树中,有
n
0
n0
n0个叶子节点,有
n
2
n2
n2个度为2的节点,则必有
n
0
=
n
2
+
1
n0=n2+1
n0=n2+1
二叉树第
i
i
i层上至多有
2
i
−
1
2^{i-1}
2i−1个结点
深度为
k
k
k的二叉树至多有
2
k
−
1
2^k-1
2k−1个结点
完全二叉树按层次编号,对于任意一个编号为
i
i
i的结点,左孩子结点的编号为
2
i
2i
2i,右孩子结点的编号为
2
i
+
1
2i+1
2i+1
(三)二叉树的遍历
前序遍历:首先访问根结点,然后遍历左子树,最后遍历右子树
中序遍历:首先访问左子树,然后遍历根节点,最后遍历右子树
后序遍历:首先遍历左子树,然后遍历右子树,最后访问根结点
层次遍历:从根结点开始按从上到下、从左到右的次序访问树
三、二叉树的基本操作
(一)存储结构
1、顺序存储结构
int Tree[MAXSIZE];//MAXSIZE根据所需结点定义,按所对应满二叉树
2、链式存储结构
struct node
{
char data;//结点数据
node *lchild, *rchild;//左右孩子指针
}Tree;
(二)二叉树的创建
以链式存储结构创建先序遍历二叉树为例
void Create(node *&T) //先序遍历的顺序建立二叉表
{
char c;
cin >> c;
if (c == '#') //读到空结点
T = NULL;
else
{
T = new node; //生成节点
T->data = c; //赋值
Create(T->lchild); //递归创建左子树
Create(T->rchild); //递归创建右子树
}
}
(三)二叉树的遍历
以先序遍历为例,输出该二叉树
void Print(node *T) //先序遍历
{
if (T) //该结点存在
{
cout << T->data; //输出该结点
Print(T->lchild); //遍历左子树
Print(T->rchild); //遍历右子树
}
}
四、二叉搜索树
(一)插入
void Insert(node *p, int x)
{
if (p == NULL)
{
node *q = new node;
q->l = NULL;
q->r = NULL;
q->data = x;
return;
}
if (x < p->data)
Insert(p->l, x);
if (x > p->data)
Insert(p->r, x);
return;
}
(二)查询
node *Find(node *p, int x)
{
if (p == NULL)
return NULL;
if (x == p->data)
return p;
if (x < p->data)
return Find(p->l, x);
if (x > p->data)
return Find(p->r, x);
}
五、哈夫曼树
哈夫曼树的带权路径长度
树的带权路径长度(Weighted Path Length of Tree,简记为WPL)是从树根到树中每一结点的路径长度之和
所有二叉树中,带权路径长度最小(即代价最小)的二叉树称为最优二叉树或哈夫曼树。
代码实现
输入一个数n,然后输入n个叶结点,需要用这些叶结点生成哈夫曼树,根据哈夫曼树的概念,这些结点有权值,即weight,最后输出哈夫曼树的带权路径长度(WPL)
#include <bits/stdc++.h>
using namespace std;
priority_queue<int, vector<int>, greater<int>> q;//定义升序队列,小根堆
int main()
{
int n, x;
cin >> n;
for (int i = 1; i <= n; ++i)
{
cin >> x;
q.push(x);//放入队列
}
int ans = 0, t;
for (int i = 1; i <= n; ++i)
{
t = 0;
t += q.top();
q.pop();
t += q.top();
q.pop();
ans += t;
q.push(t);
}
cout << ans;
return 0;
}
注意:
叶子上的权值均相同时,完全二叉树一定是最优二叉树,否则完全二叉树不一定是最优二叉树。
最优二叉树中,权越大的叶子离根越近。
最优二叉树的形态不唯一,WPL最小