红黑树2---从-2-3-4树到红黑树的演变过程以及插入算法实现原理

基本二叉排序树BST,当输入序列有序时,树的高度会急剧增加,最坏情况下时间复杂度为O(N)。

因此进一步演变为2-3-4树,2-3-4树节点类型有3种,2节点,3节点以及4节点,最重要的性质是每个叶子结点到根节点的路径长度一致,其最坏情况下为O(logN)。由于2-3-4树节点类型过大,进行插入以及查找时,需要进行节点类型判断,过于繁琐。

因此利用红连接的概念将2-3-4树转化为红黑树,即红黑树节点均为2节点,每个节点有颜色属性,通过红连接可以将红黑树对应为2-3-4树。

2-3-4树与红黑树的对应关系

2-3-4树中的3节点以及4节点转换为2节点对应关系如下:

其中3节点对应关系有两种,左倾left-leaning以及右倾

  

如下图所示,由于3节点对应关系不确定,因此同一颗2-3-4树转换为BST,由多种对应关系

  

但是如果对于3节点采取右倾策略,易得转换后的二叉树不符合BST有序性。

因此这里定义LLRB,左倾二叉树,3节点都采用左倾映射关系

此时2-3-4树与红黑树的对应关系时确定的,并且转化而来的红黑树保持BST有序性

       

LLRB基本变换

红黑树重要性质,每个叶子节点空连接到根节点路径上黑连接数目相同,即完美黑色平衡。当传入新节点时,新节点为红色,此时会破坏红黑树完美黑色平衡性质,因此需要对于红黑树中的红连接进行变换

左旋  将某个节点右节点左旋,将红连接左旋,即将该节点以及右节点最大值提升为父节点

                                        

右旋  将某个节点左节点右旋,将红连接右旋,将该节点以及左节点最小值提升为父节点

                                         

颜色变换  将一个4节点分解为3个2节点  将红连接向上传递 保持红黑树的性质之一,任意一个节点均不能同时与两个红连接相连。

   

LLRB插入算法

在LLRB插入时,一种思想是在搜索插入节点合适位置时,参考2-3-4树插入思想,将沿途节点进行变换,使得最终待插入节点为非4节点,即出入位置出现2,3节点,则都可以轻松插入。

当插入新节点时,将新节点设置为红色,可能出现的情况如下所示:

1.在一个2节点左右子节点位置插入,当在右节点位置插入时,出现右倾红连接,进行左旋变换,使其满足LLRB定义

   

2.在一个3节点的左、中、右节点位置插入,如果出现右倾红连接则左旋,如果出现连续的左倾红连接,则将底部红连接右旋,构造为一个4节点。

   

4.在一个4节点插入,且其父节点为2节点,将4节点进行分解

    

5.在一个4节点插入,且其父节点为3节点,使其分解

  

由以上可知,变换的基本思想是依次检查是否需要进行颜色变换,左旋变换,右旋变换,变换完成后,此时待插入位置处必为非4节点,此时可以直接插入新节点。

2-3-4树,LLRB插入算法如下所示:

        private Node insert(Node h, Key key, Value val){
		if(h == null)
			return new Node(key, val, 1, RED);
		if(isRed(h.left)&&isRed(h.right))
			flipColors(h);
		int cmp = key.compareTo(h.key);
		if(cmp==0) 
			h.val = val;
		else if(cmp<0) 
			h.left = insert(h.left, key, val);
		else 
			h.right = insert(h.right, key, val);
		if(isRed(h.right)) 
			rotateLeft(h);
		if(isRed(h.left)&&isRed(h.left.left))
			rotateRight(h);
		h.N = size(h.left) + size(h.right) + 1;
		return h;
	}

在进行插入时,如果出现4节点则通过颜色变换对应分解,插入新节点,然后进行调整,检查是否需要左旋,是否需要右旋等

                            

