【数据结构】二叉查找树和平衡二叉树,以及二者的区别

2024-02-18 02:44

本文主要是介绍【数据结构】二叉查找树和平衡二叉树,以及二者的区别,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

1、二叉查找树

1.1、定义

 1.2、查找二叉树的优点

 1.2、查找二叉树的弊端

2、平衡二叉树

2.1、定义

2.2、 实现树结构平衡的方法(旋转机制)

2.2.1、左旋

2.2.2、右旋

3、总结

1、二叉查找树

       二叉查找树又名二叉排序树,亦称二叉搜索树。是每个结点最多有两个子树的树结构,通常子树被称作“左子树”和“右子树”。

1.1、定义

二叉查找树的定义:

  1. 若左子树不空,则左子树上所有节点的值均小于它的根节点的值;
  2. 若右子树不空,则右子树上所有节点的值均大于它的根节点的值;
  3. 左、右子树也分别为二叉排序树;
  4. 没有键值相等的节点。

 1.2、查找二叉树的优点

普通二叉树和二叉查找树示例图如下所示:

       上图中左边为普通二叉树,它的弊端是对数据的插入没有要求,在进行数据的查找时就非常的麻烦,因为它里面的数据没有什么规律让我们进行查找。普通的二叉树如果想要查找数据的话就只能进行遍历,查找的效率非常的低。

        所以就有了上图中右边的二叉查找树,因为二叉查找树插入数据的时的规律是:小的存左边;大的存右边;一样的不存,并且它在查找数据的时候也是按照这个规律来进行查找的

 1.2、查找二叉树的弊端

现有数字{ 3,6,7,9,10,11,12 } ,基于这些数字生成二叉查找树如下:

这时候看起来二叉树的结构是很均匀的排列的,但是当依次插入13,14数据后,如下图:

       这时候发现,由于二叉树的根节点是确定不变的,所以当调整数据的插入或删除顺序,会造成二叉树朝着单项链表的方向发展(张歪了,变成歪脖子树了),大大降低了数据的查询效率。一棵树要提高查询效率,左右的高度要差不多才可以。那问题是在添加节点的时候,如何保证把它变成左右高度差不多长的这种树呢?这时候就出现了下面的平衡二叉树。

2、平衡二叉树

平衡二叉树是基于二叉查找树优化而来的。

2.1、定义

       非叶子结点最多只能有两个子结点,且左边子结点点小于当前结点值,右边子结点大于当前结点树,并且为保证查询性能增增删结点时要保证左右两边结点层级相差不大于1,具体实现有AVL、Treap、红黑树等。Java中TreeMap就是基于红黑树实现的。

       也就是说平衡二叉树是在二叉查找树的基础上又多了一个规则:任意节点左右子树高度差不超过1。

判断是否为平衡二叉树示例: 

示例1:

 

      上图中的二叉树是一个查找二叉树,但不是平衡二叉树。虽然根节点7左子树高度为3右子树高度为4,左右子树高度差不超过1。但平衡二叉树是需要任意节点都满足这个规则,比如节点10就不满足这个规则,节点10的左子树高度为0,右子树高度为3,左右子树高度差明显超过1了,所以它不是平衡二叉树。

示例2: 

 

       上图中的二叉树是一个平衡二叉树,因为它满足查找二叉树的同时还满足了规则:任意节点左右子树高度差不超过1。

2.2、 实现树结构平衡的方法(旋转机制)

        旋转机制右两种,分别是左旋和右旋。旋转机制的触发时机为:当添加一个节点之后,该树不再是一颗平衡二叉树时

2.2.1、左旋

左旋的步骤

先确定支点:从添加的节点开始,不断的往父节点找不平衡的节点

找到不平衡的节点后:

        (1)若不平衡的节点没有左子树,以不平衡的点作为支点,把支点左旋降级,变成左子节点,晋升原来的右子节点

        (2)若不平衡的节点有左子树,以不平衡的点作为支点,将根节点的右侧往左拉,原先的右子节点变成新的父节点,并把多余的左子节点出让,给已经降级的根节点当右子节点

