进击高手【第十期】树

本文介绍了树的基本概念,包括结点、度、叶结点等,并详细阐述了二叉树的定义、特殊类型如满二叉树和完全二叉树的性质。此外,还讨论了二叉树的存储结构(顺序和链式)以及遍历方法(先序、中序和后序)。最后提到了扩展二叉树的构建及其遍历输出。
摘要由CSDN通过智能技术生成

概念

树是 n ( n ≥ 0 ) n(n \geq 0) nn0 个结点的有限集合 T ( T r e e ) T(Tree) T(Tree) 。当 n = 0 n=0 n=0 时,称为空树;当 n > 0 n>0 n>0 时, 该集合满足如下条件:

  1. 其中必有一个称为 根(root) 的特定结点,它没有直接前驱,但有零个或多个直接后继。
  2. 其余 n − 1 n-1 n1 个结点可以划分成 m ( m ≥ 0 ) m(m \geq 0) mm0个互不相交的有限集 T 1 , T 2 , T 3 , ⋯ , T m T_{1},T_{2},T_{3},\cdots ,T_{m} T1T2T3Tm ,其中 T i T_{i} Ti 又是一棵树,称为根 r o o t root root的子树。 每棵子树的根结点有且仅有一个直接前驱,但有零个或多个直接后继。
    在这里插入图片描述

基本术语

  1. 结点:包含一个数据元素及若干指向其它结点的分支信息
  2. 结点的度:一个结点的子树个数称为此结点的度。
  3. 叶结点:度为 0 的结点,即无后继的结点,也称为终端结点。
  4. 分支结点:度不为 0 的结点,也称为非终端结点。
    孩子结点:一个结点的直接后继称为该结点的孩子结点。
  5. 双亲结点:一个结点的直接前驱称为该结点的双亲结点。
  6. 兄弟结点:同一双亲结点的孩子结点之间互称兄弟结点。
  7. 祖先结点:一个结点的祖先结点是指从根结点到该结点的路径上的所有结点。
  8. 子孙结点:一个结点的直接后继和间接后继称为该结点的子孙结点。
  9. 树的度: 树中所有结点的度的最大值
  10. 结点的层次:从根结点开始定义,根结点的层次为1,根的直接后继的层次为2,依此类推。
  11. 树的高度(深度): 树中所有结点的层次的最大值。
  12. 有序树:在 树T 中,如果各子树Ti之间是有先后次序的,则称为有序树。
  13. 森林: m ( m ≥ 0 ) m(m \geq0) mm0 棵互不相交的树的集合。将一棵非空树的根结点删去,树就变成一个森林;反之,给森林增加一个统一的根结点,森林就变成一棵树。

二叉树

定义

我们把满足以下两个条件的树形结构叫做二叉树(Binary Tree):

  1. 每个结点的度都不大于2;
  2. 每个结点的孩子结点次序不能任意颠倒。

二叉树的五种基本形态

在这里插入图片描述

二叉树的特殊形式

满二叉树:

深度为 k k k 且有 2 k − 1 2k-1 2k1 个结点的二叉树。在满二叉树中,每层结点都是满的,即每层结点都具有最大结点数。

完全二叉树:

深度为 k k k ,结点数为 n n n 的二叉树,如果其结点 1 ∼ n 1 \sim n 1n 的位置序号分别与满二叉树的结点 1 ∼ n 1 \sim n 1n的位置序号一一对应(也就是深度为 1 ∼ k − 1 1 \sim k-1 1k1的所有结点都是满二叉树,第 k k k 层结点全部都靠在左边),则为完全二叉树.
在这里插入图片描述

性质

  1. 在二叉树的第 i i i 层上至多有 2 i − 1 2^{i-1} 2i1 个结点 ( i ≥ 1 ) ( i \geq 1) (i1)
  2. 深度为k的二叉树至多有 2 k − 1 2^{k}-1 2k1 个结点 ( k ≥ 1 ) (k \geq 1) k1
  3. 对任意一棵二叉树 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
  4. 具有 n n n 个结点的完全二叉树的深度为 i n t ( l o g 2 n ) + 1 int(log_{2}n)+1 int(log2n)+1
  5. 对于具有 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×in,则序号为i的结点的左孩子结点的序号为 2 × i 2 \times i 2×i
    (3) 如 2 × i + 1 > n 2 \times i+1>n 2×i1>n,则序号为 i i i 的结点无右孩子;如 2 × i + 1 ≤ n 2 \times i+1 \leq n 2×i1n, 则序号为i的结点的右孩子结点的序号为 2 × i + 1 2 \times i+1 2×i1

存储结构

二叉树的结构是非线性的, 每一结点最多可有两个后继。
二叉树的存储结构有两种: 顺序存储结构和链式存储结构。
1.顺序存储结构

在这里插入图片描述

在这里插入图片描述
2. 链式存储结构
对于任意的二叉树来说,每个结点最多只有两个孩子,一个双亲结点。我们可以设计每个结点至少包括三个域:数据域、 左孩子域 和 右孩子域.
用C++可以这样声明二叉树的二叉链表结点的结构:

typedef struct Node
{
	DataType data; 
	struct Node *LChild; 
	struct Node *RChild; 
}BiTNode,  *BiTree; 

在这里插入图片描述

遍历

在这里插入图片描述

我们用L、D、R分别表示遍历左子树、访问根结点、 遍历右子树, 那么对二叉树的遍历顺序就可以有六种方式:

  1. 访问根,遍历左子树,遍历右子树(记做DLR)。
  2. 访问根,遍历右子树,遍历左子树(记做DRL)。
  3. 遍历左子树,访问根,遍历右子树(记做LDR)。
  4. 遍历左子树,遍历右子树,访问根(记做LRD)。
  5. 遍历右子树,访问根,遍历左子树(记做RDL)。
  6. 遍历右子树,遍历左子树,访问根(记做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 。

例题

  1. 小球(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;
}
  1. 扩展二叉树

先用指针变量和线性链表建立一个二叉树,然后用递归分别输出中序序列和后续序列即可。

#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;
}

end

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值