树和二叉树
1 基础概念:
1.1 度和深度
结点的度: 其子结点的数量
树的度: 最大的结点的度
树的深度: 从根算起的层数
性质:
- 树上任意两个结点路径唯一(无环)
- 非空树必有一个根结点与叶结点
- 树的边数+1 = 树的结点数
1.2 二叉数性质
二叉树: 叶结点 = 度为2结点+1
// N代表总边数, n代表结点数
边等式: N = 2 * n2 + n1
结点与边等式: N + 1 = n2 + n1 + n0
结论: n2 + 1 = n0
满二叉树 : 每个非叶结点的度都为2
完全二叉树 : 最多仅有1个度为1的结点
完全二叉数判定规则:
- 如果树为空 : 直接返回错
- 层序遍历二叉树各结点 : (创建队列,压入根结点)
2.1 若(左右子结点都非空) : 分别入队其左右字节点,出队该节点
2.2 若(左子结点为空,右子结点非空) : 直接返回错误
2.3 若(左子结点非空,右子结点为空) 或 (左右字节点都为空) : 入队其子结点, 出队该结点2.3.1 若其后队列中出现(非叶节点)的情况, 返回错误
- 返回正确
二叉树的广义表示形式:
父子关系(左右皆有) : a (b, c)
有左无右 : a(b)
有右无左 : a(, b)
例 : 1(2(4,5),3(,7))
1.3 哈夫曼编码与哈夫曼树
性质: 哈夫曼树不存在度为1的结点
(例)字符串编码
- 计算各个字符的频数, 升序排列
- 按顺序获得一组仅含根结点的树的集合
- 循环操作(集合中树的个数>1时)
3.1 取两个根结点值最小的树, 生成新树: 根结点值为两者之和, 左右子树分别为两者
3.2 从集合删除两者, 添加新树到集合中
- 计算所有叶结点到根结点的距离(路径长度(编码长度))与叶节点权值(字符频数)之和(WPL), 即为该字符串的哈夫曼编码长度
2 代码实现
2.1 创建二叉树 与 三种遍历
#include <iostream>
#include <string>
using std::cout;
using std::endl;
using std::string;
class Node {
public:
int data;
Node *lchild, *rchild;
Node(int _data) {
data = _data;
lchild = NULL;
rchild = NULL;
}
~Node() {
if (lchild) delete lchild;
if (rchild) delete rchild;
}
void preorder() {
cout << data << " ";
if (lchild) lchild->preorder();
if (rchild) rchild->preorder();
}
void inorder() {
if (lchild) lchild->preorder();
cout << data " ";
if (rchild) rchild->preorder();
}
void postorder() {
if (lchild) lchild->preorder();
if (rchild) rchild->preorder();
cout << data " ";
}
Node *build_pi_p(const string &pre_str, const string &in_str, int len) {
Node *proot = new Node(pre_str[0] - '0');
int pos = in_str.find(pre_str[0]);
if (pos > 0) {
proot->lchild = build_pi_p(pre_str.substr(1,pos), in_str.substr(0, pos), pos);
}
if (len - pos - 1 > 0) {
proot->rchild = build_pi_p(pre_str.substr(1 + pos), in_str.substr(pos + 1, len - pos - 1);
}
return proot;
}
};
class BinaryTree {
private:
Node *root;
public:
BinaryTree(){
root = NULL;
}
~BinaryTree() {
delete root;
}
BinaryTree(const string &pre_str, const string &in_str, int len) {
root = root->build_pi_p(pre_str, in_str, len);
}