之前分析了红黑树的删除,这里附上红黑树的完整版代码,包括查找、插入、删除等。删除后修复实现了两种算法,均比之前的更为简洁。一种是我自己的实现,代码非常简洁,行数更少;一种是Linux、Java等源码版本的实现,实现的略为复杂,但效率更高。两种算法经过测试,在百万级的数据上效率不分伯仲;1000万的数据中,我自己的实现比Linux内核版本的运行时间多2秒左右。

  红黑树的插入相对简单,本文中的代码实现与Linux源码版本也略有差异,效率差别不大。

  其他方法,如查找、遍历等,比较简单,不多做解释。遍历支持前序、中序、后序遍历。

  在研究红黑树的过程中,为了彻底弄懂插入与删除,画了无数的图,以删除修复为例,根据父亲节点、兄弟节点、兄弟节点的左右子节点的空、红、黑的情况,穷举了36中情况,再进行归纳合并。而弄明白以后,发现是如此的简单;实现了多种写法,最后总结为两种最简洁的实现,并进行性能测试。还写了检查一棵树是否是红黑树的代码,将在下篇博客中发布。

  至此,二叉树和红黑树研究完毕。代码如下:

 import 'tree_node.dart';
import 'tree_exception.dart';
import 'traverse_order.dart'; class RBTree<E extends Comparable<E>> {
RBTNode<E> _root;
int _nodeNumbers; RBTree() : _nodeNumbers = 0; factory RBTree.from(Iterable<Comparable<E>> elements) {
var tree = RBTree<E>();
for (var e in elements) tree.insert(e);
return tree;
} bool get isEmpty => _root == null;
int get nodeNumbers => _nodeNumbers;
RBTNode<E> get root => _root; void clear() {
_root = null;
_nodeNumbers = 0;
} bool contains(E value) => find(value) != null; bool delete(E value) => _delete(value, _fixAfterDelete); // the implement in Linux core.
bool quickDelete(E value) => _delete(value, _fixAfterDelete2); RBTNode<E> find(E value) {
var current = _root;
while (current != null) {
var c = value.compareTo(current.value);
if (c == 0) break;
current = c < 0 ? current.left : current.right;
}
return current;
} void insert(E value) {
var inserted = RBTNode<E>(value);
_insert(inserted);
_fixAfterInsert(inserted);
} E get max {
if (isEmpty) throw TreeEmptyException();
var maxNode = _root;
while (maxNode.right != null) maxNode = maxNode.right;
return maxNode.value;
} E get min {
if (isEmpty) throw TreeEmptyException();
return _minNode(_root).value;
} void traverse(void f(E e), [TraverseOrder order = TraverseOrder.inOrder]) =>
_traverse(_root, order, f); void _insert(RBTNode<E> inserted) {
RBTNode<E> p, c = _root;
while (c != null) {
p = c;
c = inserted.value.compareTo(c.value) <= 0 ? c.left : c.right;
} if (p == null) {
_root = inserted;
} else if (inserted.value.compareTo(p.value) <= 0) {
p.left = inserted;
} else {
p.right = inserted;
}
inserted.parent = p;
_nodeNumbers++;
} void _fixAfterInsert(RBTNode<E> node) {
while (_hasRedFather(node) && _hasRedUncle(node)) {
var g = _gparent(node);
g.left.paintBlack();
g.right.paintBlack();
g.paintRed();
node = g;
} if (_hasRedFather(node)) {
var g = _gparent(node);
if (node.parent == g.left) {
if (node == node.parent.right) {
_rotateLeft(node.parent);
node = node.left;
}
_rotateRight(g);
} else {
if (node == node.parent.left) {
_rotateRight(node.parent);
node = node.right;
}
_rotateLeft(g);
}
node.parent.paintBlack();
g.paintRed();
}
_root.paintBlack();
} bool _hasRedFather(RBTNode<E> node) =>
node.parent != null && node.parent.isRed; bool _hasRedUncle(RBTNode<E> node) {
var gparent = _gparent(node);
var uncle = node.parent == gparent.left ? gparent.right : gparent.left;
return uncle != null && uncle.isRed;
} RBTNode _gparent(RBTNode<E> node) => node.parent.parent; bool _delete(E value, void _fix(RBTNode<E> p, bool isLeft)) {
var d = find(value);
if (d == null) return false; if (d.left != null && d.right != null) {
var s = _successor(d);
d.value = s.value;
d = s;
}
var rp = d.left ?? d.right;
rp?.parent = d.parent;
if (d.parent == null)
_root = rp;
else if (d == d.parent.left)
d.parent.left = rp;
else
d.parent.right = rp; if (rp != null)
rp.paintBlack();
else if (d.isBlack && d.parent != null)
_fix(d.parent, d.parent.left == null); _nodeNumbers--;
return true;
} RBTNode<E> _successor(RBTNode<E> d) =>
d.right != null ? _minNode(d.right) : d.left; void _fixAfterDelete(RBTNode<E> p, bool isLeft) {
var c = isLeft ? p.right : p.left;
if (isLeft) {
if (c.isRed) {
p.paintRed();
c.paintBlack();
_rotateLeft(p);
c = p.right;
}
if (c.left != null && c.left.isRed) {
c.left.paint(p.color);
if (p.isRed) p.paintBlack();
_rotateRight(c);
_rotateLeft(p);
} else {
_rotateLeft(p);
if (p.isBlack) {
p.paintRed();
if (c.parent != null) _fixAfterDelete(c.parent, c == c.parent.left);
}
}
} else {
if (c.isRed) {
p.paintRed();
c.paintBlack();
_rotateRight(p);
c = p.left;
}
if (c.right != null && c.right.isRed) {
c.right.paint(p.color);
if (p.isRed) p.paintBlack();
_rotateLeft(c);
_rotateRight(p);
} else {
_rotateRight(p);
if (p.isBlack) {
p.paintRed();
if (c.parent != null) _fixAfterDelete(c.parent, c == c.parent.left);
}
}
}
} // the implement in Linux core.
void _fixAfterDelete2(RBTNode<E> p, bool isLeft) {
var c = isLeft ? p.right : p.left;
if (isLeft) {
if (c.isRed) {
p.paintRed();
c.paintBlack();
_rotateLeft(p);
c = p.right;
}
if ((c.left != null && c.left.isRed) ||
(c.right != null && c.right.isRed)) {
if (c.right == null || c.right.isBlack) {
_rotateRight(c);
c = p.right;
}
c.paint(p.color);
p.paintBlack();
c.right.paintBlack();
_rotateLeft(p);
} else {
c.paintRed();
if (p.isRed)
p.paintBlack();
else if (p.parent != null)
_fixAfterDelete2(p.parent, p == p.parent.left);
}
} else {
if (c.isRed) {
p.paintRed();
c.paintBlack();
_rotateRight(p);
c = p.left;
}
if ((c.left != null && c.left.isRed) ||
(c.right != null && c.right.isRed)) {
if (c.left == null || c.left.isBlack) {
_rotateLeft(c);
c = p.left;
}
c.paint(p.color);
p.paintBlack();
c.left.paintBlack();
_rotateRight(p);
} else {
c.paintRed();
if (p.isRed)
p.paintBlack();
else if (p.parent != null)
_fixAfterDelete2(p.parent, p == p.parent.left);
}
}
} void _rotateLeft(RBTNode<E> node) {
var r = node.right, p = node.parent;
r.parent = p;
if (p == null)
_root = r;
else if (p.left == node)
p.left = r;
else
p.right = r; node.right = r.left;
r.left?.parent = node;
r.left = node;
node.parent = r;
} void _rotateRight(RBTNode<E> node) {
var l = node.left, p = node.parent;
l.parent = p;
if (p == null)
_root = l;
else if (p.left == node)
p.left = l;
else
p.right = l; node.left = l.right;
l.right?.parent = node;
l.right = node;
node.parent = l;
} RBTNode<E> _minNode(RBTNode<E> r) => r.left == null ? r : _minNode(r.left); void _traverse(RBTNode<E> s, TraverseOrder order, void f(E e)) {
if (s == null) return;
switch (order) {
case TraverseOrder.inOrder:
_traverse(s.left, order, f);
f(s.value);
_traverse(s.right, order, f);
break;
case TraverseOrder.preOrder:
f(s.value);
_traverse(s.left, order, f);
_traverse(s.right, order, f);
break;
case TraverseOrder.postOrder:
_traverse(s.left, order, f);
_traverse(s.right, order, f);
f(s.value);
break;
default:
break;
}
}
}

