红黑树插入与删除完整代码(dart语言实现)
之前分析了红黑树的删除,这里附上红黑树的完整版代码,包括查找、插入、删除等。删除后修复实现了两种算法,均比之前的更为简洁。一种是我自己的实现,代码非常简洁,行数更少;一种是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语言实现)的更多相关文章
- stl map底层之红黑树插入步骤详解与代码实现
转载注明出处:http://blog.csdn.net/mxway/article/details/29216199 本篇文章并没有详细的讲解红黑树各方面的知识,只是以图形的方式对红黑树插入节点需要进 ...
- RBtree插入跟删除图解代码
一.红黑树的简单介绍 RBT 红黑树是一种平衡的二叉查找树.是一种计算机科学中经常使用的数据结构,最典型的应用是实现数据的关联,比如map等数据结构的实现. 红黑树有下面限制: 1. 节 ...
- 红黑树插入操作原理及java实现
红黑树是一种二叉平衡查找树,每个结点上有一个存储位来表示结点的颜色,可以是RED或BLACK.红黑树具有以下性质: (1) 每个结点是红色或是黑色 (2) 根结点是黑色的 (3) 如果一个结点是红色的 ...
- 红黑树插入操作---以JDK 源码为例
红黑树遵循的条件: 1.根节点为黑色. 2.外部节点(叶子节点)为黑色. 3.红色节点的孩子节点为黑色.(由此,红色节点的父节点也必为黑色) 4.从根节点到任一外部节点的路径上,黑节点的数量相同. 节 ...
- jdk源码分析红黑树——插入篇
红黑树是自平衡的排序树,自平衡的优点是减少遍历的节点,所以效率会高.如果是非平衡的二叉树,当顺序或逆序插入的时候,查找动作很可能会遍历n个节点 红黑树的规则很容易理解,但是维护这个规则难. 一.规则 ...
- RedBlack-Tree(红黑树)原理及C++代码实现
众所周知,红黑树是用途很广的平衡二叉搜索树,用过的都说好.所以我们来看看红黑树的是怎么实现的吧. 红黑树顾名思义,通过红与黑两种颜色来给每个节点上色.其中根结点和叶子结点一定是黑色的,并且红色结点的两 ...
- 顺序表的插入和删除(基于c语言)
插入:在下标p处插入数据x:返回是否成功(0/1) 几个注意点:1.还能否插入数据:2.给的下标p是否是错误的以及p的范围:3.移动时的易错点(从下标大的元素开始):4.n与palist->n; ...
- 算法导论学习---红黑树具体解释之插入(C语言实现)
前面我们学习二叉搜索树的时候发如今一些情况下其高度不是非常均匀,甚至有时候会退化成一条长链,所以我们引用一些"平衡"的二叉搜索树.红黑树就是一种"平衡"的二叉搜 ...
- TreeMap----的实现原理(红黑树)
TreeMap的实现是红黑树算法的实现,所以要了解TreeMap就必须对红黑树有一定的了解,其实这篇博文的名字叫做:根据红黑树的算法来分析TreeMap的实现,但是为了与Java提高篇系列博文保持一致 ...
随机推荐
- H.__mro__) MRO- C3算法
- IDEA中的替换功能(替换代码中的变量名很好用哦)
刚刚上班不久,这两天正在研究公司项目里面的代码,今天用阿里的插件扫描了一下代码,发现代码中有很多变量的命名,没有遵循驼峰式的命名规则.一开始我一个一个的修改这些变量名,后来无意中用了一下Ctrl+F( ...
- Emmm,从删库到跑路系列之.......Root权限的重要性
中午导入了一个.SQL文件,晚上查navicat的数据库死活打不开 错误代码1030,想起来中午导入了mysql数据库的user表,而那里面什么也没有... 默默删掉了data,然后emmm --in ...
- node封装mysql操作
前言 node是基于异步的,因此在进行数据库查询操作的通常是通过回调来操作查询结果.但是在有了es7的async/await,基本不再需要回调了,所以本篇是基于async/await对mysql进行一 ...
- CSS3 新增的文本属性
一.CSS1&2中的文本属性(W3C标准) text-indent CSS1 检索或设置对象中的文本的缩进 letter-spacing CSS1 检索或设置对象中的文字之间的间隔 word- ...
- 2-6 R语言基础 缺失值
#缺失值 Missing Value > #NaN不可识别NA> x <- c(1,NA,2,NA,3) > is.na(x)[1] FALSE TRUE FALSE TRUE ...
- ICSharpCode.SharpZipLib 开源压缩库使用示例
官方网站:http://www.icsharpcode.net/OpenSource/SharpZipLib/Default.aspx 插件描述: ICSharpCode.SharpZipLib.dl ...
- OpenCV——图像的载入、显示、输出到文件和滑动条、鼠标操作
图像的载入.显示.输出到文件和滑动条 滑动条 示例: 鼠标操作
- 20175310 《Java程序设计》第1周学习总结(2)
20175310 <Java程序设计>第1周学习总结(2) 教材学习内容总结 本周学习了教材的第一章内容,通过看微课的方式,自主学习,教材上讲的比较简单,主要的问题都在调试代码上,还有一两 ...
- 包学会之浅入浅出 Vue.js:开学篇
2016年,乃至接下来整个2017年,如果你要问前端技术框架什么最火,那无疑就是前端三巨头:React.Angular.Vue.没错,什么jQuery,seaJs,gulp等都逐渐脱离了热点.面试的时 ...