在大部分OJ题目中,节点个数
n
作为参数传入。所以,比较适合使用采用一组连续的空间来存储每个结点,即Node nodes[n]
。
1.多叉树表示法
双亲表示法
- 表格表示
- 参考代码
struct Node{
char data;
int parent;
};
Node nodes[n];
- 优缺点
比较容易找到双亲,但不容易找到孩子。
孩子表示法
- 表格表示
- 参考代码
struct Node{
char data;
vector<int> childen;
};
Node nodes[n];
- 优缺点
比较容易找到孩子,但不容易找到双亲。
优化:双亲孩子表示法
- 表格表示
struct Node{
char data;
int parent;
vector<int>children;
};
Node nodes[n];
- 优缺点
双亲孩子比较容易找到
1.3 孩子兄弟表示法
- 表格表示
- 代码参考
struct Node{
char data;
int firstchild;
int rightsib;
};
Node nodes[n];
- 优缺点
比较容易找到孩子和兄弟,但不容易找到双亲。
孩子兄弟表示法主要用来把多叉树转化为二叉树。
练习
显示树结构GraphvizOnline
graph G {
A--B
A--C
B--D
C--E
C--F
D--G
D--H
D--I
E--J
}
2.二叉树表示法
2.1顺序储存方式
将二叉树储存在一个数组中,通过存储元素的下标反映元素之间的父子关系。用一组连续地址的存储空间依次自上而下,自左到右存储二叉树的节点。
- 一棵深度为k的二叉树通常需要2^k-1个节点空间存储。
- 节点之间的关系根据二叉树的性质5确定。
5.1 通用性质
- 在非空二叉树上,第层至多有个结点。
- 深度为的二叉树至多有个结点;
- 对任何一个二叉树,若其叶子结点数为,度为的节点数为,则;
5.2 满二叉树的性质
深度为的满二叉树且有个结点。
5.3 完全二叉树的性质
个结点的完全二叉树的深度,这里这个符号表示小于等于的整数;
若对一棵有个结点的完全二叉树(深度为)的结点按层(从第层到第层)序自左至右进行编号,则对于编号为()的结点:
- 如果,则结点是二叉树的根,无双亲结点;如果,则其双亲结点编号是。
- 如果:则结点为叶子结点,无左孩子;否则,其左孩子结点编号是2i。
- 如果:则结点无右孩子;否则,其右孩子结点编号是。
节点 | 下标 |
---|---|
根节点 | 1 |
叶子节点i | 2i>2^k-1 |
节点i的父节点 | i/2 |
节点i的左孩子节点 | 2i |
节点i的右孩子节点 | 2i+1 |
- 通常用
0
表示空节点。 - 结点个数已知的完全二叉树或接近完全二叉树的二叉树,通常使用这种方式。最坏情况为深度为k且只有k个节点的单支数。
2.2 链式存储结构
因为顺序存储结构存在局限性,二叉树比较常见的是链式存储结构,由于二叉树结构简单,通常使用孩子表示法,或者孩子双亲表示法。
- 孩子表示法
struct Node{
char data;
struct Node* right_child;
struct Node* left_child;
};
Node* node;
- 孩子双亲表示法
struct Node{
char data;
struct Node* right_child;
struct Node* left_child;
struct Node* parent;
};
Node* node;