红黑树插入与删除完整代码(dart语言实现)的更多相关文章

  1. stl map底层之红黑树插入步骤详解与代码实现

    转载注明出处:http://blog.csdn.net/mxway/article/details/29216199 本篇文章并没有详细的讲解红黑树各方面的知识,只是以图形的方式对红黑树插入节点需要进 ...

  2. RBtree插入跟删除图解代码

    一.红黑树的简单介绍        RBT 红黑树是一种平衡的二叉查找树.是一种计算机科学中经常使用的数据结构,最典型的应用是实现数据的关联,比如map等数据结构的实现. 红黑树有下面限制: 1. 节 ...

  3. 红黑树插入操作原理及java实现

    红黑树是一种二叉平衡查找树,每个结点上有一个存储位来表示结点的颜色,可以是RED或BLACK.红黑树具有以下性质: (1) 每个结点是红色或是黑色 (2) 根结点是黑色的 (3) 如果一个结点是红色的 ...

  4. 红黑树插入操作---以JDK 源码为例

    红黑树遵循的条件: 1.根节点为黑色. 2.外部节点(叶子节点)为黑色. 3.红色节点的孩子节点为黑色.(由此,红色节点的父节点也必为黑色) 4.从根节点到任一外部节点的路径上,黑节点的数量相同. 节 ...

  5. jdk源码分析红黑树——插入篇

    红黑树是自平衡的排序树,自平衡的优点是减少遍历的节点,所以效率会高.如果是非平衡的二叉树,当顺序或逆序插入的时候,查找动作很可能会遍历n个节点 红黑树的规则很容易理解,但是维护这个规则难. 一.规则 ...

  6. RedBlack-Tree(红黑树)原理及C++代码实现

    众所周知,红黑树是用途很广的平衡二叉搜索树,用过的都说好.所以我们来看看红黑树的是怎么实现的吧. 红黑树顾名思义,通过红与黑两种颜色来给每个节点上色.其中根结点和叶子结点一定是黑色的,并且红色结点的两 ...

  7. 顺序表的插入和删除(基于c语言)

    插入:在下标p处插入数据x:返回是否成功(0/1) 几个注意点:1.还能否插入数据:2.给的下标p是否是错误的以及p的范围:3.移动时的易错点(从下标大的元素开始):4.n与palist->n; ...

  8. 算法导论学习---红黑树具体解释之插入(C语言实现)

    前面我们学习二叉搜索树的时候发如今一些情况下其高度不是非常均匀,甚至有时候会退化成一条长链,所以我们引用一些"平衡"的二叉搜索树.红黑树就是一种"平衡"的二叉搜 ...

  9. TreeMap----的实现原理(红黑树)

    TreeMap的实现是红黑树算法的实现,所以要了解TreeMap就必须对红黑树有一定的了解,其实这篇博文的名字叫做:根据红黑树的算法来分析TreeMap的实现,但是为了与Java提高篇系列博文保持一致 ...