左旋示例

示例1:

上图中左边的平衡二查树添加了节点12后,变成了右边的结构,这时候平衡被破坏了,所以要进行旋转。

先确定支点:从添加的节点12开始,不断的往父节点找不平衡的节点。我们发现节点10的左子树高度为0,右子树高度为2,所以找到不平衡的节点10。

找到不平衡的节点:不平衡的节点10没有左子树,以不平衡的点作为支点,把支点左旋降级,变成左子节点,晋升原来的右子节点

如下图所示:

通过左旋后就保持平衡了,还是一个平衡二叉树 

示例2:

上图中左边的平衡二查树添加了节点12后,变成了右边的结构,这时候平衡被破坏了,所以要进行旋转。

先确定支点:从添加的节点12开始,不断的往父节点找不平衡的节点。我们发现节点7的左子树高度为1,右子树高度为3,所以找到不平衡的节点7。

找到不平衡的节点:不平衡的节点7有左子树,以不平衡的点作为支点,将根节点的右侧往左拉,原先的右子节点变成新的父节点,并把多余的左子节点出让,给已经降级的根节点当右子节点

如下图所示:

 通过左旋后就保持平衡了,还是一个平衡二叉树 

2.2.2、右旋

右旋的步骤

先确定支点:从添加的节点开始,不断的往父节点找不平衡的节点

找到不平衡的节点后:

        (1)若不平衡的节点没有右子树,以不平衡的点作为支点,把支点右旋降级,变成右子节点,晋升原来的左子节点

        (2)若不平衡的节点有左子树,以不平衡的点作为支点,将根节点的左侧往右拉,原先的左子节点变成新的父节点,并把多余的右子节点出让,给已经降级的根节点当左子节点

右旋示例

示例1: 

上图中左边的平衡二查树添加了节点1后,变成了右边的结构,这时候平衡被破坏了,所以要进行旋转。

先确定支点:从添加的节点1开始,不断的往父节点找不平衡的节点。我们发现节点4的左子树高度为2,右子树高度为0,所以找到不平衡的节点4。

找到不平衡的节点:不平衡的节点4有左子树,以不平衡的点作为支点,将根节点的右侧往左拉,原先的右子节点变成新的父节点,并把多余的左子节点出让,给已经降级的根节点当右子节点

如下图所示:

  通过右旋后就保持平衡了,还是一个平衡二叉树 

示例2: 

上图中左边的平衡二查树添加了节点1后,变成了右边的结构,这时候平衡被破坏了,所以要进行旋转。

先确定支点:从添加的节点1开始,不断的往父节点找不平衡的节点。我们发现节点7的左子树高度为3,右子树高度为1,所以找到不平衡的节点7。

找到不平衡的节点:不平衡的节点7有左子树,以不平衡的点作为支点,将根节点的右侧往左拉,原先的右子节点变成新的父节点,并把多余的左子节点出让,给已经降级的根节点当右子节点

如下图所示:

  通过右旋后就保持平衡了,还是一个平衡二叉树 

3、总结

相同点:都是基于分治思想采用二分法的策略提高数据查找速度的二叉树结构。

不同点:

  1. 二叉查找树的根节点是不可变的,左右两边结点层级差没有限制;
  2. 平衡二叉树左右两边结点层级相差不大于1,通过旋转实现根节点可变,达到自平衡。

相对于二叉查找树,平衡二叉树的查询效率高,但由于增加和删除节点时,为了保证自平衡会做连续的旋转操作,平衡二叉树的额外开销比较大,耗时相对较长。

推荐:

【数据结构】前缀树的模拟实现-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_65277261/article/details/136086068?spm=1001.2014.3001.5501

【计算机组成原理】存储器知识-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_65277261/article/details/134770339?spm=1001.2014.3001.5501

java数据结构(哈希表—HashMap)含LeetCode例题讲解_leetcode hashmap.values()-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_65277261/article/details/134712832?spm=1001.2014.3001.5501

