当前位置:
首页 > Python基础教程 >
-
C#教程之红黑树插入与删除完整代码(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 }
栏目列表
最新更新
nodejs爬虫
Python正则表达式完全指南
爬取豆瓣Top250图书数据
shp 地图文件批量添加字段
爬虫小试牛刀(爬取学校通知公告)
【python基础】函数-初识函数
【python基础】函数-返回值
HTTP请求:requests模块基础使用必知必会
Python初学者友好丨详解参数传递类型
如何有效管理爬虫流量?
SQL SERVER中递归
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
初入Sql Server 之 存储过程的简单使用
这是目前我见过最好的跨域解决方案!
减少回流与重绘
减少回流与重绘
如何使用KrpanoToolJS在浏览器切图
performance.now() 与 Date.now() 对比
一款纯 JS 实现的轻量化图片编辑器
关于开发 VS Code 插件遇到的 workbench.scm.
前端设计模式——观察者模式
前端设计模式——中介者模式
创建型-原型模式