二叉搜索树
二叉搜索树
二叉搜索树
在本文中,我们将讨论二叉搜索树。本文将对具有技术背景的学生非常有帮助和信息,因为它是他们课程的重要主题。
在直接进入二叉搜索树之前,让我们先看一下树的简要说明。
什么是树?
树是一种数据结构,用于以分层形式表示数据。它可以定义为称为节点的对象或实体的集合,它们链接在一起以模拟层次结构。树是一种非线性数据结构,因为树中的数据不是线性或顺序存储的。
现在,让我们开始讨论二叉搜索树。
什么是二叉搜索树?
二叉搜索树遵循某种顺序来排列元素。在二叉搜索树中,左节点的值必须小于父节点,右节点的值必须大于父节点。该规则递归地应用于根的左子树和右子树。
让我们通过一个例子来理解二叉搜索树的概念。
上图中,我们可以观察到根节点为40,左子树的所有节点都小于根节点,右子树的所有节点都大于根节点。
同样,我们可以看到根节点的左子节点大于其左子节点且小于其右子节点。因此,它也满足二叉搜索树的性质。因此,我们可以说上图中的树是二叉搜索树。
假设如果我们将上述树中节点 35 的值更改为 55,则检查该树是否为二叉搜索树。
在上述树中,根节点的值为40,大于其左孩子30,但小于其右孩子30,即55。因此,上述树不满足二叉搜索树的性质。因此,上述树不是二叉搜索树。
二叉搜索树的优点
- 在二叉搜索树中搜索元素很容易,因为我们总是会提示哪个子树具有所需的元素。
- 与数组和链表相比,BST 中的插入和删除操作更快。
创建二叉搜索树的示例
现在,让我们用一个例子来看看二叉搜索树的创建。
假设数据元素是 — 45、15、79、90、10、55、12、20、50
- 首先,我们必须插入 45 入树为树根。
- 然后,读取下一个元素;如果它小于根节点,则将其作为左子树的根插入,并移动到下一个元素。
- 否则,如果元素大于根节点,则将其插入为右子树的根。
现在,让我们看看使用给定数据元素创建二叉搜索树的过程。创建 BST 的过程如下所示 -
第 1 步——插入 45。
第 2 步 — 插入 15。
由于 15 小于 45,所以将其作为左子树的根节点插入。
第 3 步——插入 79。
由于79大于45,所以插入它作为右子树的根节点。
第 4 步 — 插入 90。
90 大于 45 和 79,因此将作为 79 的右子树插入。
第 5 步 — 插入 10。
10 小于 45 和 15,因此将作为 15 的左子树插入。
第 6 步 — 插入 55。
55大于45小于79,所以会作为79的左子树插入。
第 7 步 — 插入 12。
12 小于 45 和 15 但大于 10,因此将作为 10 的右子树插入。
第 8 步 — 插入 20。
20 小于 45 但大于 15,因此将作为 15 的右子树插入。
第 9 步 — 插入 50。
50 大于 45 但小于 79 和 55。因此,它将作为 55 的左子树插入。
至此,二叉搜索树的创建就完成了。之后,让我们转向可以在二叉搜索树上执行的操作。
我们可以对二叉搜索树进行插入、删除和搜索操作。
让我们了解如何在二叉搜索树上执行搜索。
在二叉搜索树中搜索
搜索意味着查找或定位数据结构中的特定元素或节点。在二叉搜索树中,搜索节点很容易,因为 BST 中的元素以特定顺序存储。在二叉搜索树中搜索节点的步骤如下:
- 首先,将要搜索的元素与树的根元素进行比较。
- 如果 root 与目标元素匹配,则返回节点的位置。
- 如果不匹配,则检查该项是否小于根元素,如果小于根元素,则移动到左子树。
- 如果它大于根元素,则移动到右子树。
- 递归重复上述过程,直到找到匹配项。
- 如果在树中未找到或不存在该元素,则返回 NULL。
现在,让我们通过一个例子来理解二叉树中的搜索。我们采用上面形成的二叉搜索树。假设我们必须从下面的树中找到节点 20。
步骤1:
第2步:
第三步:
现在,让我们看看在二叉搜索树中搜索元素的算法。
在二叉搜索树中搜索元素的算法
- 搜索(根,项目)
- 第 1 步 — 如果 (item = root → data) 或 (root = NULL)
- 返回根
- else if (item < root → data)
- 返回搜索(根→左,项目)
- 别的
- 返回搜索(根→右,项目)
- 万一
- 第 2 步 — 结束
现在让我们了解如何在二叉搜索树上执行删除。我们还将看到一个从给定树中删除元素的示例。
二叉搜索树中的删除
在二叉搜索树中,我们必须牢记不违反 BST 的性质,从树中删除一个节点。要从 BST 中删除节点,可能会出现三种情况 -
- 要删除的节点是叶子节点,或者,
- 要删除的节点只有一个孩子,并且,
- 要删除的节点有两个孩子
我们将详细了解上面列出的情况。
当要删除的节点是叶子节点时
在 BST 中删除一个节点是最简单的情况。在这里,我们必须用 NULL 替换叶子节点并简单地释放分配的空间。
我们可以在下图中看到从 BST 中删除叶节点的过程。在下图中,假设我们要删除节点 90,因为要删除的节点是叶子节点,所以将其替换为 NULL,分配的空间将被释放。
当要删除的节点只有一个孩子时
在这种情况下,我们必须将目标节点替换为其子节点,然后删除子节点。这意味着在将目标节点替换为其子节点后,子节点现在将包含要删除的值。因此,我们只需将子节点替换为 NULL 并释放分配的空间。
我们可以在下图中看到从 BST 中删除具有一个子节点的过程。在下图中,假设我们要删除节点 79,因为要删除的节点只有一个子节点,所以将其替换为子节点 55。
因此,被替换的节点 79 现在将是一个可以轻松删除的叶节点。
当要删除的节点有两个孩子时
这种在 BST 中删除节点的情况在其他两种情况中有点复杂。在这种情况下,应遵循的步骤如下:
- 首先,找到要删除的节点的中序后继。
- 之后,将该节点替换为中序后继节点,直到目标节点位于树的叶子上。
- 最后,将节点替换为 NULL 并释放分配的空间。
当节点的右孩子不为空时,需要中序后继。我们可以通过在节点的右孩子中找到最小元素来获得中序后继。
我们可以在下图中看到从 BST 中删除具有两个子节点的节点的过程。在下图中,假设我们要删除节点 45,即根节点,因为要删除的节点有两个子节点,所以将其替换为其中序后继节点。现在,节点 45 将位于树的叶子上,以便可以轻松删除它。
现在让我们了解如何在二叉搜索树上执行插入操作。
在二叉搜索树中插入
BST 中的新密钥总是插入到叶子中。要在 BST 中插入元素,我们必须从根节点开始搜索;如果要插入的节点小于根节点,则在左子树中搜索一个空位置。否则,在右子树中搜索空位置并插入数据。 BST中的插入类似于搜索,因为我们总是要保持左子树小于根,右子树大于根的规则。
现在,让我们通过一个示例来看看将节点插入 BST 的过程。
二叉搜索树的复杂性
让我们看看二叉搜索树的时间和空间复杂度。我们将看到在最佳情况、平均情况和最坏情况下插入、删除和搜索操作的时间复杂度。
1.时间复杂度
操作 最佳情况时间复杂度 平均情况时间复杂度 最坏情况时间复杂度 插入 O(log n) O(log n) O(n) 删除 O(log n) O(log n) O(n) 搜索 O(log n) O(log n) O(n)
其中“n”是给定树中的节点数。
2. 空间复杂度
操作空间复杂度 插入 上) 删除 上) 搜索 上)
- 二叉搜索树所有操作的空间复杂度为O(n)。
二叉搜索树的实现
现在,让我们看看实现二叉搜索树操作的程序。
程序: 编写一个程序以在 C++ 中执行二叉搜索树的操作。
在这个程序中,我们将看到二叉搜索树操作的实现。在这里,我们将看到树的创建、中序遍历、插入和删除操作。
在这里,我们将看到树的中序遍历来检查树的节点是否在正确的位置。我们知道中序遍历总是以升序为我们提供数据。所以,在执行完插入和删除操作之后,我们进行中序遍历,遍历之后,如果我们得到数据是升序的,那么很明显节点在正确的位置。
- #包括
- 使用命名空间标准;
- 结构节点{
- 整数数据;
- 节点*左;
- 节点 *right;
- };
- 节点*创建(整数项)
- {
- 节点*节点=新节点;
- 节点->数据=项目;
- 节点->左=节点->右=空;
- 返回节点;
- }
- /形成的树的中序遍历/
- 无效顺序(节点*根)
- {
- 如果(根 == NULL)
- 返回;
- 中序(根->左); //遍历左子树
- cout<<根->数据<<“”; //遍历根节点
- 中序(根-> 右); //遍历右子树
- }
- Node* findMinimum(Node* cur) /寻找中序后继/
- {
- 而(当前->左!= NULL){
- cur = cur->左;
- }
- 返回当前;
- }
- Node* insert(Node* root, int item) /插入一个节点/
- {
- 如果(根 == NULL)
- 返回创建(项目); /如果树为空,则返回新节点/
- 如果(项目<根->数据)
- 根->左=插入(根->左,项目);
- 别的
- root->right = 插入(root->right, item);
- 返回根;
- }
- 无效搜索(节点* &cur,int 项目,节点* &parent)
- {
- while (cur != NULL && cur->data != item)
- {
- 父母=当前;
- 如果(项目<当前->数据)
- cur = cur->左;
- 别的
- cur = cur->正确;
- }
- }
- void delete(Node& root, int item) /删除节点的函数*/
- {
- 节点* 父级 = NULL;
- 节点* cur = 根;
- 搜索(当前,项目,父); /找到要删除的节点/
- 如果(cur == NULL)
- 返回;
- if (cur->left == NULL && cur->right == NULL) /当节点没有子节点时/
- {
- if (cur != root)
- {
- if (parent->left == cur)
- 父->左= NULL;
- 别的
- 父->右=空;
- }
- 别的
- 根=空;
- 免费(当前);
- }
- else if (cur->left && cur->right)
- {
- 节点* succ = findMinimum(cur->right);
- int val = succ->数据;
- 删除(根,成功->数据);
- 当前->数据= val;
- }
- 别的
- {
- 节点*子 = (cur->left)?当前->左:当前->右;
- if (cur != root)
- {
- if (cur == parent->left)
- 父母->左=孩子;
- 别的
- 父母->权利=孩子;
- }
- 别的
- 根=孩子;
- 免费(当前);
- }
- }
- 主函数()
- {
- 节点*根 = NULL;
- 根=插入(根,45);
- 根=插入(根,30);
- 根=插入(根,50);
- 根=插入(根,25);
- 根=插入(根,35);
- 根=插入(根,45);
- 根=插入(根,60);
- 根=插入(根,4);
- printf(“给定二叉树的中序遍历是—\n”);
- 有序(根);
- 删除(根,25);
- printf(“\n删除节点25后,给定二叉树的中序遍历为——\n”);
- 有序(根);
- 插入(根,2);
- printf(“\n插入节点2后,给定二叉树的中序遍历为——\n”);
- 有序(根);
- 返回0;
- }
输出
执行上述代码后,输出将是 -
所以,这就是这篇文章的全部内容。希望这篇文章对您有所帮助和信息。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明