树的概念
树型结构
树型结构是非线性结构,树是一种由有限结点组成的集合,具有一对多的性质
![](https://s1.imgbed.xyz/2022/10/25/A9BSA.png)
树型结构像是一个棵上下颠倒的树,根在上,叶子在下
![二叉树](https://s1.imgbed.xyz/2022/10/25/A9fB4.png)
除了根结点和叶结点外,每个结点的前驱只会有一个,后继结点可以有多个
子树不会相交;
除了根结点外,每个结点只有一个父结点(前驱);
当一颗树的结点数为n时,边的数量为n-1;
基本概念
![](https://s1.imgbed.xyz/2022/10/26/A93vg.png)
结点的度:结点具有的子树的个数称为度
树的度:整棵树中所有的结点的度的最大值
根结点:结点没有前驱(父结点),如A点即为根结点
叶结点:结点没有后继(孩子结点),即结点的度为0,如D,E,F,G
父结点:一个结点的"后继"指向其他结点,此时该结点为其他结点的父结点
孩子结点:子树的根结点为一个结点的"后继",该子树的根结点则为这个结点的孩子结点,如B,C 为A 的孩子结点
结点的层次:以根结点为第一层,其子结点则为下一层
树的高度:树具有的最大的结点层次,上图树的高度即为3
子树:
其他概念
兄弟结点:具有相同父结点的其他结点可称为兄弟结点
结点祖先:从一个结点开始向父结点溯源至根结点的所有结点都为该节点的祖先,如上图D 结点的祖先为B和A
森林:由多棵不相交的树组成的集合称为森林
树的应用
树的应用范围十分广泛,如文件目录,树的特殊形式——二叉树更是数据结构中十分重要的一种结构
二叉树
概念
二叉树是树的一种特殊形式,在二叉树中,每个结点的度最大为2,即对一个结点而言,一个结点最多有两棵子树
特殊形式
完全二叉树
完全二叉树:在二叉树结构中,除最后一层外其他层结点数都为最大值,叶结点只出现在最后两层,若在倒数第二层则在右部连续,若在最后一层则在左部连续;当结点的度为1时,其孩子必为叶结点且为左叶结点
![https://s1.imgbed.xyz/2022/10/27/AgvG7.png](https://s1.imgbed.xyz/2022/10/27/AgvG7.png)
![](https://s1.imgbed.xyz/2022/10/27/AgiJL.png)
满二叉树
满二叉树与完全二叉树相似,但是满二叉树除了最后一层外无叶结点,每层结点数都达到最大值
![](https://s1.imgbed.xyz/2022/10/27/AgGHb.png)
性质
根据二叉树的特殊形式,可推导出的特殊性质有**(前提:根结点编号为0)**:
-
假设根结点的层数为1,层数为 i 的结点的最大个数为 2 i − 1 2^{i-1} 2i−1
-
假设根结点的层数为1,若树的高度为k,则结点的最大个数为 2 k − 1 2^{k}-1 2k−1
-
任一二叉树,如果其叶结点个数为l,度为2的结点个数为n,则有 l = n + 1
-
具有n个结点的二叉树,其最大高度为 [ log 2 n ] + 1 [\log_{2}{n}]+1 [log2n]+1
( [ log 2 n ] [\log_{2}{n}] [log2n]向下取整) -
对有n个结点的二叉树编号,从上至下,从左向右编号,如上图满二叉树,则对于序号i的结点有:
i > 0 时,父结点编号为(i-1)/2;i = 0 即为根结点
若2i + 1 < n,则存在左孩子结点,编号为2i + 1
同理2i + 2 < n,存在右孩子结点,编号为2i + 2
存储
顺序结构:存储在类似数组的结构中,根据序号建立二叉树,可用于建堆,排序等,一般用于完全二叉树
类似链式存储结构:
双亲表示法:存储数据的同时记录指向父结点的引用
class Node {
Object date;//数据域
Node parent;//父结点引用
}
孩子表示法:存储数据的同时记录指向子结点的引用
class Node {
Object date;//数据域
Node leftChild;//左孩子引用
Node rightChild;//右孩子引用
}
同时可以将孩子表示法与双亲表示法结合成为孩子双亲表示法
孩子兄弟表示法:存储数据的同时记录指向子结点和右兄弟结点的引用
class Node {
Object date;//数据域
Node firstChild;//第一个子结点引用
Node rightBro;//右兄弟结点引用
}
基本操作
要模仿实现树的操作,首先我们要创建一棵树
public class Tree {
TreeNode root;
public static class TreeNode {
int date;//数据域
TreeNode leftChild;//左孩子引用
TreeNode rightChild;//右孩子引用
public TreeNode(int date) {
this.date = date;
}
}
public void creatTree() {//手动创建一棵树
TreeNode node1 = new TreeNode(1);
TreeNode node2 = new TreeNode(2);
TreeNode node3 = new TreeNode(3);
TreeNode node4 = new TreeNode(4);
TreeNode node5 = new TreeNode(5);
TreeNode node6 = new TreeNode(6);
root = node1;
node1.leftChild = node2;
node1.rightChild = node3;
node2.leftChild = node4;
node2.rightChild = node5;
node3.leftChild = node6;
}
public static void main(String[] args) {
Tree tree = new Tree();
tree.creatTree();
System.out.println(tree.root.date);
}
}
此时创建的树的结构图为
![](https://s1.imgbed.xyz/2022/10/27/AkBhu.png)
遍历
二叉树的形式契合递归方式进行实现和操作,而二叉树中的crud(增删查改)多数都有递归 与遍历的应用,所以二叉树的遍历是需要重点要掌握的一个内容
前序遍历
前序遍历:当遍历到当前结点时就对当前结点进行操作,然后由左至右对子结点进行遍历
public void preOrder(TreeNode root) {
if(root == null){
return;
}
func();//对数据进行的操作
preOrder(root.leftChild);
preOrder(root.rightChild);
}
//当func()为println时,结果:1 2 4 5 3 6
中序遍历
中序遍历:优先遍历左子结点,到当前结点为Null时返回,进行数据操作,然后对右子结点进行遍历
public void inOrder(TreeNode root) {
if(root == null){
return;
}
inOrder(root.leftChild);
func();//对数据进行的操作
inOrder(root.rightChild);
}
//当func()为println时,结果:4 2 5 1 6 3
后序遍历
中序遍历:优先遍历左子结点,到当前结点为Null时返回,进行右子结点的遍历,然后再进行数据操作
public void postOrder(TreeNode root) {
if(root == null){
return;
}
postOrder(root.left);
postOrder(root.right);
func();//对数据进行的操作
}
其他操作
方法 | 摘要 |
---|---|
int size(Node root) | 获取树中节点的个数 |
int getLeafNodeCount(Node root) | 获取叶子节点的个数 |
int getKLevelNodeCount(Node root) | 获取第K层节点的个数 |
Node find(Node root, int val) | 检测值为value的元素是否存在 |
void levelOrder(Node root) | 层序遍历 |
boolean isCompleteTree(Node root) | 判断一棵树是不是完全二叉树 |
*本文的主要目的是充当学习笔记,同时强化学习效果,且兼有分享所学知识之意,欢迎批评指正。*