红黑树插入与删除完整代码(dart语言实现)

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

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

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

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

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

  1 import ‘tree_node.dart‘;
  2 import ‘tree_exception.dart‘;
  3 import ‘traverse_order.dart‘;
  4
  5 class RBTree<E extends Comparable<E>> {
  6   RBTNode<E> _root;
  7   int _nodeNumbers;
  8
  9   RBTree() : _nodeNumbers = 0;
 10
 11   factory RBTree.from(Iterable<Comparable<E>> elements) {
 12     var tree = RBTree<E>();
 13     for (var e in elements) tree.insert(e);
 14     return tree;
 15   }
 16
 17   bool get isEmpty => _root == null;
 18   int get nodeNumbers => _nodeNumbers;
 19   RBTNode<E> get root => _root;
 20
 21   void clear() {
 22     _root = null;
 23     _nodeNumbers = 0;
 24   }
 25
 26   bool contains(E value) => find(value) != null;
 27
 28   bool delete(E value) => _delete(value, _fixAfterDelete);
 29
 30   // the implement in Linux core.
 31   bool quickDelete(E value) => _delete(value, _fixAfterDelete2);
 32
 33   RBTNode<E> find(E value) {
 34     var current = _root;
 35     while (current != null) {
 36       var c = value.compareTo(current.value);
 37       if (c == 0) break;
 38       current = c < 0 ? current.left : current.right;
 39     }
 40     return current;
 41   }
 42
 43   void insert(E value) {
 44     var inserted = RBTNode<E>(value);
 45     _insert(inserted);
 46     _fixAfterInsert(inserted);
 47   }
 48
 49   E get max {
 50     if (isEmpty) throw TreeEmptyException();
 51     var maxNode = _root;
 52     while (maxNode.right != null) maxNode = maxNode.right;
 53     return maxNode.value;
 54   }
 55
 56   E get min {
 57     if (isEmpty) throw TreeEmptyException();
 58     return _minNode(_root).value;
 59   }
 60
 61   void traverse(void f(E e), [TraverseOrder order = TraverseOrder.inOrder]) =>
 62       _traverse(_root, order, f);
 63
 64   void _insert(RBTNode<E> inserted) {
 65     RBTNode<E> p, c = _root;
 66     while (c != null) {
 67       p = c;
 68       c = inserted.value.compareTo(c.value) <= 0 ? c.left : c.right;
 69     }
 70
 71     if (p == null) {
 72       _root = inserted;
 73     } else if (inserted.value.compareTo(p.value) <= 0) {
 74       p.left = inserted;
 75     } else {
 76       p.right = inserted;
 77     }
 78     inserted.parent = p;
 79     _nodeNumbers++;
 80   }
 81
 82   void _fixAfterInsert(RBTNode<E> node) {
 83     while (_hasRedFather(node) && _hasRedUncle(node)) {
 84       var g = _gparent(node);
 85       g.left.paintBlack();
 86       g.right.paintBlack();
 87       g.paintRed();
 88       node = g;
 89     }
 90
 91     if (_hasRedFather(node)) {
 92       var g = _gparent(node);
 93       if (node.parent == g.left) {
 94         if (node == node.parent.right) {
 95           _rotateLeft(node.parent);
 96           node = node.left;
 97         }
 98         _rotateRight(g);
 99       } else {
100         if (node == node.parent.left) {
101           _rotateRight(node.parent);
102           node = node.right;
103         }
104         _rotateLeft(g);
105       }
106       node.parent.paintBlack();
107       g.paintRed();
108     }
109     _root.paintBlack();
110   }
111
112   bool _hasRedFather(RBTNode<E> node) =>
113       node.parent != null && node.parent.isRed;
114
115   bool _hasRedUncle(RBTNode<E> node) {
116     var gparent = _gparent(node);
117     var uncle = node.parent == gparent.left ? gparent.right : gparent.left;
118     return uncle != null && uncle.isRed;
119   }
120
121   RBTNode _gparent(RBTNode<E> node) => node.parent.parent;
122
123   bool _delete(E value, void _fix(RBTNode<E> p, bool isLeft)) {
124     var d = find(value);
125     if (d == null) return false;
126
127     if (d.left != null && d.right != null) {
128       var s = _successor(d);
129       d.value = s.value;
130       d = s;
131     }
132     var rp = d.left ?? d.right;
133     rp?.parent = d.parent;
134     if (d.parent == null)
135       _root = rp;
136     else if (d == d.parent.left)
137       d.parent.left = rp;
138     else
139       d.parent.right = rp;
140
141     if (rp != null)
142       rp.paintBlack();
143     else if (d.isBlack && d.parent != null)
144       _fix(d.parent, d.parent.left == null);
145
146     _nodeNumbers--;
147     return true;
148   }
149
150   RBTNode<E> _successor(RBTNode<E> d) =>
151       d.right != null ? _minNode(d.right) : d.left;
152
153   void _fixAfterDelete(RBTNode<E> p, bool isLeft) {
154     var c = isLeft ? p.right : p.left;
155     if (isLeft) {
156       if (c.isRed) {
157         p.paintRed();
158         c.paintBlack();
159         _rotateLeft(p);
160         c = p.right;
161       }
162       if (c.left != null && c.left.isRed) {
163         c.left.paint(p.color);
164         if (p.isRed) p.paintBlack();
165         _rotateRight(c);
166         _rotateLeft(p);
167       } else {
168         _rotateLeft(p);
169         if (p.isBlack) {
170           p.paintRed();
171           if (c.parent != null) _fixAfterDelete(c.parent, c == c.parent.left);
172         }
173       }
174     } else {
175       if (c.isRed) {
176         p.paintRed();
177         c.paintBlack();
178         _rotateRight(p);
179         c = p.left;
180       }
181       if (c.right != null && c.right.isRed) {
182         c.right.paint(p.color);
183         if (p.isRed) p.paintBlack();
184         _rotateLeft(c);
185         _rotateRight(p);
186       } else {
187         _rotateRight(p);
188         if (p.isBlack) {
189           p.paintRed();
190           if (c.parent != null) _fixAfterDelete(c.parent, c == c.parent.left);
191         }
192       }
193     }
194   }
195
196   // the implement in Linux core.
197   void _fixAfterDelete2(RBTNode<E> p, bool isLeft) {
198     var c = isLeft ? p.right : p.left;
199     if (isLeft) {
200       if (c.isRed) {
201         p.paintRed();
202         c.paintBlack();
203         _rotateLeft(p);
204         c = p.right;
205       }
206       if ((c.left != null && c.left.isRed) ||
207           (c.right != null && c.right.isRed)) {
208         if (c.right == null || c.right.isBlack) {
209           _rotateRight(c);
210           c = p.right;
211         }
212         c.paint(p.color);
213         p.paintBlack();
214         c.right.paintBlack();
215         _rotateLeft(p);
216       } else {
217         c.paintRed();
218         if (p.isRed)
219           p.paintBlack();
220         else if (p.parent != null)
221           _fixAfterDelete2(p.parent, p == p.parent.left);
222       }
223     } else {
224       if (c.isRed) {
225         p.paintRed();
226         c.paintBlack();
227         _rotateRight(p);
228         c = p.left;
229       }
230       if ((c.left != null && c.left.isRed) ||
231           (c.right != null && c.right.isRed)) {
232         if (c.left == null || c.left.isBlack) {
233           _rotateLeft(c);
234           c = p.left;
235         }
236         c.paint(p.color);
237         p.paintBlack();
238         c.left.paintBlack();
239         _rotateRight(p);
240       } else {
241         c.paintRed();
242         if (p.isRed)
243           p.paintBlack();
244         else if (p.parent != null)
245           _fixAfterDelete2(p.parent, p == p.parent.left);
246       }
247     }
248   }
249
250   void _rotateLeft(RBTNode<E> node) {
251     var r = node.right, p = node.parent;
252     r.parent = p;
253     if (p == null)
254       _root = r;
255     else if (p.left == node)
256       p.left = r;
257     else
258       p.right = r;
259
260     node.right = r.left;
261     r.left?.parent = node;
262     r.left = node;
263     node.parent = r;
264   }
265
266   void _rotateRight(RBTNode<E> node) {
267     var l = node.left, p = node.parent;
268     l.parent = p;
269     if (p == null)
270       _root = l;
271     else if (p.left == node)
272       p.left = l;
273     else
274       p.right = l;
275
276     node.left = l.right;
277     l.right?.parent = node;
278     l.right = node;
279     node.parent = l;
280   }
281
282   RBTNode<E> _minNode(RBTNode<E> r) => r.left == null ? r : _minNode(r.left);
283
284   void _traverse(RBTNode<E> s, TraverseOrder order, void f(E e)) {
285     if (s == null) return;
286     switch (order) {
287       case TraverseOrder.inOrder:
288         _traverse(s.left, order, f);
289         f(s.value);
290         _traverse(s.right, order, f);
291         break;
292       case TraverseOrder.preOrder:
293         f(s.value);
294         _traverse(s.left, order, f);
295         _traverse(s.right, order, f);
296         break;
297       case TraverseOrder.postOrder:
298         _traverse(s.left, order, f);
299         _traverse(s.right, order, f);
300         f(s.value);
301         break;
302       default:
303         break;
304     }
305   }
306 }

