数据结构中树的类型

2025年3月17日 | 阅读 21 分钟

在理解数据结构中的树类型之前,让我们先了解什么是树作为数据结构。树可以定义为一种非线性数据结构,它以节点的形式存储数据,并且节点通过边相互连接。在所有节点中,有一个主节点称为根节点,所有其他节点都是这些节点的子节点。存在一些属性或规则,每个节点都应该遵循或满足。这些规则是:

  • 每棵树都从一个主节点(称为根节点)开始。所有其他节点都是此根节点的子节点。根节点没有父节点。
  • 树中的每个节点可以与父节点关联多个子节点,但每个子节点严格来说只能有一个父节点。
  • 树中的每个父节点通过边与其子节点连接,该边用于在需要遍历树时进行遍历。在某些类型的树中,它们的边被赋予一个数字值,称为成本,用于确定遍历的总体成本,或者通过将连接到该特定节点与根节点的所有边相加来计算遍历该特定节点或遍历该节点的成本。

正如我们在上图中看到的,显示了一棵树,其根节点名为A,有三个子节点B、C和D。子节点B又有两个子节点E和F。同样,节点C有三个子节点G、H和I。节点D也有J和K作为子节点。如果我们想遍历到节点J,首先我们会从根节点A开始,然后去子节点D,最后到达节点J。

可用的树的各种类型

  • 通用树
  • 二叉树
  • 二叉搜索树
  • AVL 树
  • 红黑树
  • N叉树

现在让我们详细了解它们中的每一个,以便更好地理解它们。

通用树

通用树是树数据结构的基本形式之一。在通用树中,每个节点可以有零个或多于零个子节点。通用树的子树不保持有序属性。在通用树中,一个节点最多可以有 n(子节点数)个节点。如果不对树的层次结构施加任何限制,则该树称为通用树。在通用树中,每个节点都可以有无限数量的子节点。树是所有其他树的超集。

代码

输出

Printing the nodes of tree level wise :
Level order traversal :
(level 0) 10
(level 1) 2 34 56 100
(level 2) 77 88 1 7 8 9

在上面编写的代码中,我们创建了一个名为 GenralTree 的类,其中有一个名为 Node 的静态内部类,它将表示树的实际节点。我们还有一个公共静态函数 newNode,用于将新节点添加到树中,并将新添加节点的值作为参数传递给此 newNode 函数。

在 main 函数中,我们首先创建了一个名为 Node 的内部静态类的对象作为根节点,其值为 10。然后,我们向根节点添加了四个子节点,其值为 2、34、56 和 100。新添加的四个子节点将位于第 1 层,根节点将位于第 0 层。现在,我们向第 1 层中的第一个节点(即值为 2 的节点)添加了两个子节点,其值分别为 77 和 88。此外,我们向第 1 层中的第二个节点(即值为 34 的节点)添加了一个子节点,其值为 1。最后,我们向第 1 层中的最后一个节点(即值为 100 的节点)添加了三个子节点,其值分别为 7、8 和 9。

成功创建树后,我们按层级打印了树,这意味着会打印一层中的节点,然后打印下一层中的节点,直到耗尽树中的所有节点。

为了按层级打印树,我们创建了一个名为 LevelOrderTraversal 的函数,它将按层级打印树。在成功创建树之后,我们将根节点作为参数传递给 LevelOrderTraversal 函数来调用它。

二叉树

二叉树可以定义为一种树,其中每个父节点最多可以添加两个子节点。子节点称为左子节点和右子节点。二叉树是最流行的树之一。当我们对二叉树应用各种约束和特性时,会形成各种其他树,例如 AVL 树、BST(二叉搜索树)、RBT 树等。我们将在后续讨论中详细解释这些类型的树。

换句话说,我们可以说,一个元素最多有两个子节点的通用树称为二叉树。由于二叉树中的每个元素最多只有 2 个子节点,我们通常称它们为左子节点和右子节点。

二叉树节点包含以下部分:

  • 数据
  • 指向左子节点的指针
  • 指向右子节点的指针

代码

输出

Printing the nodes of tree level wise :
Level order traversal :
(level 0) 150
(level 1) 250 270
(level 2) 320 350

在上面编写的代码中,我们创建了一个名为 BinaryTree 的类,其中有一个名为 Node 的另一个类,它将表示树的实际节点。

