二叉搜索树-数组的实现方式

      树是一种相对比较复杂的数据结构,它要么为空,要么具有一个值并具有零个或多个孩子,每个孩子本身就是树,这是一个递归的定义,二叉树是树的一种特殊形式,也是数据结构中最常用到的形式,二叉树又可以根据左右孩子节点与跟节点的大小关系分为很多种,这里以二叉搜索树为例学习,二叉搜索树有一个额外的特点:每一个节点的值比它的左子树的所有节点的值都要大,但比它的右子树的所有节点的值都要小,这个定义排除了树中存在值相同的节点的可能性。二叉搜索树是一种关键值快速查找数据的优秀工具。

      和分析堆栈、队列一样我们首先还是分析二叉搜索树提供的接口,首先就是数据的插入InsertBST()、数据的删除DeleteBST()。既然它是一个查找数据的优秀工具那么必不可少的就是查找接口了SerchBST(),和堆栈和队列不同,二叉树并没有限制只能访问某一个值,因此二叉树具有一个基本操作遍历。除此之外,那就是二叉搜索树的建立与销毁。

       接口如下:

 

      

 

      建立一个二叉树实际上就是一个不断插入新值的过程,因为这个新值必须插入到一个合适的位置才能继续保持二叉搜索树的特性。插入的基本思路如下:

                如果树为空:

                      把新值作为跟节点插入

                否则:

                      如果新值小于当前节点的值:

                             把新值插入到当前节点的左子树

                      否则:

                             把新值插入当前节点的右子树

这个算法是按照搜索二叉树的定义来完成的,可以看书这个算法也是一个递归,并且是一个尾部递归,因此可以很容易使用迭代来代替递归提高程序的效率。

       从二叉搜索树删除一个值是比较困难的,从一颗数的中部删除一个节点将导致它的的子树和属的其余部分断开,我们必须重新链接他们,并且面临三种处理情况:删除没有孩子的节点;删除有一个孩子的节点;删除有两个孩子的节点。第一种情况比较简单,直接删除该节点就可以了不会导致子树断开,因为这个节点已经没有子树了,删除有一个孩子的节点时把这个节点的双亲节点和它的孩子连接起来就可以了,最后一种情况是比较困难的,因为一个节点有两个孩子,它的双亲不能链接到它的两个孩子,解决这个问题的一个策略是删除它的左子树最大的那个值,并用这个值代替原先被删除的那个节点的值。

       由于二叉搜索树的有序性,所以在树中查找一个也定的值是比较容易的,同意是一个递归的算法:

                如果树为空:

                      这个值不存在于树中

                否则:

                      如果这个值和根节点的值相等:

                            成功找到这个值

                     否则:

                            如果这个值小于根几点的值:

                                  查找左子树

                            否则:

                                  查找右子树

这也是一个尾部递归可以使用迭代代替提高算法的效率。

      遍历树的节点有几种不同的次序,最常用的是前序、中序、后序和层次遍历。所有类型的遍历都是从树的跟节点或你希望开始遍历的子树的根节点开始。

      前序遍历:简单点记就是“根左右”,先查看根节点然后遍历左子树,遍历左子树也是“根左右”的方式,当做子树遍历完成以后开始遍历右子树也是以“根左右”的方式,也就是说遍历也是一个递归的方式。

      中序遍历:可记作“左根右”;后序遍历可以记作“左右根”。遍历的方式可以参考前序遍历的方式。

      层次遍历:层次遍历先从跟节点开始,同一层从左向右开始遍历。一种比较普遍的做法是使用队列来实现层次遍历,当访问某给节点时首先将这个节点的左右孩子进入队列,然后依次从队列中出列遍历。

 

      接下来就是实现二叉搜索树的各种是接口了,还是堆栈和队列一样,使用静态数组、动态数组、链式结构来分别实现。

      静态数组的实现比较简单,某个节点的左右孩子很容易计算处理,可以使用数组的下标来代替指针,因此不需要额外的空间来存储指向左右节点的指针,计算公式如下:

       节点N的双亲节点为:     N/2  (注意这里没有问题,因为整数的除法会截去小数部分)  

       节点N的左孩子节点为:  2*N

       节点N的右孩子节点为:  2*N+1

       注意这个规则是建立在根节点是数组下标为1的元素,但是实际上数组都是以下标0开始的,如果不想忽略数组的第0个空间,可以将公式稍微修改一下:

        节点N的双亲节点为:    (N+1)/2 -1

        节点N的左孩子节点为: 2*N + 1

        节点N的右孩子节点为: 2*N + 2

        由于数组元素的个数是预先确定的,不管二叉树有没有只有这个空间这个空间已经分配,因此必须使用一个特殊的值用于标识这个值是否被使用,这里我们使用0值作为此节点未被使用的标识。

        具体的实现方式如下:

 

 

动态数组的实现只是多了一个创建数组的过程,其他实现方式和静态数组的实现完全一样。

 

 

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值