二叉树
-
完全二叉树: 不需要存地址. ( 算法优化常用完全二叉树: 记录式改为计算式 . 计算式耗时, 但省空间)
左子树: 2 * i
右子树: 2 * i + 1
-
满二叉树: 没有度为1的结点. 要么是0, 要么是2.
二叉树性质:
1. 第i层最多有2^(i - 1)个结点
2. 深度为k的二叉树最多有2^k - 1个结点
3. 度为0(叶子结点)的结点比度为2的结点多1
4. 总结点数 - 总边数 = 1
广义表:
可用来表示二叉树.
表示形式如下:
- ( ): 空树
- A / A( ): 只有一个根节点A的树
- A( B, ) / A(B): 根节点A有一个左孩子B
- A( B, C ) : 根节点A有左孩子B和有孩子C
广义表建立二叉树:
结构定义:
//以括号为分割点来区分左右子树
//(开始压栈标志 . )是弹出栈标志
typedef struct Node {
int key;
struct Node *lchild, *rchild;
} Node;
//栈
typedef struct Stack {
Node **data;
int top, size;
} Stack;
例如: 上图的完美二叉树的广义表为: 1(2(4, 5), 3(6, ))
输出二叉树广义表形式的伪代码:
输出节点存储的值;
如果左孩子不为空:
输出 "(";
递归输出左子树;
如果右孩子为空:
输出 ")"。
如果右孩子不为空:
如果左孩子为空:
输出 "("。
输出 “,”;
递归输出右子树;
输出 ")"。
哈弗曼编码
- 根据频率建立的一颗路径带权的二叉树.
【规定】左孩子结点路径为0, 右孩子结点路径为1, 每个字母编码就是根结点到字母对应结点的路径
- 树上每个结点存储字母出现的频率.
- 根结点到结点的路径即是字母的编码. 频率高的字母使用的编码越短, 反之编码越长(可以缩小字符串的空间占比)
结构定义:
int data//数据区
struct Node *next//next指针
实现步骤:(用小顶堆做)
- 维护一个小顶堆,堆存在二维数组中([存字符][存编码]),弹出两次堆顶元素(数组0位值)
- 将两个弹出元素相加的和插入堆尾,为了维护小顶堆的特性,堆会在内部进行调整。
- 如此反复1, 2步骤,直到数组中只有一个元素为止,树就建好了
- 存编码的方式:首先每个叶子节点的编码都初始化为’\0’
- 从根节点到某叶子节点的路径中,若走左子树,编码存’0’,若走右子树,编码存’1’