这篇关于【数据结构】二叉查找树和平衡二叉树,以及二者的区别的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/719801

相关文章

Vue和React受控组件的区别小结

《Vue和React受控组件的区别小结》本文主要介绍了Vue和React受控组件的区别小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录背景React 的实现vue3 的实现写法一:直接修改事件参数写法二:通过ref引用 DOMVu

Go之errors.New和fmt.Errorf 的区别小结

《Go之errors.New和fmt.Errorf的区别小结》本文主要介绍了Go之errors.New和fmt.Errorf的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考... 目录error的基本用法1. 获取错误信息2. 在条件判断中使用基本区别1.函数签名2.使用场景详细对

Redis中哨兵机制和集群的区别及说明

《Redis中哨兵机制和集群的区别及说明》Redis哨兵通过主从复制实现高可用,适用于中小规模数据;集群采用分布式分片,支持动态扩展,适合大规模数据,哨兵管理简单但扩展性弱,集群性能更强但架构复杂,根... 目录一、架构设计与节点角色1. 哨兵机制(Sentinel)2. 集群(Cluster)二、数据分片

C#高效实现Word文档内容查找与替换的6种方法

《C#高效实现Word文档内容查找与替换的6种方法》在日常文档处理工作中,尤其是面对大型Word文档时,手动查找、替换文本往往既耗时又容易出错,本文整理了C#查找与替换Word内容的6种方法,大家可以... 目录环境准备方法一:查找文本并替换为新文本方法二:使用正则表达式查找并替换文本方法三:将文本替换为图

redis数据结构之String详解

《redis数据结构之String详解》Redis以String为基础类型,因C字符串效率低、非二进制安全等问题,采用SDS动态字符串实现高效存储,通过RedisObject封装,支持多种编码方式(如... 目录一、为什么Redis选String作为基础类型?二、SDS底层数据结构三、RedisObject

Python中高级文本模式匹配与查找技术指南

《Python中高级文本模式匹配与查找技术指南》文本处理是编程世界的永恒主题,而模式匹配则是文本处理的基石,本文将深度剖析PythonCookbook中的核心匹配技术,并结合实际工程案例展示其应用,希... 目录引言一、基础工具:字符串方法与序列匹配二、正则表达式:模式匹配的瑞士军刀2.1 re模块核心AP

一文带你迅速搞懂路由器/交换机/光猫三者概念区别

《一文带你迅速搞懂路由器/交换机/光猫三者概念区别》讨论网络设备时,常提及路由器、交换机及光猫等词汇,日常生活、工作中,这些设备至关重要,居家上网、企业内部沟通乃至互联网冲浪皆无法脱离其影响力,本文将... 当谈论网络设备时,我们常常会听到路由器、交换机和光猫这几个名词。它们是构建现代网络基础设施的关键组成

redis和redission分布式锁原理及区别说明

《redis和redission分布式锁原理及区别说明》文章对比了synchronized、乐观锁、Redis分布式锁及Redission锁的原理与区别,指出在集群环境下synchronized失效,... 目录Redis和redission分布式锁原理及区别1、有的同伴想到了synchronized关键字

JAVA覆盖和重写的区别及说明

《JAVA覆盖和重写的区别及说明》非静态方法的覆盖即重写,具有多态性;静态方法无法被覆盖,但可被重写(仅通过类名调用),二者区别在于绑定时机与引用类型关联性... 目录Java覆盖和重写的区别经常听到两种话认真读完上面两份代码JAVA覆盖和重写的区别经常听到两种话1.覆盖=重写。2.静态方法可andro

C++中全局变量和局部变量的区别

《C++中全局变量和局部变量的区别》本文主要介绍了C++中全局变量和局部变量的区别,全局变量和局部变量在作用域和生命周期上有显著的区别,下面就来介绍一下,感兴趣的可以了解一下... 目录一、全局变量定义生命周期存储位置代码示例输出二、局部变量定义生命周期存储位置代码示例输出三、全局变量和局部变量的区别作用域