算法-红黑树

之前的一片博客中关于二叉查找树在最差的情况是O(n),不能完全的达到O(lgN),在一棵还有N个节点的树中,如果树的高度为lgN,那么我们可以在lgN次比较内结束查找,不过动态插入保证树的平衡性代码量和额外的空间都会是很大的代价。为了保证查找树的平衡性,我们可以允许树中的节点可以保存多个键,标准的二叉树的节点我们可以称之为2-节点(一个键和两条链接),3-节点(含有两个键和三条链接),这就是2-3树。一个2-结点左链接小于该结点,右链接大于该节点。3-节点左链接小于所有键,中链介于两个键之间,右链大于所有键。

2-3树能够在常数级别实现数亿数字的查找和插入,不过实现起来需要维护两种不同的数据节点,而且中间需要大量的代码控制变换,因为就有2-3树的改进版红黑树出现了,所有的节点都是统一的2-节点,3-节点拆分成了2-节点中间通过红线链接,正常的链接之间是黑色,红黑树因此得名。

实现树最基本的就是节点,节点定义代码:

@interface RedBlackNode:NSObject

@property  (strong,nonatomic)  NSString  *key;//键

@property  (strong,nonatomic)  NSString  *value;//值

@property (strong,nonatomic) RedBlackNode  *left;//左子树的节点

@property (strong,nonatomic) RedBlackNode  *right;//右子树的节点

@property  (assign,nonatomic)  NSInteger childCount;//以该结点为根的自述中的结点总数

@property  (assign,nonatomic)  RedBlackEnum color;//链接颜色

-(void)initWithData:(NSString *)key  value:(NSString *)value  childCount:(NSInteger)childCount color:(RedBlackEnum)color;

@end

跟之前二叉查找树之间最大区别在于多了颜色的控制:

-(void)initWithData:(NSString *)key value:(NSString *)value childCount:(NSInteger)childCount color:(RedBlackEnum)color{
    self.key=key;
    self.value=value;
    self.childCount=childCount;
    self.color=color;
}

红黑树的查找和二叉查找树一样代码一样,不过最大的不同就是插入有所不同,插入比较复杂,需要的辅助方法比较多:

@interface RedBlackTree : NSObject

@property  (strong,nonatomic)  RedBlackNode  *root;//红黑树的根节点

-(NSString  *)get:(NSString *)key;//获取键对应的值

-(void)put:(NSString *)key  value:(NSString *)value;//插入键值对

//判断是否是红色链接
-(Boolean)isRed:(RedBlackNode *)node;

//左旋转
-(RedBlackNode *)rotateLeft:(RedBlackNode *)node;

//右旋转
-(RedBlackNode *)rotateRight:(RedBlackNode *)node;

//反转颜色
-(void)flipColors:(RedBlackNode *)node;

@end

红黑树主要实现代码:

@implementation RedBlackTree

-(NSString *)get:(NSString *)key{
    return [self getByKey:self.root key:key];
}

-(NSString *)getByKey:(RedBlackNode *)node  key:(NSString *)key{
    //在node为根结点的子树种查找并返回key所对应的值
    //如果找不到返回null
    if (node==nil) {
        return nil;
    }
    //左右节点进行比较,每个结点的键值大于左子树的结点值小于右子树的结点值
    NSInteger  compare=[key integerValue]-[node.key integerValue];
    if (compare>0) {
        return [self getByKey:node.right key:key];
    }else if(compare<0){
        return [self getByKey:node.left key:key];
    }else{
        return node.value;
    }
}
//http://www.cnblogs.com/xiaofeixiang
-(void)put:(NSString *)key value:(NSString *)value{
    //查找键值,找到则更新它的值,否则为它创建一个新的结点
    self.root=[self putNode:self.root key:key value:value];
    self.root.color=Black;
}