将颜色变换放置于左旋,右旋之后有:

        private Node put(Node h, Key key, Value val) {
		if(h == null)
			return new Node(key, val, 1, RED);		
		int cmp = key.compareTo(h.key);
		if(cmp>0)
			h.right = put(h.right, key, val);
		else if(cmp<0)
			h.left = put(h.left, key, val);
		else
			h.val = val;
		if(!isRed(h.left)&&isRed(h.right))
			h = rotateLeft(h);
		if(isRed(h.left)&&isRed(h.left.left))
			h = rotateRight(h);
		if(isRed(h.left)&&isRed(h.right))
			flipColors(h);
		h.N = size(h.left) + size(h.right) + 1;
		return h;		
	}

此时相当于在一颗2-3树中执行插入操作,每插入一个节点时,通过左旋,右旋以及颜色变换,来最终保证树中没有4节点

                  

对于两种插入算法,其实对应于2-3-4树中的插入算法思想

              

一种是由上到下,在进行搜索过程中,将遇到的4节点进行变换,使得带插入位置为非4节点,这样可以直接插入新节点,然后利用左旋,右旋来调整红黑树保持平衡性;

一种是由下到上,当插入一个新节点时,利用左旋,右旋以及颜色变换,使得树中全部为非4节点;

因此可以通过由下到上的思想来理解红黑树的插入算法:

红黑树是一颗满足以下条件的BST:

每个节点颜色由指向该节点连接颜色决定,红连接以及黑连接

任何节点不能同时与两个红连接相连

完美黑色平衡,任何空连接到根节点具有相同的路径长度

当插入一个新节点时,令该节点为红色,使用红连接与其父节点进行相连,由于新节点的插入,可能破坏平衡性,因此通过左旋,右旋,颜色变换来调整,使得新树满足红黑树性质。

具体的变换如下:

最终的插入算法:

        public void put(Key key, Value val){
		root = put(root, key, val);
		root.color = BLACK;
	} 
	
	private Node put(Node h, Key key, Value val) {
		if(h == null)
			return new Node(key, val, 1, RED);		
		int cmp = key.compareTo(h.key);
		if(cmp>0)
			h.right = put(h.right, key, val);
		else if(cmp<0)
			h.left = put(h.left, key, val);
		else
			h.val = val;
		if(!isRed(h.left)&&isRed(h.right))
			h = rotateLeft(h);
		if(isRed(h.left)&&isRed(h.left.left))
			h = rotateRight(h);
		if(isRed(h.left)&&isRed(h.right))
			flipColors(h);
		h.N = size(h.left) + size(h.right) + 1;
		return h;		
	}

参考链接:http://www.cs.princeton.edu/~rs/talks/LLRB/RedBlack.pdf

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Objective-C是一面向对象的编程语言它是基于C语言的扩展虽然Objective-C本身并没有提供实现,但可以通过使用Foundation框架中的NSSet类来实现类似的功能[^2]。 NSSet是Foundation框架中的一个集合类,它可以存储一组无序且唯一的对象。NSSet内部的实现可能使用了等数据结构来提高查询速度。 下面是一个使用Objective-C实现的示例代码: ```objective-c #import <Foundation/Foundation.h> @interface RedBlackTree : NSObject - (void)insertValue:(NSNumber *)value; - (BOOL)containsValue:(NSNumber *)value; @end @implementation RedBlackTree { NSMutableSet *_set; } - (instancetype)init { self = [super init]; if (self) { _set = [NSMutableSet set]; } return self; } - (void)insertValue:(NSNumber *)value { [_set addObject:value]; } - (BOOL)containsValue:(NSNumber *)value { return [_set containsObject:value]; } @end int main(int argc, const char * argv[]) { @autoreleasepool { RedBlackTree *tree = [[RedBlackTree alloc] init]; [tree insertValue:@5]; [tree insertValue:@3]; [tree insertValue:@8]; NSLog(@"Contains 5: %@", [tree containsValue:@5] ? @"Yes" : @"No"); // 输出:Contains 5: Yes NSLog(@"Contains 7: %@", [tree containsValue:@7] ? @"Yes" : @"No"); // 输出:Contains 7: No } return 0; } ``` 在上面的示例代码中,我们创建了一个RedBlackTree类,它使用NSMutableSet来存储的节点。insertValue方法用于插入一个值,containsValue方法用于检查某个值是否存在于中。 请注意,这只是一个简单的示例,实际上实现要复杂得多。如果需要更复杂的功能,建议使用第三方库或自行实现

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值