数据结构与算法回顾-4:平衡查找树

二叉树虽然能解决查找的问题,但是在某些情况下,比如当任意相邻的两个元素之间是按照升序或者降序插入的话,那么得到的树将是一个链表的形状。当然这只是一种极端的情况,只是用来说明,树的形状对二叉查找的效率有很大的影响。

这里的平衡二叉树能够让树保持完美的平衡,不会出现极端的成为链表等,而且我们也会试图去保持树的完美平衡。

它实现这个平衡目的的方式是:对于 3-结点,如果再向其插入数据,就会使其变成 4-结点。4-结点会被分解成一棵子树,并将子树的根节点“进位”父结点。所以,如果进位并导致了根结点变成了 4-结点,那么根结点就会被分解成一棵子树。也就是说,实际上平衡查找树的根结点是会发生变化的,而且这种变化的趋势总是倾向于,将树的左子树中的高度与右子树的高度相差。

平衡查找树的定义:平衡查找树是一种二叉排序树,其中每一个节点的左子树和右子树的高度相差至多等于 1.

我们将树上结点的左子树深度减去右子树深度的值称为平衡因子,那么平衡二叉树上所有结点的平衡因子只可能是 -1, 0, 1.

1、2-3查找树

http://algs4.cs.princeton.edu/33balanced/images/23tree-anatomy.png

  1. 将一棵标准二叉查找树的结点称为 2-结点(含有一个键和两条链接),3-结点是指含有两个键和三条链接的结点;
  2. 一棵 2-3 查找树或为一棵空树,由 2-结点和 3-结点构成,并且左链接执行的键都小于该结点,右链接指向的键都大于该结点

如图所示是一课 2-3查找树,在它的内部插入新的结点的时候比平衡查找树略复杂。这里面包含一种类似“进位”的方式,即如果在某个结点插入了新的结点之后它变成了 4-结点(3 个键 4 个链接),那么需要将其分解并将分解后的中间结点传递到父结点中。如果父结点成了 4-结点,那么就继续讲父结点分解,并向上传递,一直打到最顶层的根结点为止。

上图就是关于 2-3 树插入结点的时候结点的分裂和融合的示意图,实际上我们可以借助上面的思考方式来考虑 2-3 树的一些操作的执行过程。即如果是以上面的 4-结点为例的话,从左到右四个链接分别代表的含义是:小于 A 的结点构成的树,A 和 C 之间的结点构成的树,C 和 E 之间的结点构成的树以及大于 E 的结点构成的树。

2、红黑二叉查找树

2.1 定义

如图所示,红黑二叉查找树只是将 2-3 查找树中的 3-结点转表示成由一条左斜的红色链接相连的两个 2-结点。这种表示方法的优点是我们可以无需修改就使用二叉查找树的 get() 方法。

有些图在表示红黑树的时候,没有使用红连接,而是使用红色的结点,比如这里的 a 就应该被表示成一个红色的结点。虽然表达方式不一样,但是实际意义是一样的—— a 和 b 构成了 2-3 树中的 3 结点。

红黑二叉查找树的等价定义:

  1. 红链接均为左链接;
  2. 树的根为黑色,叶子节点(即所谓的空节点)为黑色;(根必须为黑色的,但可以是 3-结点)
  3. 没有任何一个结点同时和两个红链接相连;
  4. 该树是完美黑色平衡,即任意空链接到根结点的路径上的黑链接数量相同。

实际上红黑二叉查找树将红链接画平时,一棵红黑树就是一棵 2-3 树。我们在二叉树的基础之上增加了一个红黑的条件,这使得红黑树的红链接既能够表示 2-3 树中的 3-结点的情形,又能具有二叉树的只具有两个分支的性能。即它既满足了我们对效率的要求,又能够比较方便地实现。

注意下面的关于红黑二叉树的操作中,除了完成基本的功能之外,是如何维护树的平衡的

2.2 红黑树的表示

与二叉树类似,只是这里需要在二叉树的基础之上增加一个字段 color 用于表示红黑二叉查找树的结点的颜色:

	public class RedBlackBST<Key extends Comparable<Key>, Value> {
   
	    private final static boolean RED = true;
	    private final static boolean BLACK = false;
	    private Node<Key, Value> root;
	
	    private static class Node<Key extends Comparable<Key>, Value> {
   
	        Key key;
	        Value value;
	        Node leftChild, rightChild;
	        int N;
	        boolean color; // 增加了一个颜色字段
	
	        public Node(Node leftChild, Key key, Value value, int n, boolean color, Node rightChild) {
   
	            this.key = key;
	            this.value = value;
	            this.leftChild = leftChild;
	            this.rightChild = rightChild;
	            N = n;
	            this.color = color;
	        }
	    }
	}