-(RedBlackNode *)putNode:(RedBlackNode *)node  key:(NSString *)key  value:(NSString *)value{
    if (node==nil) {
        RedBlackNode  *newNode=[[RedBlackNode alloc]init];
        [newNode initWithData:key value:value childCount:1 color:Red];
        return newNode;
    }
    NSInteger  compare=[key integerValue]-[node.key integerValue];
    if (compare>0) {
        node.right=[self putNode:node.right key:key value:value];
    }else if(compare<0){
        node.left=[self putNode:node.left key:key value:value];
    }else{
        node.value=value;
    }
    //将含有红色右链接的3-结点(4-结点)向左旋转
    if ([self isRed:node.right]&&![self isRed:node.left]) {
        node=[self rotateLeft:node];
    }
    //连续红色左链接向右旋转
    if ([self isRed:node.left]&&[self isRed:node.left.left]) {
        node=[self rotateRight:node];
    }
    //红色链接向上传递
    if ([self isRed:node.left]&&[self isRed:node.right]) {
        [self flipColors:node];
    }

    node.childCount=[self childSizeCount:node.left]+[self childSizeCount:node.right]+1;
    return node;
}

-(NSInteger)childSize{
    return [self childSizeCount:self.root];
}

-(NSInteger)childSizeCount:(RedBlackNode *)node{
    if (node==nil) {
        return 0;
    }else{
        return node.childCount;
    }
}

-(Boolean)isRed:(RedBlackNode *)node{
    if (!node) {
        return false;
    }
    return node.color==Red;
}
//左旋转,将较大的值作为根节点
-(RedBlackNode *)rotateLeft:(RedBlackNode *)node{
    RedBlackNode  *rightNode=node.right;
    node.right=rightNode.left;
    rightNode.left=node;
    rightNode.color=node.color;
    node.color=Red;
    rightNode.childCount=node.childCount;
    node.childCount=[self childSizeCount:node.left]+[self childSizeCount:node.right]+1;
    return rightNode;
}

//右旋转,将较小的值作为根节点
-(RedBlackNode *)rotateRight:(RedBlackNode *)node{
    RedBlackNode  *leftNode=node.left;
    node.left=leftNode.right;
    leftNode.right=node;
    leftNode.color=node.color;
    node.color=Red;
    leftNode.childCount=node.childCount;
    node.childCount=[self childSizeCount:node.left]+[self childSizeCount:node.right]+1;
    return leftNode;
}
//反转颜色
-(void)flipColors:(RedBlackNode *)node{
    node.color=Red;
    node.left.color=Black;
    node.right.color=Black;
}

@end

红黑树测试代码:

        RedBlackTree  *redBlackTree=[[RedBlackTree alloc]init];
        [redBlackTree put:@"3" value:@"FlyElephant"];
        [redBlackTree put:@"9" value:@"原文地址:http://www.cnblogs.com/xiaofeixiang"];
        [redBlackTree put:@"10" value:@"博客园"];
        [redBlackTree put:@"0" value:@"技术交流:228407086"];
        NSString  *temp=[redBlackTree get:@"9"];
        NSLog(@"红黑树:%@",temp);

测试效果:

红黑树能保证在最差的情况查找和删除,删除都是对数级别的,在过亿的数据处理中,红黑树能够在几十次比较之内完成这些操作,红黑树的魅力让人折服。

时间: 2024-10-10 02:16:23

算法-红黑树的相关文章

算法---红黑树实现介绍(一)

一.概述 红黑树是一种经典的存储结构,就其本身来说是一个二叉查找树,只是在这个基础上,树的节点增加了一个属性用于表示颜色(红或黑).通过限制从根节点到叶子的各个路径的节点着色的限制,来保证不会有哪个路径会比其它的路径长度超过2倍,从而红黑树是接近平衡的. 一直以来没有把红黑树完全理解,总觉得太难,望而生畏,最近下决心要弄清楚,也是花了很长时间,不过总算是明白了.记录下来以便更好的理解. 二.红黑树的特点 作为红黑树,需要有这5个限制,如下: 1)树中的每个节点,要么是红色,要么是黑色 2)树的根

算法--红黑树实现介绍(二)

