二叉树基础
一、二叉树的定义
二叉树是每个节点最多有两个孩子节点(即每个节点的度最大为 2)的有序树。 定义为左子树和右子树,左子树和右子树是有顺序的,不能颠倒。
- 二叉树:每 个节点最多有两个孩子节点。
- 有序树:左子树和右子树是有顺序的,不能颠倒。
- 重要术语:节点、根节点、叶子节点、父/母节点、子节点、子树、层次、深度、路径等。
二、二叉树的类型
- 空二叉树:没有任何节点。
- 单节点二叉树:只有一个根节点。
- 多节点二叉树:有多个节点。
- 左子树为空的二叉树
- 右子树为空的二叉树
- 满二叉树:每一层的节点数都达到最大值,即一个深度为 d 的满二叉树有 2^d - 1 个节点。
- 完全二叉树:除了最底层外,每层节点都充满,且最底层从左向右连续填充
- 平衡二叉树:任意节点的左右子树的高度差不超过 1。
满二叉树与完全二叉树 的 区分
二叉树是有序树,对一颗满二叉树和一颗完全二叉树按「自上向下,自左向右」的顺序进行编号,如上图。
完全二叉树中的所有结点的编号必须和满二叉树的相同编号的结点在位置上完全相同。
换句话说,完全二叉树的结点按「自上向下,自左向右」的顺序不能中断。T3 的结点 C 没有左孩子,显然按那个顺序是中断的。
备注
二叉树是由根结点、左子树、右子树这三部分递归地组合而成的。
三、二叉树的存储
- 顺序存储:使用线性表存储二叉树,适合完全二叉树。
- 链式存储:使用链表存储二叉树,适合任意二叉树。
- 静态链表:使用数组模拟链表,适合任意二叉树。
- 动态链表:使用链表存储二叉树,适合任意二叉树。
- 静态数组:使用数组存储二叉树,适合完全二叉树。 静态数组,根节点一般存储在数组下标为 1 的位置。
struct BTNode{
int data; //结点里的数
int lchild, //左孩子的结点指针(数组下标)
int rchild; //右孩子的结点指针(数组下标)
} btnode[1000];
构建树
/* 输入数据:
A 2 3
B 4 5
F 0 6
C 7 0
D 0 0
G 0 8
E 0 0
H 0 0
*/
int n ;
cin>>n;
for(int i=1; i<=n; i++){
cin>>btnode[i].data>>btnode[i].lchild>>btnode[i].rchild;
}
求二叉树的深度
求二叉树的深度
int max_depth = 0;
int get_depth(int root){
if(root == 0) return 0;
BTNode node = btnode[root];
if(node.lchild == 0 && node.rchild == 0) return 1;
if(node.lchild != 0)
max_depth = max(max_depth, get_depth(node.lchild));
if(node.rchild != 0)
max_depth = max(max_depth, get_depth(node.rchild));
return max_depth + 1;
}
//...
cout<<get_depth(1);
常见操作:
- 查找元素:在二叉树中查找给定值的节点。
- 插入元素:在二叉搜索树中插入一个新节点。
- 删除元素:在二叉搜索树中删除一个节点(涉及到左子树最大值或右子树最小值的替换,比如队、平衡树等)。
四、二叉树的遍历
教学生了解如何遍历二叉树,并用不同的遍历方式来解决问题。可以使用图示和代码示例来说明。
- 前序遍历/先序遍历(Pre-order Traversal):
- 访问根节点
- 遍历左子树