随机推荐

  1. vc使用jsoncpp头文件冲突问题

    编译时出现 1>d:\program files (x86)\microsoft visual studio 9.0\vc\include\xdebug(32) : warning C4229: ...

  2. sed和awk学习整理

    Awk和Sed的基本使用 可以用大至相同的方式调用sed 和awk .命令行讲法是:command [options] script filename几乎和所有的unlx程序一样,sed和awk都可以 ...

  3. Django商城项目笔记No.8用户部分-注册接口实现

    Django商城项目笔记No.8用户部分-注册接口实现 users的view.py中增加如下代码 class RegisterUserView(CreateAPIView): "" ...

  4. Docker 基础 - Docker 与前端(二)

    一.Docker 系统架构 守护进程 负责容器的创建.运行和监控,还负责镜像的构建和存储.docker demon 命令可启动 Docker 守护进程. Docker 客户端 通过http与 dock ...

  5. 2.python数据结构的性能分析

    一.引言 - 现在大家对 大O 算法和不同函数之间的差异有了了解.本节的目标是告诉你 Python 列表和字典操作的 大O 性能.然后我们将做一些基于时间的实验来说明每个数据结构的花销和使用这些数据结 ...

  6. 容器内部设置JVM的Heap大小

    容器内部利用脚本来获取容器的CGroup资源限制,并通过设置JVM的Heap大小. Docker1.7开始将容器cgroup信息挂载到容器中,所以应用可以从 /sys/fs/cgroup/memory ...

  7. FileUriExposedException_Android7.0适配

    一. FileUriExposedException的解决 问题 由于在Android7.0上,google使用了新的权限机制,所以导致在调用相机的时候,如果传递的URI为”file://”类型,的系 ...

  8. 串口通信DMA中断

    这是以前学32的时候写的,那时候学了32之后感觉32真是太强大了,比51强的没影.关于dma网上有许多的资料,亲们搜搜,这里只贴代码了,其实我也想详详细细地叙述一番,但是自己本身打字就慢,还有好多事情 ...

  9. VBA删除 语法

    Option Explicit '清空数据  Private Sub CommandButton1_Click() Dim qknum As Integer  '选择是或者否 来确认删除数据 '中对话 ...

  10. 自研后端HTTP请求参数验证器服务ParamertValidateService

    好处:方便了后端对HTTP请求中参数进行核验,只需一次编写效验器,一行代码便可对所有参数的pojo进行参数核验!而且更改效验逻辑时只需要更改效验器类即可,实现了解耦合. 只需要程序员按照规范开发一个P ...