概念
树是 n ( n ≥ 0 ) n(n \geq 0) n(n≥0) 个结点的有限集合 T ( T r e e ) T(Tree) T(Tree) 。当 n = 0 n=0 n=0 时,称为空树;当 n > 0 n>0 n>0 时, 该集合满足如下条件:
- 其中必有一个称为 根(root) 的特定结点,它没有直接前驱,但有零个或多个直接后继。
- 其余
n
−
1
n-1
n−1 个结点可以划分成
m
(
m
≥
0
)
m(m \geq 0)
m(m≥0)个互不相交的有限集
T
1
,
T
2
,
T
3
,
⋯
,
T
m
T_{1},T_{2},T_{3},\cdots ,T_{m}
T1,T2,T3,⋯,Tm ,其中
T
i
T_{i}
Ti 又是一棵树,称为根
r
o
o
t
root
root的子树。 每棵子树的根结点有且仅有一个直接前驱,但有零个或多个直接后继。
基本术语
- 结点:包含一个数据元素及若干指向其它结点的分支信息
- 结点的度:一个结点的子树个数称为此结点的度。
- 叶结点:度为 0 的结点,即无后继的结点,也称为终端结点。
- 分支结点:度不为 0 的结点,也称为非终端结点。
孩子结点:一个结点的直接后继称为该结点的孩子结点。 - 双亲结点:一个结点的直接前驱称为该结点的双亲结点。
- 兄弟结点:同一双亲结点的孩子结点之间互称兄弟结点。
- 祖先结点:一个结点的祖先结点是指从根结点到该结点的路径上的所有结点。
- 子孙结点:一个结点的直接后继和间接后继称为该结点的子孙结点。
- 树的度: 树中所有结点的度的最大值。
- 结点的层次:从根结点开始定义,根结点的层次为1,根的直接后继的层次为2,依此类推。
- 树的高度(深度): 树中所有结点的层次的最大值。
- 有序树:在 树T 中,如果各子树Ti之间是有先后次序的,则称为有序树。
- 森林: m ( m ≥ 0 ) m(m \geq0) m(m≥0) 棵互不相交的树的集合。将一棵非空树的根结点删去,树就变成一个森林;反之,给森林增加一个统一的根结点,森林就变成一棵树。
二叉树
定义
我们把满足以下两个条件的树形结构叫做二叉树(Binary Tree):
- 每个结点的度都不大于2;
- 每个结点的孩子结点次序不能任意颠倒。
二叉树的五种基本形态
二叉树的特殊形式
满二叉树:
深度为 k k k 且有 2 k − 1 2k-1 2k−1 个结点的二叉树。在满二叉树中,每层结点都是满的,即每层结点都具有最大结点数。
完全二叉树:
深度为
k
k
k ,结点数为
n
n
n 的二叉树,如果其结点
1
∼
n
1 \sim n
1∼n 的位置序号分别与满二叉树的结点
1
∼
n
1 \sim n
1∼n的位置序号一一对应(也就是深度为
1
∼
k
−
1
1 \sim k-1
1∼k−1的所有结点都是满二叉树,第
k
k
k 层结点全部都靠在左边),则为完全二叉树.
性质
- 在二叉树的第 i i i 层上至多有 2 i − 1 2^{i-1} 2i−1 个结点 ( i ≥ 1 ) ( i \geq 1) (i≥1)。
- 深度为k的二叉树至多有 2 k − 1 2^{k}-1 2k−1 个结点 ( k ≥ 1 ) (k \geq 1) (k≥1)。
- 对任意一棵二叉树 T T T,若终端结点数为 n 0 n_{0} n0 ,而其度数为 2 的结点数为 n 2 n_{2} n2,则 n 0 = n 2 + 1 n_{0}=n_{2}+1 n0=n2+1。
- 具有 n n n 个结点的完全二叉树的深度为 i n t ( l o g 2 n ) + 1 int(log_{2}n)+1 int(log2n)+1
- 对于具有
n
n
n 个结点的完全二叉树, 如果按照 从上到下 和 从左到右 的顺序对二叉树中的所有结点从 1开始顺序编号, 则对于任意的序号为
i
i
i 的结点有:
(1) 如 i = 1 i=1 i=1,则序号为 i i i 的结点是 根结点, 无双亲结点; 如 i > 1 i>1 i>1 , 则序号为 i i i 的结点的双亲结点序号为 i n t ( i / 2 ) int(i/2) int(i/2) 。
(2) 如 2 × i > n 2 \times i>n 2×i>n,则序号为i的结点无左孩子;如 2 × i ≤ n 2 \times i \leq n 2×i≤n,则序号为i的结点的左孩子结点的序号为 2 × i 2 \times i 2×i 。
(3) 如 2 × i + 1 > n 2 \times i+1>n 2×i+1>n,则序号为 i i i 的结点无右孩子;如 2 × i + 1 ≤ n 2 \times i+1 \leq n 2×i+1≤n, 则序号为i的结点的右孩子结点的序号为 2 × i + 1 2 \times i+1 2×i+1
存储结构
二叉树的结构是非线性的, 每一结点最多可有两个后继。
二叉树的存储结构有两种: 顺序存储结构和链式存储结构。
1.顺序存储结构
2. 链式存储结构
对于任意的二叉树来说,每个结点最多只有两个孩子,一个双亲结点。我们可以设计每个结点至少包括三个域:数据域、 左孩子域 和 右孩子域.
用C++可以这样声明二叉树的二叉链表结点的结构:
typedef struct Node
{
DataType data;
struct Node *LChild;
struct Node *RChild;
}BiTNode, *BiTree;
遍历
我们用L、D、R分别表示遍历左子树、访问根结点、 遍历右子树, 那么对二叉树的遍历顺序就可以有六种方式:
- 访问根,遍历左子树,遍历右子树(记做DLR)。
- 访问根,遍历右子树,遍历左子树(记做DRL)。
- 遍历左子树,访问根,遍历右子树(记做LDR)。
- 遍历左子树,遍历右子树,访问根(记做LRD)。
- 遍历右子树,访问根,遍历左子树(记做RDL)。
- 遍历右子树,遍历左子树,访问根(记做RLD)。
先序遍历: A、 B、 D、 F、 G、 C、 E、 H 。
中序遍历: B、 F、 D、 G、 A、 C、 E、 H 。
后序遍历: F、 G、 D、 B、 H、 E、 C、 A 。
例题
- 小球(drop)
设置一个计数器,如果此结点为 f a l s e false false ,将它变为 t r u e true true,访问左子树;如果此结点为 t r u e true true,将他变为 f a l s e false false,访问右子树;最后输出 m m m 次循环后所访问的叶子节点。
#include<bits/stdc++.h>
using namespace std;
const int Max = 5242885;
int d, l, last, maxn;
bool vis[Max];
void dfs(int x){
if(!vis[x]){
vis[x] = 1;
if(2 * x > maxn){
last = x;
return ;
}
dfs(2 * x);
}
else{
vis[x] = 0;
if(2 * x + 1 > maxn){
last = x;
return ;
}
dfs(2 * x + 1);
}
}
int main() {
scanf("%d %d", &d, &l);
maxn = pow(2, d) - 1;
while(l--)
dfs(1);
printf("%d", last);
return 0;
}
先用指针变量和线性链表建立一个二叉树,然后用递归分别输出中序序列和后续序列即可。
#include<bits/stdc++.h>
using namespace std;
struct node{
char id;
int cld[2];
}tree[85];
int root,cnt;
int newnode(char v){
cnt++;
tree[cnt].id = v;
tree[cnt].cld[0] = tree[cnt].cld[1] = 0;
return cnt;
}
void build(int &rt){
char c;
c = getchar();
if(c == '.') return;
rt = newnode(c);
build(tree[rt].cld[0]);
build(tree[rt].cld[1]);
}
void inorder(int rt){
if(rt == 0) return;
inorder(tree[rt].cld[0]);
printf("%c", tree[rt].id);
inorder(tree[rt].cld[1]);
}
void postorder(int rt){
if(rt == 0) return;
postorder(tree[rt].cld[0]);
postorder(tree[rt].cld[1]);
printf("%c", tree[rt].id);
}
int main(){
build(root);
inorder(root);
puts("");
postorder(root);
return 0;
}