4
// Mike Krüger <mkrueger@novell.com>
6
// Copyright (c) 2007 Novell, Inc (http://www.novell.com)
8
// Permission is hereby granted, free of charge, to any person obtaining a copy
9
// of this software and associated documentation files (the "Software"), to deal
10
// in the Software without restriction, including without limitation the rights
11
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
// copies of the Software, and to permit persons to whom the Software is
13
// furnished to do so, subject to the following conditions:
15
// The above copyright notice and this permission notice shall be included in
16
// all copies or substantial portions of the Software.
18
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30
using System.Diagnostics;
31
using System.Collections.Generic;
33
namespace Mono.TextEditor
35
public class RedBlackTree<T> : ICollection<T>
37
public RedBlackTreeNode Root {
42
public void Add (RedBlackTreeNode node)
47
FixTreeOnInsert (node);
51
RedBlackTreeNode parent = Root;
54
if (((IComparable)parent.value).CompareTo (node.value) <= 0) {
55
if (parent.left == null) {
56
Insert (parent, node, true);
61
if (parent.right == null) {
62
Insert (parent, node, false);
65
parent = parent.right;
70
public RedBlackTreeIterator Insert (RedBlackTreeNode parent, RedBlackTreeNode node, bool insertLeft)
73
Debug.Assert (parent.left == null);
76
Debug.Assert (parent.right == null);
82
this.OnChildrenChanged (new RedBlackTreeNodeEventArgs (parent));
83
FixTreeOnInsert (node);
85
return new RedBlackTreeIterator (node);
88
void FixTreeOnInsert (RedBlackTreeNode node)
90
if (node.parent == null) {
95
if (node.parent.color == black)
98
if (node.Uncle != null && node.Uncle.color == red) {
99
node.parent.color = black;
100
node.Uncle.color = black;
101
node.Grandparent.color = red;
102
FixTreeOnInsert (node.Grandparent);
106
if (node == node.parent.right && node.parent == node.Grandparent.left) {
107
RotateLeft (node.parent);
109
} else if (node == node.parent.left && node.parent == node.Grandparent.right) {
110
RotateRight (node.parent);
114
node.parent.color = black;
115
node.Grandparent.color = red;
116
if (node == node.parent.left && node.parent == node.Grandparent.left) {
117
RotateRight (node.Grandparent);
119
RotateLeft (node.Grandparent);
123
void RotateLeft (RedBlackTreeNode node)
125
RedBlackTreeNode right = node.right;
126
this.Replace (node, right);
127
node.right = right.left;
128
if (node.right != null)
129
node.right.parent = node;
132
this.OnNodeRotateLeft (new RedBlackTreeNodeEventArgs (node));
135
void RotateRight (RedBlackTreeNode node)
137
RedBlackTreeNode left = node.left;
138
Replace (node, left);
139
node.left = left.right;
140
if (node.left != null)
141
node.left.parent = node;
144
this.OnNodeRotateRight (new RedBlackTreeNodeEventArgs (node));
147
public void RemoveAt (RedBlackTreeIterator iter)
151
} catch (Exception e) {
152
string s1 = "remove:" + iter.node.value;
153
string s2 = this.ToString ();
154
Console.WriteLine (s1);
155
Console.WriteLine (s2);
156
Console.WriteLine ("----");
157
Console.WriteLine (e);
162
void Replace (RedBlackTreeNode oldNode, RedBlackTreeNode newNode)
165
newNode.parent = oldNode.parent;
166
if (oldNode.parent == null) {
169
if (oldNode.parent.left == oldNode)
170
oldNode.parent.left = newNode;
172
oldNode.parent.right = newNode;
173
this.OnChildrenChanged (new RedBlackTreeNodeEventArgs (oldNode.parent));
177
public void Remove (RedBlackTreeNode node)
179
if (node.left != null && node.right != null) {
180
RedBlackTreeNode outerLeft = node.right.OuterLeft;
182
Replace (node, outerLeft);
184
outerLeft.color = node.color;
185
outerLeft.left = node.left;
186
if (outerLeft.left != null)
187
outerLeft.left.parent = outerLeft;
189
outerLeft.right = node.right;
190
if (outerLeft.right != null)
191
outerLeft.right.parent = outerLeft;
192
this.OnChildrenChanged (new RedBlackTreeNodeEventArgs (outerLeft));
196
// node has only one child
197
RedBlackTreeNode child = node.left ?? node.right;
199
Replace (node, child);
201
if (node.color == black && child != null) {
202
if (child.color == red) {
205
DeleteOneChild (child);
210
static bool GetColorSafe (RedBlackTreeNode node)
212
return node != null ? node.color : black;
215
void DeleteOneChild (RedBlackTreeNode node)
218
if (node == null || node.parent == null)
221
RedBlackTreeNode parent = node.parent;
222
RedBlackTreeNode sibling = node.Sibling;
227
if (sibling.color == red) {
229
sibling.color = black;
230
if (node == parent.left) {
233
RotateRight (parent);
235
sibling = node.Sibling;
241
if (parent.color == black &&
242
sibling.color == black &&
243
GetColorSafe (sibling.left) == black &&
244
GetColorSafe (sibling.right) == black) {
246
DeleteOneChild (parent);
251
if (parent.color == red &&
252
sibling.color == black &&
253
GetColorSafe (sibling.left) == black &&
254
GetColorSafe (sibling.right) == black) {
256
parent.color = black;
261
if (node == parent.left &&
262
sibling.color == black &&
263
GetColorSafe (sibling.left) == red &&
264
GetColorSafe (sibling.right) == black) {
266
if (sibling.left != null)
267
sibling.left.color = black;
268
RotateRight (sibling);
269
} else if (node == parent.right &&
270
sibling.color == black &&
271
GetColorSafe (sibling.right) == red &&
272
GetColorSafe (sibling.left) == black) {
274
if (sibling.right != null)
275
sibling.right.color = black;
276
RotateLeft (sibling);
280
sibling = node.Sibling;
283
sibling.color = parent.color;
284
parent.color = black;
285
if (node == parent.left) {
286
if (sibling.right != null)
287
sibling.right.color = black;
290
if (sibling.left != null)
291
sibling.left.color = black;
292
RotateRight (parent);
296
#region ICollection<T> implementation
302
public void Add(T item)
304
Add (new RedBlackTreeNode (item));
313
public bool Contains(T item)
315
RedBlackTreeIterator iter = new RedBlackTreeIterator (Root.OuterLeft);
316
while (iter.IsValid) {
317
if (iter.Current.Equals (item))
324
public bool Remove(T item)
326
RedBlackTreeIterator iter = new RedBlackTreeIterator (Root.OuterLeft);
327
while (iter.IsValid) {
328
if (iter.Current.Equals (item)) {
329
this.RemoveAt (iter);
337
IEnumerator<T> IEnumerable<T>.GetEnumerator()
339
return GetEnumerator();
342
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
344
return GetEnumerator();
347
public bool IsReadOnly {
348
get { return false; }
352
public void CopyTo (T[] array, int arrayIndex)
354
Debug.Assert (array != null);
355
Debug.Assert (0 <= arrayIndex && arrayIndex < array.Length);
357
foreach (T value in this)
361
public RedBlackTreeIterator GetEnumerator()
365
RedBlackTreeNode dummyNode = new RedBlackTreeNode (default(T));
366
dummyNode.right = Root;
367
return new RedBlackTreeIterator (dummyNode);
371
public event EventHandler<RedBlackTreeNodeEventArgs> ChildrenChanged;
372
protected virtual void OnChildrenChanged (RedBlackTreeNodeEventArgs args)
374
if (ChildrenChanged != null)
375
ChildrenChanged (this, args);
378
public event EventHandler<RedBlackTreeNodeEventArgs> NodeRotateLeft;
379
protected virtual void OnNodeRotateLeft (RedBlackTreeNodeEventArgs args)
381
if (NodeRotateLeft != null)
382
NodeRotateLeft (this, args);
385
public event EventHandler<RedBlackTreeNodeEventArgs> NodeRotateRight;
386
protected virtual void OnNodeRotateRight (RedBlackTreeNodeEventArgs args)
388
if (NodeRotateRight != null)
389
NodeRotateRight (this, args);
392
public class RedBlackTreeNodeEventArgs : EventArgs
394
public RedBlackTreeNode Node {
399
public RedBlackTreeNodeEventArgs (RedBlackTreeNode node)
405
string GetIndent (int level)
407
return new String ('\t', level);
410
void AppendNode (StringBuilder builder, RedBlackTreeNode node, int indent)
412
builder.Append (GetIndent (indent) + "Node (" + (node.color == red ? "r" : "b" ) + "):" + node.value.ToString () + Environment.NewLine);
413
builder.Append (GetIndent (indent) + "Left: ");
414
if (node.left != null) {
415
builder.Append (Environment.NewLine);
416
AppendNode (builder, node.left, indent + 1);
418
builder.Append ("null");
421
builder.Append (Environment.NewLine);
422
builder.Append (GetIndent (indent) + "Right: ");
423
if (node.right != null) {
424
builder.Append (Environment.NewLine);
425
AppendNode (builder, node.right, indent + 1);
427
builder.Append ("null");
431
public override string ToString ()
433
StringBuilder result = new StringBuilder ();
434
AppendNode (result, Root, 0);
435
return result.ToString ();
438
static bool red = true;
439
static bool black = false;
441
public class RedBlackTreeNode
443
public RedBlackTreeNode parent;
444
public RedBlackTreeNode left, right;
448
public RedBlackTreeNode (T value)
455
return left == null && right == null;
459
public RedBlackTreeNode Sibling {
463
return this == parent.left ? parent.right : parent.left;
466
public RedBlackTreeNode OuterLeft {
468
return left != null ? left.OuterLeft : this;
472
public RedBlackTreeNode OuterRight {
474
return right != null ? right.OuterRight : this;
478
public RedBlackTreeNode Grandparent {
480
return parent != null ? parent.parent : null;
484
public RedBlackTreeNode Uncle {
486
RedBlackTreeNode grandparent = Grandparent;
487
if (grandparent == null)
489
return parent == grandparent.left ? grandparent.right : grandparent.left;
494
public class RedBlackTreeIterator : IEnumerator<T>
496
public RedBlackTreeNode startNode;
497
public RedBlackTreeNode node;
499
public RedBlackTreeIterator (RedBlackTreeNode node)
501
this.startNode = this.node = node;
504
public RedBlackTreeIterator Clone ()
506
return new RedBlackTreeIterator (this.startNode);
509
public bool IsValid {
510
get { return node != null; }
515
return node != null ? node.value : default(T);
519
public RedBlackTreeNode CurrentNode {
525
object System.Collections.IEnumerator.Current {
533
this.node = this.startNode;
536
public void Dispose ()
540
public bool MoveNext ()
544
if (node.right == null) {
545
RedBlackTreeNode oldNode;
549
} while (node != null && node.right == oldNode);
551
node = node.right.OuterLeft;
556
public bool MoveBack ()
560
if (node.left == null) {
561
RedBlackTreeNode oldNode;
565
} while (node != null && node.left == oldNode);
567
node = node.left.OuterRight;