数据结构和算法学习记录——二叉搜索树的插入操作、删除操作

简介: 数据结构和算法学习记录——二叉搜索树的插入操作、删除操作

二叉搜索树的插入

要进行二叉搜索树的插入,

关键点在于要找到元素应该插入到哪个位置,可以采用与Find类似的方法,

将要插入的节点与根节点进行比较,如果大于根节点,就往右边走;

若小于根节点,就往左边走;

直到某一个节点的左子树或者右子树为空就停止,进行节点的插入操作。

思路图解

代码实现

BinTree Insert(ElementType x, BinTree BST)
{
  if (!BST)    //若树为空,则创建并返回一个节点的二叉搜索树
  {
    BST = malloc(sizeof(struct TreeNode));
    BST->data = x;
    BST->Left = BST->Right = NULL;
  }
  else if (x > BST->data)     //开始查找要插入元素的位置
  {
    BST->Right = Insert(x, BST->Right);   //递归进入右子树
  }
  else if (x < BST->data)
  {
    BST->Left = Insert(x, BST->Left);    //递归进入左子树
  }
  //else
  //{
  //  //x匹配成功,则说明都不做
  //}
  return BST;
}

要点

需要注意的是:

当找到了新节点应该插入的位置时,需要通过找到上一个节点的地址,来将上一个节点的左子树指针或者右子树指针指向新节点。

例如:

例题

以一年十二个月的英文缩写为键值,按从一月到十二月的顺序输入

即输入序列为:

Jan、Feb、Mar、Apr、May、Jun、July、Aug、Sept、Oct、Nov、Dec。

它形成的二叉搜索树是怎样的呢?

这里月份缩写键值的比较,按照的是字母在字典中的排序大小,如A最小,Z最大。如果第一个字母相同,则继续比较第二个字母。

形成的二叉搜索树就为:

二叉搜索树的删除

二叉搜索树的删除需要考虑三种情况:

情况一

1.要删除的节点是叶节点:

那么就可以直接删除,并再修改该节点的父节点指针——置为空。

例:

情况二

2.要删除的节点只有一个孩子节点:

那么就将该节点的父节点的指针指向要删除节点的孩子节点。

例:

情况三

3.要删除的节点有左、右两颗子树:

这种情况是比较复杂的,我们把复杂的问题问题转换为简单的问题。

我们已经知道了没有孩子节点的情况和只有一个孩子节点的情况该怎么删除了,当有两个孩子节点的情况时,就考虑能不能把它变成只有一个孩子节点的情况来处理呢?

是可以实现的:用另一节点替代被删除的节点,这个节点应是右子树的最小元素或者左子树的最大元素。

例:

右子树的最小元素

左子树的最大元素

所以删除节点有两个孩子节点的情况下,我们就变成了在右子树找最小元素或者在左子树找最大元素的问题了。这样处理的好处是:左子树的最大值一定不是有两个孩子节点的情况、而右子树的最小值也一定不是有两个孩子节点的情况。

代码实现

BinTree Delete(ElementType x, BinTree BST)
{
  Position Tmp;
  if (!BST)
  {
    printf("要删除的元素未找到\n");
  }
  else if (x < BST->data)
  {
    BST->Left = Delete(x, BST->Left);  //查找节点,往左子树递归
  }
  else if (x > BST->data)
  {
    BST->Right = Delete(x, BST->Right);//查找节点,往右子树递归
  }
  else                                   //找到了要删除的节点
  {
    if (BST->Left && BST->Right)     //被删除的节点有左右两个孩子节点
    {
      Tmp = FindMin(BST->Right);   //在右子树中找到最小元素
      BST->data = Tmp->data;       //将最小元素填充到要删除的节点位置
      BST->Right = Delete(BST->data, BST->Right);
      //在要删除节点的右子树里删除那个最小元素
    }
    else                             //被删除的节点只有一个孩子节点或者没有孩子节点
    {
      Tmp = BST;
      if (!BST->Left)              //有右孩子节点或者没有孩子节点
      {
        BST = BST->Right;
      }
      else if (!BST->Right)        //有左孩子节点或者没有孩子节点
      {
        BST = BST->Left;
      }
      free(Tmp);
    }
  }
  return BST;
}

end



