diff options
author | Rich Hickey <richhickey@gmail.com> | 2006-06-07 18:54:53 +0000 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2006-06-07 18:54:53 +0000 |
commit | 59d0ff1ec90c4b325e161cdbbe304a159180d53b (patch) | |
tree | 40250b99f4fe47e0bbbf49ae462ee8792729b79c /src/cli/runtime/PersistentTree.cs | |
parent | 66038cc7c71c09785e18fa0f4a5b2af675bd7803 (diff) |
renamed to PersistentTree
Diffstat (limited to 'src/cli/runtime/PersistentTree.cs')
-rw-r--r-- | src/cli/runtime/PersistentTree.cs | 789 |
1 files changed, 789 insertions, 0 deletions
diff --git a/src/cli/runtime/PersistentTree.cs b/src/cli/runtime/PersistentTree.cs new file mode 100644 index 00000000..3ed31f41 --- /dev/null +++ b/src/cli/runtime/PersistentTree.cs @@ -0,0 +1,789 @@ +/** + * Copyright (c) Rich Hickey. All rights reserved. + * The use and distribution terms for this software are covered by the + * Common Public License 1.0 (http://opensource.org/licenses/cpl.php) + * which can be found in the file CPL.TXT at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +/* rich May 20, 2006 */ + +using System;
+using System.Collections;
+using System.Collections.Specialized;
+ +namespace org.clojure.runtime
+{ + +/** + * Persistent Red Black Tree + * Note that instances of this class are constant values + * i.e. add/remove etc return new values + * <p/> + * See Okasaki, Kahrs, Larsen et al + */ + +public class PersistentTree : IPersistentMap{ + +public readonly IComparer comp; +public readonly Node tree; +public readonly int _count; + +public PersistentTree():this(null){ +} + +public PersistentTree(IComparer comp){ + this.comp = comp; + tree = null; + _count = 0; +} + +public int count(){ + return _count; + } + +public int capacity(){ + return _count; + } + +public bool contains(Object key){ + return find(key) != null; +}
+
+ public IPersistentMap add(Object key)
+ { + return put(key, null); +} + +public IPersistentMap put(Object key, Object val){ + Box found = new Box(null); + Node t = add(tree, key, val, found); + if(t == null) //null == already contains key + { + Node foundNode = (Node) found.val; + if(foundNode.val() == val) //note only get same collection on identity of val, not equals() + return this; + return new PersistentTree(comp, replace(tree, key, val), _count); + } + return new PersistentTree(comp, t.blacken(), _count + 1); +} + + +public IPersistentMap remove(Object key){ + Box found = new Box(null); + Node t = remove(tree, key, found); + if(t == null) + { + if(found.val == null)//null == doesn't contain key + return this; + //empty + return new PersistentTree(comp); + } + return new PersistentTree(comp, t.blacken(), _count - 1); +} + + +public IEnumerator GetEnumerator(){ + return new NodeIEnumerator(tree, true); +} + +public NodeIEnumerator reverseIEnumerator(){ + return new NodeIEnumerator(tree, false); +} + +public IEnumerator keys(){
+return keys((NodeIEnumerator)GetEnumerator()); +} + +public IEnumerator vals(){
+return vals((NodeIEnumerator)GetEnumerator()); +} + +public IEnumerator keys(NodeIEnumerator it){ + return new KeyIEnumerator(it); +} + +public IEnumerator vals(NodeIEnumerator it){ + return new ValIEnumerator(it); +} + +public Object minKey(){ + Node t = min(); + return t!=null?t._key:null; +} + +public Node min(){ + Node t = tree; + if(t != null) + { + while(t.left() != null) + t = t.left(); + } + return t; +} + +public Object maxKey(){ + Node t = max(); + return t!=null?t._key:null; +} + +public Node max(){ + Node t = tree; + if(t != null) + { + while(t.right() != null) + t = t.right(); + } + return t; +} + +public int depth(){ + return depth(tree); +} + +int depth(Node t){ + if(t == null) + return 0; + return 1 + Math.Max(depth(t.left()), depth(t.right())); +} + +public Object get(Object key){ + Node n = (Node)find(key); + return (n != null) ? n.val() : null; +} + +public IMapEntry find(Object key){ + Node t = tree; + while(t != null) + { + int c = compare(key, t._key); + if(c == 0) + return t; + else if(c < 0) + t = t.left(); + else + t = t.right(); + } + return t; +} + +int compare(Object k1, Object k2){ + if(comp != null) + return comp.Compare(k1, k2); + return ((IComparable) k1).CompareTo(k2); +} + +Node add(Node t, Object key, Object val, Box found){ + if(t == null) + { + if(val == null) + return new Red(key); + return new RedVal(key, val); + } + int c = compare(key, t._key); + if(c == 0) + { + found.val = t; + return null; + } + Node ins = c < 0 ? add(t.left(), key, val, found) : add(t.right(), key, val, found); + if(ins == null) //found below + return null; + if(c < 0) + return t.addLeft(ins); + return t.addRight(ins); +} + +Node remove(Node t, Object key, Box found){ + if(t == null) + return null; //not found indicator + int c = compare(key, t._key); + if(c == 0) + { + found.val = t; + return append(t.left(), t.right()); + } + Node del = c < 0 ? remove(t.left(), key, found) : remove(t.right(), key, found); + if(del == null && found.val == null) //not found below + return null; + if(c < 0) + { + if(t.left() is Black) + return balanceLeftDel(t._key, t.val(), del, t.right()); + else + return red(t._key, t.val(), del, t.right()); + } + if(t.right() is Black) + return balanceRightDel(t._key, t.val(), t.left(), del); + return red(t._key, t.val(), t.left(), del); +// return t.removeLeft(del); +// return t.removeRight(del); +} + +static Node append(Node left, Node right){ + if(left == null) + return right; + else if(right == null) + return left; + else if(left is Red) + { + if(right is Red) + { + Node app = append(left.right(), right.left()); + if(app is Red) + return red(app._key, app.val(), + red(left._key, left.val(), left.left(), app.left()), + red(right._key, right.val(), app.right(), right.right())); + else + return red(left._key, left.val(), left.left(), red(right._key, right.val(), app, right.right())); + } + else + return red(left._key, left.val(), left.left(), append(left.right(), right)); + } + else if(right is Red) + return red(right._key, right.val(), append(left, right.left()), right.right()); + else //black/black + { + Node app = append(left.right(), right.left()); + if(app is Red) + return red(app._key, app.val(), + black(left._key, left.val(), left.left(), app.left()), + black(right._key, right.val(), app.right(), right.right())); + else + return balanceLeftDel(left._key, left.val(), left.left(), black(right._key, right.val(), app, right.right())); + } +} + +static Node balanceLeftDel(Object key, Object val, Node del, Node right){ + if(del is Red) + return red(key, val, del.blacken(), right); + else if(right is Black) + return rightBalance(key, val, del, right.redden()); + else if(right is Red && right.left() is Black) + return red(right.left()._key, right.left().val(), + black(key, val, del, right.left().left()), + rightBalance(right._key, right.val(), right.left().right(), right.right().redden())); + else + throw new InvalidOperationException("Invariant violation"); +} + +static Node balanceRightDel(Object key, Object val, Node left, Node del){ + if(del is Red) + return red(key, val, left, del.blacken()); + else if(left is Black) + return leftBalance(key, val, left.redden(), del); + else if(left is Red && left.right() is Black) + return red(left.right()._key, left.right().val(), + leftBalance(left._key, left.val(), left.left().redden(), left.right().left()), + black(key, val, left.right().right(), del)); + else + throw new InvalidOperationException("Invariant violation"); +} + +static Node leftBalance(Object key, Object val, Node ins, Node right){ + if(ins is Red && ins.left() is Red) + return red(ins._key, ins.val(), ins.left().blacken(), black(key, val, ins.right(), right)); + else if(ins is Red && ins.right() is Red) + return red(ins.right()._key, ins.right().val(), + black(ins._key, ins.val(), ins.left(), ins.right().left()), + black(key, val, ins.right().right(), right)); + else + return black(key, val, ins, right); +} + + +static Node rightBalance(Object key, Object val, Node left, Node ins){ + if(ins is Red && ins.right() is Red) + return red(ins._key, ins.val(), black(key, val, left, ins.left()), ins.right().blacken()); + else if(ins is Red && ins.left() is Red) + return red(ins.left()._key, ins.left().val(), + black(key, val, left, ins.left().left()), + black(ins._key, ins.val(), ins.left().right(), ins.right())); + else + return black(key, val, left, ins); +} + +Node replace(Node t, Object key, Object val){ + int c = compare(key, t._key); + return t.replace(t._key, + c == 0 ? val : t.val(), + c < 0 ? replace(t.left(), key, val) : t.left(), + c > 0 ? replace(t.right(), key, val) : t.right()); +} + +PersistentTree(IComparer comp, Node tree, int count){ + this.comp = comp; + this.tree = tree; + this._count = count; +} + +static Red red(Object key, Object val, Node left, Node right){ + if(left == null && right == null) + { + if(val == null) + return new Red(key); + return new RedVal(key, val); + } + if(val == null) + return new RedBranch(key, left, right); + return new RedBranchVal(key, val, left, right); +} + +static Black black(Object key, Object val, Node left, Node right){ + if(left == null && right == null) + { + if(val == null) + return new Black(key); + return new BlackVal(key, val); + } + if(val == null) + return new BlackBranch(key, left, right); + return new BlackBranchVal(key, val, left, right); +} + + +public abstract class Node : IMapEntry{ + internal readonly Object _key; + + internal Node(Object key){ + this._key = key; + } + + public Object key(){ + return _key; + } + + virtual public Object val(){ + return null; + }
+
+ internal virtual Node left()
+ { + return null; + }
+
+ internal virtual Node right()
+ { + return null; + } + + internal abstract Node addLeft(Node ins);
+
+ internal abstract Node addRight(Node ins);
+
+ internal abstract Node removeLeft(Node del);
+
+ internal abstract Node removeRight(Node del);
+
+ internal abstract Node blacken();
+
+ internal abstract Node redden();
+
+ internal virtual Node balanceLeft(Node parent)
+ { + return black(parent._key, parent.val(), this, parent.right()); + }
+
+ internal virtual Node balanceRight(Node parent)
+ { + return black(parent._key, parent.val(), parent.left(), this); + }
+
+ internal abstract Node replace(Object key, Object val, Node left, Node right); +} + +class Black : Node{ + public Black(Object key):base(key){ + } + + internal override Node addLeft(Node ins){ + return ins.balanceLeft(this); + }
+
+ internal override Node addRight(Node ins)
+ { + return ins.balanceRight(this); + }
+
+ internal override Node removeLeft(Node del)
+ { + return balanceLeftDel(_key, val(), del, right()); + }
+
+ internal override Node removeRight(Node del)
+ { + return balanceRightDel(_key, val(), left(), del); + }
+
+ internal override Node blacken()
+ { + return this; + }
+
+ internal override Node redden()
+ { + return new Red(_key); + }
+
+ internal override Node replace(Object key, Object val, Node left, Node right)
+ { + return black(key, val, left, right); + } +} + +class BlackVal : Black{ + readonly Object _val; + + public BlackVal(Object key, Object val):base(key){ + this._val = val; + } + + override public Object val(){ + return _val; + }
+
+ internal override Node redden()
+ { + return new RedVal(_key, _val); + } + +} + +class BlackBranch : Black{ + internal readonly Node _left; + internal readonly Node _right; + + public BlackBranch(Object key, Node left, Node right):base(key){ + this._left = left; + this._right = right; + }
+
+ internal override Node left()
+ { + return _left; + }
+
+ internal override Node right()
+ { + return _right; + }
+
+ internal override Node redden()
+ { + return new RedBranch(_key, _left, _right); + } + +} + +class BlackBranchVal : BlackBranch{ + readonly Object _val; + + public BlackBranchVal(Object key, Object val, Node left, Node right): base(key, left, right){ + this._val = val; + } + + override public Object val(){ + return _val; + }
+
+ internal override Node redden()
+ { + return new RedBranchVal(_key, _val, _left, _right); + } + +} + +class Red : Node{ + public Red(Object key):base(key){ + }
+
+ internal override Node addLeft(Node ins)
+ { + return red(_key, val(), ins, right()); + }
+
+ internal override Node addRight(Node ins)
+ { + return red(_key, val(), left(), ins); + }
+
+ internal override Node removeLeft(Node del)
+ { + return red(_key, val(), del, right()); + }
+
+ internal override Node removeRight(Node del)
+ { + return red(_key, val(), left(), del); + }
+
+ internal override Node blacken()
+ { + return new Black(_key); + }
+
+ internal override Node redden()
+ { + throw new InvalidOperationException("Invariant violation"); + }
+
+ internal override Node replace(Object key, Object val, Node left, Node right)
+ { + return red(key, val, left, right); + } +} + +class RedVal : Red{ + readonly Object _val; + + public RedVal(Object key, Object val):base(key){ + this._val = val; + } + + override public Object val(){ + return _val; + }
+
+ internal override Node blacken()
+ { + return new BlackVal(_key, _val); + } +} + +class RedBranch : Red{ + internal readonly Node _left; + internal readonly Node _right; + + public RedBranch(Object key, Node left, Node right):base(key){ + this._left = left; + this._right = right; + }
+
+ internal override Node left()
+ { + return _left; + }
+
+ internal override Node right()
+ { + return _right; + }
+
+ internal override Node balanceLeft(Node parent)
+ { + if(_left is Red) + return red(_key, val(), _left.blacken(), black(parent._key, parent.val(), _right, parent.right())); + else if(_right is Red) + return red(_right._key, _right.val(), black(_key, val(), _left, _right.left()), + black(parent._key, parent.val(), _right.right(), parent.right())); + else + return base.balanceLeft(parent); + + }
+
+ internal override Node balanceRight(Node parent)
+ { + if(_right is Red) + return red(_key, val(), black(parent._key, parent.val(), parent.left(), _left), _right.blacken()); + else if(_left is Red) + return red(_left._key, _left.val(), black(parent._key, parent.val(), parent.left(), _left.left()), + black(_key, val(), _left.right(), _right)); + else + return base.balanceRight(parent); + }
+
+ internal override Node blacken()
+ { + return new BlackBranch(_key, _left, _right); + } +} + +class RedBranchVal : RedBranch{ + readonly Object _val; + + public RedBranchVal(Object key, Object val, Node left, Node right):base(key, left, right){ + + this._val = val; + } + + override public Object val(){ + return _val; + }
+
+ internal override Node blacken()
+ { + return new BlackBranchVal(_key, _val, _left, _right); + } +} + +public class NodeIEnumerator : IEnumerator{ + Stack stack = new Stack(); + bool asc;
+ object curr; + + internal NodeIEnumerator(Node t, bool asc){ + this.asc = asc; + push(t); + } + + void push(Node t){ + while(t != null) + { + stack.Push(t); + t = asc ? t.left() : t.right(); + } + } + + bool hasNext(){ + return !(stack.Count == 0); + } + + Object next(){ + Node t = (Node) stack.Pop(); + push(asc ? t.right() : t.left()); + return t; + } + + public void remove(){ + throw new InvalidOperationException(); + }
+
+#region IEnumerator Members
+
+public object Current
+ {
+ get { return curr; }
+ }
+
+public bool MoveNext()
+ {
+ if (hasNext())
+ {
+ curr = next();
+ return true;
+ }
+ return false;
+ }
+
+public void Reset()
+ {
+ throw new Exception("The method or operation is not implemented.");
+ }
+
+#endregion
+ } + +class KeyIEnumerator : IEnumerator{ + NodeIEnumerator it; + + internal KeyIEnumerator(NodeIEnumerator it){ + this.it = it; + } +
+#region IEnumerator Members
+
+public object Current
+{
+get { return ((Node)it.Current)._key; }
+}
+
+public bool MoveNext()
+{
+return it.MoveNext();
+}
+
+public void Reset()
+{
+ throw new Exception("The method or operation is not implemented.");
+}
+
+#endregion
+} + +class ValIEnumerator : IEnumerator{ + NodeIEnumerator it; + + internal ValIEnumerator(NodeIEnumerator it){ + this.it = it; + }
+
+#region IEnumerator Members
+
+public object Current
+ {
+ get { return ((Node)it.Current).val(); }
+ }
+
+public bool MoveNext()
+ {
+ return it.MoveNext();
+ }
+
+public void Reset()
+ {
+ throw new Exception("The method or operation is not implemented.");
+ }
+
+#endregion
+ } + + /*
+ [STAThread] +static public void Main(String[] args){ + if(args.Length != 1) + Console.Error.WriteLine("Usage: RBTree n"); + int n = Int32.Parse(args[0]); + Object[] ints = new Object[n]; + for(int i = 0; i < ints.Length; i++) + { + ints[i] = i; + } + //Collections.shuffle(Arrays.asList(ints));
+ Array.Reverse(ints); + Console.WriteLine("Building set"); + RBTree set = new RBTree(); + //for(int i = 0; i < ints.Length; i++) + // { + // Object anInt = ints[i]; + // set = set.add(anInt); + // } + for(int i = 0; i < ints.Length; i++) + { + Object anInt = ints[i]; + set = set.put(anInt, anInt); + }
+ Console.WriteLine("Building SortedList");
+ SortedList od = new SortedList();
+ for (int i = 0; i < ints.Length; i++)
+ {
+ Object anInt = ints[i];
+ od.Add(anInt, anInt);
+ }
+ + Console.Error.WriteLine("count = " + set.count + ", min: " + set.minKey() + ", max: " + set.maxKey() + + ", depth: " + set.depth()); + IEnumerator it = set.keys(); + while(it.MoveNext()) + { + Object o = it.Current; + if(!set.contains(o)) + Console.Error.WriteLine("Can't find: " + o); + else if(n < 2000) + Console.Write(o.ToString() + ","); + } + + for(int i = 0; i < ints.Length/2; i++) + { + Object anInt = ints[i]; + set = set.remove(anInt); + } + + Console.Error.WriteLine(); + Console.Error.WriteLine("count = " + set.count + ", min: " + set.minKey() + ", max: " + set.maxKey() + + ", depth: " + set.depth()); +} + //*/ +} + } |