原文地址:https://www.cnblogs.com/outerspace/p/10628956.html

时间: 2024-08-27 17:54:41

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

红黑树插入和删除的情况分析

红黑树是特殊二叉查找树的一种,一颗红黑树有以下5种性质: 1.根节点为黑色. 2.每个节点不是黑色就是红色. 3.每个红色节点的两个儿子一定是黑色. 4.所有的叶子节点都是黑色.(注:这里的叶子节点并不是真正意义上的叶子节点,而是一种只有颜色属性但不存放数据的节点,而且其没有儿子节点) 5.一个红黑树的中任取一个节点,从它所在位置到其他任何叶子节点的简单路径上所经过的黑色节点数相同. 这2个性质决定了从根节点到叶子节点的最长路径不可能大于最短路径的2倍.所以红黑树是一个大致平衡的二叉树.但跟AV

红黑树插入删除节点过程分析 &amp;&amp; C代码实现

红黑树的插入和删除规则: 红黑树的五个性质 1.    每个节点要么是红的,要么是黑的 2.    根节点时黑色的 3.    每个叶节点(叶节点既指树尾端NIL指针或NULL节点)是黑色的 4.    如果一个节点时红的,那么它的两个儿子都是黑色的 5.    对每个节点,其到叶节点树尾端NIL指针的每一条路径都包含相同数目的黑节点 这里所说的"叶节点"或者"NULL节点",它不包含数据而只充当树在此结束的知识. 二叉树的左旋和右旋这里不再讲解 红黑树的插入操作:

