树和二叉树的基本概念
树+人类亲缘关系来定义树
树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的
下面介绍的概念中,重要的我会在前面打√,是你必须记住的内容
节点的度
一个节点含有的子树的个数(或者叫这个节点的孩子的个数)
√ 叶节点或终端节点
度为0的节点称为叶节点
非终端节点或分支节点
度不为0
√ 双亲节点或父节点
若一个节点含有子节点,则这个节点称为其子节点的父节点,如上图,A是B的父节点
√ 孩子节点或子节点
一个节点含有的子树的根节点称为该节点的子节点; 如上图:B是A的孩子节点
兄弟节点
具有相同父节点的节点互称为兄弟节点(这可是亲兄弟啊); 如上图:B、C是兄弟节点
√ 树的度
一棵树中,最大的节点的度称为树的度。
节点的层次
从根开始定义起,根为第1层,根的子节点为第2层,以此类推,就是一层一层往下走
√ 树的高度和深度
从根开始定义起,根为第1层,根的子节点为第2层,以此类推
空树的高度是0
堂兄弟节点
双亲在同一层的节点互为堂兄弟
节点的祖先
从根到该节点所经分支上的所有节点
子孙
以某节点为根的子树中任一节点都称为该节点的子孙。如上图:所有节点都是A的子孙
森林(多棵树)
互不相交的树,后续会学到并查集和文件系统都是森林
任何一棵树都包含根和子树,即 [根+N棵子树(N>=0)],树是递归定义的,树是根加子树构成,子树是根加子树构成,子树的子树……
递归定义通俗来说就是套娃,把大问题拆解为小问题(分治问题),这里的树,可以拆成根和子树,子树又可以拆成根和子树……
树和非树
- 子树之间是不相交的,是没关联的
- 除了根节点外,每个节点有且仅有一个父节点
- 一棵N个节点的树有N-1条边
树的表示
说了这么多,上代码看看,我们怎么用代码来定义一个树,有两种情况:
明确告诉树的度
#define N 4//明确告诉树的度是4
struct TreeNode
{
int val;
struct TreeNode* subs[N];
};
没有明确说树的度
使用顺序表来表示
struct TreeNode
{
int val;
Seqlist subs;//顺序表内部存动态开辟的struct TreeNode*
vector<struct TreeNode*> subs;//后续C++直接就可以用容器来存,方便得很
};
但是上面两个方式都不够好
最牛B的方式–左孩子右兄弟表示法
struct TreeNode
{
int val;
struct TreeNode* leftChild;
struct TreeNode* rightBrother;
};
二叉树
一棵二叉树是结点的一个有限集合,该集合或者为空,或者是由一个根节点加上两棵别称为左子
树和右子树的二叉树组成。
- 每个结点最多有两棵子树,即二叉树不存在度大于2的结点。
- 二叉树的子树有左右之分,其子树的次序不能颠倒。
特殊的二叉树
满二叉树和完全二叉树
满二叉树就是每一层都是满的,都生了两个
完全二叉树:前h-1层都是满的,第h层不是满的
完美的满二叉树~~
二叉树的存储
两种存储方式–二叉链表和三叉链表
因为是初步,所以我们先学习二叉链表
顺序存储:
数组的存储也是有局限性的,它只适用于完全二叉树和满二叉树,如果不是就不适合了,因为不是连续的:
这里是不能连续存的,会破坏父子关系
用数组存储,可以是可以,但是会存在很多空间浪费
非完全二叉树只适合用链式结构存储,空就是NULL指针就行
链式存储
(敬请期待……)