一.概述 在前一篇中我们回顾了红黑树的特点及添加的处理,可以得知红黑树首先是一个二叉查找树,在此基础上通过增加节点颜色的约束来使得红黑树近似平衡.当我们添加或者删除节点时,我们需要对树进行调整以使其重新满足红黑树.这涉及到节点颜色的变化及部分节点的旋转.关于节点的旋转,以及添加时的处理我们已经介绍完了,所以本文重点介绍红黑树的删除. 二.红黑树的特点 在介绍删除时,我们还是再来回顾一下红黑树的五个特点,如下: 1)节点的颜色是红色或者黑色 2)树的根节点为黑色 3)树的叶子节点为黑色 4)如果一

数据结构与算法-红黑树

前言 红黑树是工程中最常用到的一种自平衡二叉排序树,其和AVL树类似,都是在进行插入.删除时通过一定的调整操作来维持相对稳定的树高,从而获得较好的查询性能. 性质 1. 节点是红色或黑色. 2. 根节点是黑色. 3 每个叶节点(null节点)是黑色的. 4 每个红色节点的两个子节点都是黑色.(从每个叶子到根的所有路径上不能有两个连续的红色节点) 5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点. 维护红黑树形状(树高)的,主要就是4.5两条性质,性质4决定了最长的路径莫过于红黑间隔

15 2 用于查找的高级数据结构和算法 红黑树

算法导论 第三部分——基本数据结构——红黑树

红黑树 红黑树是一种二叉查找树,但在每个结点上增加了一个存储位表示结点的颜色,可以是RED或者BLACK.通过对任何一条从根到叶子的路径上各个着色方式的限制, 红黑树确保没有一条路径会比其他路径长出两倍,因而是接近平衡的.当二叉查找树的高度较低时,这些操作执行的比较快,但是当树的高度较高时,这些操作的性能可能 不比用链表好.红黑树(red-black tree)是一种平衡的二叉查找树,它能保证在最坏情况下,基本的动态操作集合运行时间为O(lgn). 1.红黑树的性质 #define RED 0

红黑树之插入

1.红黑树 (1).概念 i>每个结点不是红的就是黑的: ii>根结点为黑的: iii>红结点的孩子必为黑结点: iv>(除了根结点)任一结点不管通过什么路径,到达叶子节点的黑结点数目一定相同: 总结概括:一头一脚黑,黑同红不连:根为黑,到脚(叶子节点)的黑结点相同,红结点不相连: 2.递归--->一般先写if结束语句 化非递归------>用while()循环和栈; enum{RED, BLACK}; 这个枚举是有值得,分别为0.1: 3.红黑树与AVL树  AVL树

动画 | 什么是红黑树?(与2-3-4树等价)

二分搜索树是为了快速查找而生,它是一颗二叉树,每一个节点只有一个元素(值或键值对),左子树所有节点的值均小于父节点的值,右子树所有的值均大于父节点的值,左右子树也是一颗二分搜索树,而且没有键值相等的节点.它的查找.插入和删除的时间复杂度都与树高成比例,期望值是O(log n). 但是插入数组如[],二分搜索树的缺点就暴露出来了,二分搜索树退化成线性表,查找的时间复杂度达到最坏时间复杂度O(n). 动画:二分搜索树退化成线性表 那有没有插入和删除操作都能保持树的完美平衡性(任何一个节点到其叶子节点

红黑树&mdash;&mdash;算法导论(15)

1. 什么是红黑树 (1) 简介     上一篇我们介绍了基本动态集合操作时间复杂度均为O(h)的二叉搜索树.但遗憾的是,只有当二叉搜索树高度较低时,这些集合操作才会较快:即当树的高度较高(甚至一种极端情况是树变成了1条链)时,这些集合操作并不比在链表上执行的快.     于是我们需要构建出一种"平衡"的二叉搜索树.     红黑树(red-black tree)正是其中的一种.它可以保证在最坏的情况下,基本集合操作的时间复杂度是O(lgn). (2) 性质     与普通二叉搜索树不

编程算法 - 最小的k个数 红黑树 代码(C++)

最小的k个数 红黑树 代码(C++) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 输入n个整数, 找出其中的最小k个数. 使用红黑树(multiset), 每次替换最大的值, 依次迭代. 时间复杂度: O(nlogk). 代码: /* * main.cpp * * Created on: 2014年6月29日 * Author: wang */ #include <iostream> #include <vector> #includ