2.3 旋转

2.3.1 原理

在实现某些操作的时候(比如插入、删除等),会出现红链接在右侧或者两条连续的红链接的状况,在继续操作之前需要对这些情况进行修复,这就需要对其进行旋转。将右侧的红链接转换为左侧的红链接的过程叫做左旋,相反的操作叫做右旋

图 左旋的示意图

图 右旋的示意图

其实所谓的左旋和右旋是比较容易理解的,你可以将其想象成旋转就是将 E 和 S 中的那个“低”一些的“拎”起来的过程。比如左旋时,就像将S“拎”起来,拎起来之后,E 和 S 之间的那个结点,自然地从 S 滑落到了 E 上面。

旋转的时候有几个地方需要注意:旋转之前和之后根结点的颜色的变化,两个结点的颜色变化,两个结点的子结点的变化。

2.3.2 代码实现

下面是左旋和右旋的代码实现,以及容易出现错误的一些地方:

    private Node<Key, Value> rotateLeft(Node<Key, Value> node) {
   
        Node<Key, Value> right = node.rightChild;
        // node.color = BLACK; // 错误:结点的颜色应该是链接到结点的链接的颜色,所以旋转之后node的结点的颜色变成红色才对
        node.color = RED;
        // right.color = RED; // 错误:旋转之之后right结点的颜色是node的颜色,本质上旋转只是这棵子树内部的变化,对外不变
        right.color = node.color;
        right.leftChild = node; // right的左结点变成了node
        node.
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
道01数据结构算法绪论. mp402_谈谈算法. mp4 西03_时间复杂度和空间复杂度.mp404_时间复杂度和空间复杂度2.mp405_时间复杂度和空间复杂度3.mp4险06线性表. mp407_线性表2. mp408_线性表3. mp4品09_ 线性表4. mp410_线性表5. mp411_线性表6. mp4@12_线性表7. mp413_线性表8. mp4西14. 线性表9. mp415_线性表10. mp4 16_单链表小结:腾讯面试题. mp4品17_ 线性表12. mp418_约瑟夫问题. mp4西19_ 线性表14. mp4 20_魔术师发牌问题. mp421线性表16. mp4逾22_ 线性表17. mp423_栈和队列. mp424_栈和队列2. mp4面25_ 进制转换. mp4面26_ 栈和队列4. mp427_逆波兰计算器mp4 28_中缀表达式转换为后缀表达式01. mp4逾29_ 中缀表达式转换为后缀表达式02. mp430_栈和队列7. mp431_栈和队列8. mp4 西32递归和分治思想.mp433_递归和分治思想2. mp434_汉诺塔. mp4 35_八皇后问题. mp4 四36_字符串.mp4 二37_ KMP算法. mp4 四71斐波那契查找(黄金分割法查找).38_ KMP算法2. mp4 立39_ KMP算法之NEXT数组代码原理分析. mp4二40_ KMP算法之实现及优化. mp4二41. mp4 四42_的存储结构. mp443_的存储结构2. mp4四44_二艾. mp445_二叉2. mp4 46_二又的存数结构. mp447_二又的遍历. mp4 48_二丈的建立和遍历算法. mp4四49_线索二叉. mp4 50_线索二又代码实现. mp4 画51_、森林及二又的相互转换. mp452_赫夫曼. mp453_赫夫曼编码. mp4 四54_赫夫曼编码C语言实现. mp4口55_图. mp4 逾56_图的定义与术语2. mp457_图的存储结构. mp4 58_图的存储结构(邻接表) . mp4 59_图的存储结构(十字链表、邻接多重表、边集数组) . mp4四93堆排序的代码实现mp460_图的遍历(深度优先遍历) . mp4 品94归并排序. mp4 四61_马踏棋盘算法(骑士周游问题) . mp4 95归并排序(迭代实现) . mp4品62_图的遍历(广度优先遍历) . mp4 國96快速排序.mp4 63_最小生成(普里姆算法) . mp4 二97快速排序的优化mp464_最小生成( 克鲁斯卡尔算法) . mp4 立98总结回顾.mp4画65_最短路径(迪杰斯特拉算法).mp466_最短路径( 弗洛伊德算法) . mp4口67拓扑排序. mp4二68关键路径.mp4口69_查找算法. mp4 画69关键路径(代码讲解).mp4

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值