在 main 函数中,我们首先创建了一个名为 Node 的类的对象作为根节点,其值为 150。然后,我们向根节点添加了两个子节点,其值分别为 250 和 270。新添加的两个子节点将位于第 1 层,根节点将位于第 0 层。现在,我们向第 1 层中的第一个节点(即值为 250 的节点)添加了两个子节点,其值分别为 320 和 350。

成功创建树后,我们按层级打印了树,这意味着会打印一层中的节点,然后打印下一层中的节点,直到耗尽树中的所有节点。

为了按层级打印树,我们创建了一个名为 printLevelOrder 的函数,它将按层级打印树。在成功创建树之后,我们调用了 printLevelOrder 函数。

二叉搜索树

二叉搜索树(也称为 BST)是具有各种限制的二叉树的扩展。

二叉搜索树中的主要约束是,节点左子节点的值应小于或等于父节点的值,并且右子节点的值应大于或等于父节点的值。

顾名思义,二叉搜索树最适合搜索操作,因为在每个节点,我们都可以确定移动到哪里,也就是说,如果我们处于某个节点,并且我们的搜索键的值小于该节点的值,那么我们需要向左移动,反之亦然,如果搜索键的值更大。

代码

输出

Printing the nodes of tree level wise :
Level order traversal :
(level 0) 50
(level 1) 30 70
(level 2) 20 40 60 80

在上面编写的代码中,创建了一个以值为 50 的根节点为根的二叉搜索树,然后分别向其添加了一个值为 30 的左子节点和值为 70 的右子节点。然后,我们向第 1 层中的左子节点(值为 20 和 40)添加了一个左子节点和右子节点;之后,我们向根节点的第 1 层中的右子节点(值为 60 和 80)添加了一个左子节点和右子节点。

成功创建树后,我们按层级打印了树,这意味着会打印一层中的节点,然后打印下一层中的节点,直到耗尽树中的所有节点。

为了按层级打印树,我们创建了一个名为 printLevelOrder 的函数,它将按层级打印树。在成功创建树之后,我们调用了 printLevelOrder 函数。

AVL 树

AVL 树可以定义为一种自平衡二叉搜索树。AVL 这个名字是以发明者 Adelson-Velshi 和 Landis 的名字命名的。AVL 树具有动态平衡树节点的属性。添加了一个名为平衡因子的附加指标,用于确定 AVL 树中每个节点是否需要平衡树或子树。节点的高度最多为 1。在 AVL 树中,正确的平衡因子是 1、0 和 -1。如果树有新节点,它将被旋转以确保其平衡。

AVL 树中的查看、插入和删除等各种操作需要 O(log n) 的时间。它主要应用于查找操作。

代码

输出

Printing the nodes of tree-level wise :
Level order traversal :
45
24 87
12 33 94

红黑树

与 AVL 树一样,红黑树也是一种自动平衡树。之所以称为红黑树,是因为每个节点根据某些条件具有红色或黑色的特定颜色。由于它是一种自平衡树,它会维护树的整体平衡。在 AVL 树上,搜索操作只需 O(log n) 时间。在红黑树中添加新节点会导致现有节点旋转,以维护红黑树的属性。

代码

输出

Printing the nodes of tree level wise :
Level order traversal :
 
| THREE | B | ONE | TWO |
 
| ONE | B | FOUR | NULL | | TWO | B | NULL | NULL |
 
| FOUR | R | NULL | NULL |

因此,在上面的代码中,我们成功地实现了具有插入和遍历操作的红黑树。输出中打印的数据顺序是:

  • 节点中的数据
  • 该节点的颜色
  • 该特定节点的左子节点
  • 该特定节点的右子节点

如果树的右子节点或左子节点为 NULL,则表示该特定节点分别没有右子节点或左子节点。

N叉树

在 N 叉树中,与前面的父节点关联的最大子节点数是 N。N 叉树与通用树或泛型树非常相似,后者也可以在树中包含任意数量的节点。

在 Java 编程语言中,N 叉树的实现与通用树完全相同。

因此,在本文中,我们清楚地了解了不同类型的树,并简要地回顾了它们中的每一种,以便更好地理解。我们还为通用树、二叉树、二叉搜索树、AVL 树、红黑树和 N 叉树等所有这些类型的树实现了示例 Java 代码。