RBtree插入跟删除图解代码

一.红黑树的简介 红黑树是一种平衡的二叉查找树,是一种计算机科学中常用的数据结构,最典型的应用是实现数据的关联,例如map等数据结构的实现. 红黑树有以下限制: 1. 节点必须是红色或者是黑色 2. 根节点是黑色的 3. 所有的叶子节点是黑色的. 4. 每个红色节点的两个子节点是黑色的,也就是不能存在父子两个节点全是红色 5. 从任意每个节点到其每个叶子节点的所有简单路径上黑色节点的数量是相同的. 要说明一下限制3.一般在红黑树中,每个节点空指针处还会加空的黑色的孩子(称为岗哨).所以限制3一定

红黑树-插入操作

红黑树的五个性质: 1)每个结点要么是红的,要么是黑的. 2)根结点是黑的. 3)每个叶结点,即空结点(NIL)是黑的. 4)如果一个结点是红的,那么它的俩个儿子都是黑的. 5)对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点. 红黑树插入的几种情况: 1.树是空的,直接将节点设置为根节点,颜色为黑: public void case1(RBnode T,RBnode newNode){        if(newNode.getParent()==null){         

红黑树插入详解

查找二叉树插入节点: 已知查找二叉树的性质为根节点的值大于左子树的值,小于右子树的值,按照此规律,根据要插入的值为其寻找合适的插入位置,最后将其插入即可: Tree-Insert(T,z) { x = root(T); y = NULL; while(x != NULL) { y = x; if(key[z] < key[x]) x = left[x]; else x = right[x]; } p[z] = y; if(y == NULL) root[T] = z; else if(key[z

红黑树 插入

红黑树是一种二叉搜索树,每个节点增加一位来储存节点的颜色,红或黑. 红黑树通过如何一条从跟到叶子的路径上各个节点的着色方式的限制,红黑树确保没有一条路径比另一条路径长两倍. 其他性质: 根节点是黑色. 红色节点的子节点都为黑色. 叶子节点或NULL空节点都为黑色.所有原来的叶子节点都有NULL的空节点作为新的叶子节点,取代了自己的叶子节点的身份,即,所有的NULL节点都是黑色的意思. 最重要一点:任何一节点到叶子节点的NULL指针的路径经过的黑色节点数相同. 插入: 左旋 以节点p为支点的话,即

红黑树 节点的删除

接上一篇. 红黑树的插入操作! 红黑树的删除继续分各种情况进行考虑. 首先考虑红黑树的单支情况,即只有父节点只有一个子节点,另外一个为NULL,这样的话,只有一种情况,即父节点为黑色,子节点为红色,因为其他情况都会是孩子为黑色,因为孩子为红色父为红色,则与红父黑子矛盾.而当孩子是黑色时,另一个孩子是黑色的NULL,则必定使左右路径上黑色节点数量不等.所以单支只能为黑父红子. 这里的单支情况,是对任意一点的,若其只有一个孩子,则其必为黑色,孩子必为红色,且孩子为叶子节点.孩子为红色,如果有孙子,其

算法导论 之 红黑树 - 插入[C语言]

作者:邹祁峰 邮箱:[email protected] 博客:http://blog.csdn.net/qifengzou 日期:2013.12.24 21:00 转载请注明来自"祁峰"的CSDN博客 1 引言 在之前的博文中,本人对平衡二叉树的处理做了较详尽的分析,有兴趣的朋友可以参阅博文<算法导论 之 平衡二叉树 - 创建 插入 搜索 销毁>和<算法导论 之 平衡二叉树 - 删除>.平衡二叉树AVL是严格的平衡树,在增删结点时,其旋转操作的次数较多:而红黑树

初探红黑树-插入操作原理

事实总是因为人的欲望产生的, 想要才会有,而当大多数人想的一样的时候 就只会变成后人所得到生活 往复 引: 红黑树,应运而生 啊(叹气),反正我是这么认为的 比原来的它略显成熟,但又涉世不深,却又显其独到的风采 述: 需求,是红黑树的生来原因,哪方面呢,姑且我认为是效率 规则引来查询二叉树,简简单单,不复杂,说一就是一,说再见就再也不会见 但人的关系总是很复杂,规则也是相对的.当然也渲染到了查询二叉树身上 红黑树也只是复杂的其中一种而已,满足人们的欲求不满,可以这么说么? 路口一 基本理解树 基