目录
相关文章
|
3月前
|
存储 监控 安全
企业上网监控系统中红黑树数据结构的 Python 算法实现与应用研究
企业上网监控系统需高效处理海量数据,传统数据结构存在性能瓶颈。红黑树通过自平衡机制,确保查找、插入、删除操作的时间复杂度稳定在 O(log n),适用于网络记录存储、设备信息维护及安全事件排序等场景。本文分析红黑树的理论基础、应用场景及 Python 实现,并探讨其在企业监控系统中的实践价值,提升系统性能与稳定性。
78 1
|
3月前
|
存储 监控 算法
基于跳表数据结构的企业局域网监控异常连接实时检测 C++ 算法研究
跳表(Skip List)是一种基于概率的数据结构,适用于企业局域网监控中海量连接记录的高效处理。其通过多层索引机制实现快速查找、插入和删除操作,时间复杂度为 $O(\log n)$,优于链表和平衡树。跳表在异常连接识别、黑名单管理和历史记录溯源等场景中表现出色,具备实现简单、支持范围查询等优势,是企业网络监控中动态数据管理的理想选择。
91 0
|
7月前
|
算法 数据可视化 开发者
为什么要学习数据结构与算法
今天,我向大家介绍一门非常重要的课程——《数据结构与算法》。这门课不仅是计算机学科的核心,更是每一位开发者从“小白”迈向“高手”的必经之路。
为什么要学习数据结构与算法
|
7月前
|
算法 Java
算法系列之数据结构-Huffman树
Huffman树(哈夫曼树)又称最优二叉树,是一种带权路径长度最短的二叉树,常用于信息传输、数据压缩等方面。它的构造基于字符出现的频率,通过将频率较低的字符组合在一起,最终形成一棵树。在Huffman树中,每个叶节点代表一个字符,而每个字符的编码则是从根节点到叶节点的路径所对应的二进制序列。
160 3
 算法系列之数据结构-Huffman树
|
7月前
|
算法 Java
算法系列之数据结构-二叉搜索树
二叉查找树(Binary Search Tree,简称BST)是一种常用的数据结构,它能够高效地进行查找、插入和删除操作。二叉查找树的特点是,对于树中的每个节点,其左子树中的所有节点都小于该节点,而右子树中的所有节点都大于该节点。
215 22
|
7月前
|
C语言 C++ 容器
【数据结构】二叉搜索树(二叉排序树)
本文介绍了二叉搜索树(Binary Search Tree, BST)的定义、实现及其性能分析。二叉搜索树是一种特殊的二叉树,其特点是左子树所有节点值小于根节点值,右子树所有节点值大于根节点值,且每个子树也满足此特性。文中详细讲解了BST的节点结构、插入、查找、删除等操作的实现,并通过C++代码展示了这些功能。此外,还讨论了BST的性能:在理想情况下,时间复杂度接近O(logN),但在最坏情况下可能退化为O(N)。为了提高效率,后续将学习自平衡二叉搜索树如AVL树和红黑树。掌握BST有助于理解STL中的set和map容器。感谢阅读,欢迎点赞支持。
494 9
|
11月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
229 59
|
4月前
|
编译器 C语言 C++
栈区的非法访问导致的死循环(x64)
这段内容主要分析了一段C语言代码在VS2022中形成死循环的原因,涉及栈区内存布局和数组越界问题。代码中`arr[15]`越界访问,修改了变量`i`的值,导致`for`循环条件始终为真,形成死循环。原因是VS2022栈区从低地址到高地址分配内存,`arr`数组与`i`相邻,`arr[15]`恰好覆盖`i`的地址。而在VS2019中,栈区先分配高地址再分配低地址,因此相同代码表现不同。这说明编译器对栈区内存分配顺序的实现差异会导致程序行为不一致,需避免数组越界以确保代码健壮性。
63 0
栈区的非法访问导致的死循环(x64)
232.用栈实现队列,225. 用队列实现栈
在232题中,通过两个栈(`stIn`和`stOut`)模拟队列的先入先出(FIFO)行为。`push`操作将元素压入`stIn`,`pop`和`peek`操作则通过将`stIn`的元素转移到`stOut`来实现队列的顺序访问。 225题则是利用单个队列(`que`)模拟栈的后入先出(LIFO)特性。通过多次调整队列头部元素的位置,确保弹出顺序符合栈的要求。`top`操作直接返回队列尾部元素,`empty`判断队列是否为空。 两题均仅使用基础数据结构操作,展示了栈与队列之间的转换逻辑。
|
9月前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
340 77

热门文章

最新文章