数据结构(树)
树形结构是一种非常重要的数据结构,它被广泛用于各种实际应用中,如文件系统、搜索引擎、数据库索引等;常用来做查询操作
树的基本概念#
节点(Node):树形结构中的基本元素,它可以是数据元素,也可以是一个空指针。
边(Edge):连接两个节点的线段,表示父子关系。
子树(Subtree):以某个节点为根节点的树。
父节点(Parent Node):一个节点在树中直接上层节点。
祖先节点(Ancestor Node):从根节点到该节点所经过的所有节点。
子孙节点(Descendant Node):以该节点为根的子树中所有节点。
根节点(Root Node):树中最顶层的节点,它没有父节点。
叶子节点(Leaf Node):没有子节点的节点。
树的深度(Depth):树中节点的层最大数。
树的度(Degree):树中所有节点度的最大值。
常见的树结构#
二叉搜索树(Binary Search Tree):也叫做二叉查找树、有序二叉树或者排序二叉树。是指一棵空树或者具有下列性质的二叉树:
- 如果任意节点的左子树不为空,则左子树上所有节点的值均小于它的根节点的值。
- 如果任意节点的右子树不为空,则右子树上所有节点的值均大于它的根节点的值。
- 任意节点的左子树、右子树均为二叉搜索树。
平衡二叉树(Balanced Binary Tree):它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。平衡二叉树的常用实现方法有红黑树、AVL、替罪羊树、Treap、伸展树等。 最小二叉平衡树的节点的公式如下 F(n)=F(n-1)+F(n-2)+1 这个类似于一个递归的数列,可以参考Fibonacci数列,1是根节点,F(n-1)是左子树的节点数量,F(n-2)是右子树的节点数量
AVL树:AVL树是高度平衡的二叉树。它的特点是: AVL树中任何节点的两个子树的高度最大差别为1,AVL树的平衡性要求更加严格,因此在插入和删除操作时可能需要进行更多的旋转操作来保持平衡,这可能会导致性能略低于其他平衡二叉树
红黑树(Red Black Tree) 红黑树是一种自平衡的二叉搜索树,它通过引入“颜色”来保持树的大致平衡,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组,是平衡二叉树和AVL树的折中
红黑树与AVL树的比较:
- AVL树的时间复杂度虽然优于红黑树,但是对于现在的计算机,cpu太快,可以忽略性能差异
- 红黑树的插入删除比AVL树更便于控制操作
- 红黑树整体性能略优于AVL树(红黑树旋转情况少于AVL树)
B树(B-tree):多路搜索树,每个节点可以拥有多个子节点。
- 优点:适合大规模数据存储,减少磁盘I/O操作;搜索、插入和删除的时间复杂度稳定在O(log n)。
- 缺点:实现复杂,不适合小规模数据。
B+树(B+ tree) 基于B树的一种树结构,叶节点之间通过指针连接形成有序链表
- 优点:适合大规模数据存储,减少磁盘I/O操作;范围查询效率高。
- 缺点:实现复杂。
Trie树(前缀树) 多叉树,用于存储字符串集合,通常用于字符串检索。
- 优点:适合前缀匹配检索;搜索效率高。
- 缺点:空间消耗较大。
Java实现树形结构#
前面我们知道有很多不同的树结构,每种树结构都有不同的存储方式。比如二叉树、平衡二叉树、AVL树等,为了减少树的深度而做特殊的扁平化处理;下面是一个简单的二叉树示例:
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) {
val = x;
}
}
public class BinaryTree {
private TreeNode root;
public void addElement(int value) {
root = addElementToTree(root, value);
}
private TreeNode addElementToTree(TreeNode node, int value) {
if (node == null) {
return new TreeNode(value);
}
if (value < node.val) {
node.left = addElementToTree(node.left, value);
} else if (value > node.val) {
node.right = addElementToTree(node.right, value);
}
return node;
}
}
将第一个元素当作根节点,小于val则放入left,大于val放入right节点。但这种方式很容易发生不平衡的情况,极有可能很形成链表的方式。导致出现复杂度O(n)的情况;所以后续引入的平衡二叉树的概念,通过旋转的方式调整树的结构
4种常见的遍历方式#
前序遍历 访问根结点;先序遍历左子树;先序遍历右子树。
中序遍历 中序遍历左子树;访问根结点;中序遍历右子树。
后序遍历 后序遍历左子树;后序遍历右子树;访问根结点。
层序遍历 从上到下、从左到右依次访问每一个节点
public class TreeTraversal {
// 前序遍历
public void preOrder(TreeNode root) {
if (root != null) {
System.out.print(root.val + " ");
preOrder(root.left);
preOrder(root.right);
}
}
// 中序遍历
public void inOrder(TreeNode root) {
if (root != null) {
inOrder(root.left);
System.out.print(root.val + " ");
inOrder(root.right);
}
}
// 后序遍历
public void postOrder(TreeNode root) {
if (root != null) {
postOrder(root.left);
postOrder(root.right);
System.out.print(root.val + " ");
}
}
// 层序遍历
public void levelOrder(TreeNode root) {
if (root == null) {
return;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
TreeNode node = queue.poll();
System.out.print(node.val + " ");
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
}
}
public static void main(String[] args) {
TreeNode root = new TreeNode(1);
root.left = new TreeNode(2);
root.right = new TreeNode(3);
root.left.left = new TreeNode(4);
root.left.right = new TreeNode(5);
}
}
运行这段代码将输出以下结果:
前序遍历:
1 2 4 5 3
中序遍历:
4 2 5 1 3
后序遍历:
4 5 2 3 1
层序遍历:
1 2 3 4 5
总结#
树形结构是一种非常有用的数据结构,它可以帮助我们有效地管理和处理具有层次关系的数据。在Java中,我们可以使用类来表示树的节点,并通过添加和删除节点来操作树形结构。
了解更多:https://www.cnblogs.com/henuliulei/p/15114440.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了