-
Notifications
You must be signed in to change notification settings - Fork 79
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added 90% implementation of a Splay Tree in F#.
TODO: IDictionary interface IList interface on the TiedList class Make TiedList and SplayTreeNode private to the module See https://gist.github.com/940104 for reference implementation. Signed-off-by: John Gietzen <otac0n@gietzen.us>
- Loading branch information
Showing
1 changed file
with
298 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,298 @@ | ||
module SplayTree | ||
|
||
open System | ||
open System.Collections | ||
open System.Collections.Generic | ||
open System.Diagnostics | ||
|
||
[<AllowNullLiteral>] | ||
type SplayTreeNode<'TKey, 'TValue> = | ||
val Key:'TKey | ||
val mutable Value:'TValue | ||
|
||
[<DefaultValue>] | ||
val mutable Left:SplayTreeNode<'TKey,'TValue> | ||
|
||
[<DefaultValue>] | ||
val mutable Right:SplayTreeNode<'TKey,'TValue> | ||
|
||
new(key:'TKey, value:'TValue) = { Key = key; Value = value } | ||
|
||
|
||
type SplayTree<'TKey, 'TValue when 'TKey :> IComparable<'TKey> and 'TValue : equality>() as this = | ||
[<DefaultValue>] | ||
val mutable root:SplayTreeNode<'TKey,'TValue> | ||
|
||
[<DefaultValue>] | ||
val mutable count:int | ||
|
||
[<DefaultValue>] | ||
val mutable version:int | ||
|
||
member this.Add(key:'TKey, value:'TValue) = | ||
this.Set(key, value, true) | ||
|
||
member this.Add(item:KeyValuePair<'TKey, 'TValue>) = | ||
this.Set(item.Key, item.Value, true) | ||
|
||
member private this.Set(key:'TKey, value:'TValue, throwOnExisting:bool) = | ||
if this.count = 0 then | ||
this.version <- this.version + 1 | ||
this.root <- new SplayTreeNode<'TKey,'TValue>(key, value) | ||
this.count <- 1 | ||
else | ||
this.Splay(key) | ||
let c = key.CompareTo(this.root.Key) | ||
if c = 0 then | ||
if throwOnExisting then | ||
raise (new ArgumentException("An item with the same key already exists in the tree.")) | ||
this.version <- this.version + 1 | ||
this.root.Value <- value | ||
else | ||
let n = new SplayTreeNode<'TKey,'TValue>(key, value) | ||
if c < 0 then | ||
n.Left <- this.root.Left | ||
n.Right <- this.root | ||
this.root.Left <- null | ||
else | ||
n.Right <- this.root.Right | ||
n.Left <- this.root | ||
this.root.Right <- null; | ||
this.version <- this.version + 1 | ||
this.root <- n | ||
this.count <- this.count + 1 | ||
|
||
member this.Clear() = | ||
if this.count <> 0 then | ||
this.root <- null | ||
this.count <- 0 | ||
this.version <- this.version + 1 | ||
|
||
member this.ContainsKey(key:'TKey) = | ||
if this.count = 0 then | ||
false | ||
else | ||
this.Splay(key) | ||
key.CompareTo(this.root.Key) = 0 | ||
|
||
member this.Contains(item:KeyValuePair<'TKey, 'TValue>) = | ||
if this.count = 0 then | ||
false | ||
else | ||
this.Splay(item.Key) | ||
item.Key.CompareTo(this.root.Key) = 0 && (obj.ReferenceEquals(this.root.Value, item.Value) || (not (obj.ReferenceEquals(item.Value, null)) && item.Value.Equals(this.root.Value))) | ||
|
||
member private this.Splay(key:'TKey) = | ||
let mutable t = this.root | ||
let mutable header = new SplayTreeNode<'TKey,'TValue>(Unchecked.defaultof<'TKey>, Unchecked.defaultof<'TValue>) | ||
let mutable l = header | ||
let mutable r = header | ||
|
||
let mutable go = true | ||
while go do | ||
let c = key.CompareTo(t.Key) | ||
if c < 0 then | ||
if t.Left = null then | ||
go <- false | ||
else | ||
if key.CompareTo(t.Left.Key) < 0 then | ||
let temp = t.Left | ||
t.Left <- temp.Right | ||
temp.Right <- t | ||
t <- temp | ||
if t.Left = null then | ||
go <- false | ||
if go then | ||
r.Left <- t | ||
r <- t | ||
t <- t.Left | ||
elif c > 0 then | ||
if t.Right = null then | ||
go <- false | ||
else | ||
if key.CompareTo(t.Right.Key) > 0 then | ||
let temp = t.Right | ||
t.Right <- temp.Left | ||
temp.Left <- t | ||
t <- temp | ||
if t.Right = null then | ||
go <- false | ||
if go then | ||
l.Right <- t | ||
l <- t | ||
t <- t.Right | ||
else | ||
go <- false | ||
l.Right <- t.Left | ||
r.Left <- t.Right | ||
t.Left <- header.Right | ||
t.Right <- header.Left | ||
this.root <- t | ||
|
||
member this.Remove(key:'TKey) : bool = | ||
if this.count = 0 then | ||
false | ||
else | ||
this.Splay(key) | ||
if key.CompareTo(this.root.Key) <> 0 then | ||
false | ||
else | ||
if this.root.Left = null then | ||
this.root <- this.root.Right | ||
else | ||
let swap = this.root.Right | ||
this.root <- this.root.Left | ||
this.Splay(key) | ||
this.root.Right <- swap | ||
this.version <- this.version + 1 | ||
this.count <- this.count - 1 | ||
true | ||
|
||
member this.Remove(item:KeyValuePair<'TKey, 'TValue>) : bool = | ||
if this.count = 0 then | ||
false | ||
else | ||
this.Splay(item.Key) | ||
if item.Key.CompareTo(this.root.Key) = 0 && (obj.ReferenceEquals(this.root.Value, item.Value) || (not (obj.ReferenceEquals(item.Value, null)) && item.Value.Equals(this.root.Value))) then | ||
false | ||
else | ||
if this.root.Left = null then | ||
this.root <- this.root.Right | ||
else | ||
let swap = this.root.Right | ||
this.root <- this.root.Left | ||
this.Splay(item.Key) | ||
this.root.Right <- swap | ||
this.version <- this.version + 1 | ||
this.count <- this.count - 1 | ||
true | ||
|
||
member this.TryGetValue(key:'TKey, value:'TValue byref) = | ||
if this.count = 0 then | ||
value <- Unchecked.defaultof<'TValue> | ||
false | ||
else | ||
this.Splay(key) | ||
if key.CompareTo(this.root.Key) <> 0 then | ||
value <- Unchecked.defaultof<'TValue> | ||
false | ||
else | ||
value <- this.root.Value | ||
true | ||
|
||
member this.Item | ||
with get(key:'TKey) = | ||
if this.count = 0 then | ||
raise (new KeyNotFoundException("The key was not found in the tree.")) | ||
else | ||
this.Splay(key) | ||
if key.CompareTo(this.root.Key) <> 0 then | ||
raise (new KeyNotFoundException("The key was not found in the tree.")) | ||
else | ||
this.root.Value | ||
and set(key:'TKey) value = | ||
this.Set(key, value, false) | ||
|
||
member this.Count | ||
with get() = this.count | ||
|
||
member this.IsReadOnly | ||
with get() = false | ||
|
||
member this.Trim(depth:int) = | ||
if depth < 0 then | ||
raise (new ArgumentOutOfRangeException("depth", "The trim depth must not be negative.")) | ||
elif depth = 0 then | ||
this.Clear() | ||
elif this.count <> 0 then | ||
let prevCount = this.count | ||
this.count <- this.Trim(this.root, depth - 1) | ||
if prevCount <> this.count then | ||
this.version <- this.version + 1 | ||
|
||
member private this.Trim(node:SplayTreeNode<'TKey, 'TValue>, depth:int) = | ||
if depth = 0 then | ||
node.Left <- null | ||
node.Right <- null | ||
1 | ||
else | ||
let mutable count = 1 | ||
if node.Left <> null then | ||
count <- count + this.Trim(node.Left, depth - 1) | ||
if node.Right <> null then | ||
count <- count + this.Trim(node.Right, depth - 1) | ||
count | ||
|
||
member this.CopyTo(array:KeyValuePair<'TKey, 'TValue>[], arrayIndex:int) = | ||
this.AsList(fun node -> new KeyValuePair<'TKey, 'TValue>(node.Key, node.Value)).CopyTo(array, arrayIndex) | ||
|
||
member this.GetEnumerator() : IEnumerator<KeyValuePair<'TKey, 'TValue>> = | ||
(new TiedList<KeyValuePair<'TKey, 'TValue>,'TKey, 'TValue>(this, this.version, this.AsList(fun node -> new KeyValuePair<'TKey, 'TValue>(node.Key, node.Value)))).GetEnumerator() | ||
|
||
member private this.AsList<'TEnumerator>(selector:SplayTreeNode<'TKey, 'TValue>->'TEnumerator) : IList<'TEnumerator> = | ||
let result = new List<'TEnumerator>(this.count) | ||
if this.root <> null then | ||
this.PopulateList(this.root, result, selector) | ||
result :> IList<'TEnumerator> | ||
|
||
member private this.PopulateList(node:SplayTreeNode<'TKey, 'TValue>, list:List<'TEnumerator>, selector:SplayTreeNode<'TKey, 'TValue>->'TEnumerator) = | ||
if node.Left <> null then this.PopulateList(node.Left, list, selector) | ||
list.Add(selector(node)) | ||
if node.Right <> null then this.PopulateList(node.Right, list, selector) | ||
|
||
and TiedList<'T, 'TKey, 'TValue when 'TKey :> IComparable<'TKey> and 'TValue : equality>(tree:SplayTree<'TKey, 'TValue>, version:int, backingList:IList<'T>) as this = | ||
let tree = tree | ||
let version = version | ||
let backingList = backingList | ||
|
||
member private this.CheckVersion() = | ||
if version <> tree.version then | ||
raise (new InvalidOperationException("The collection has been modified.")) | ||
|
||
member this.Count | ||
with get() = tree.count | ||
|
||
member this.IsReadOnly | ||
with get() = true | ||
|
||
member this.Item | ||
with get index = | ||
this.CheckVersion() | ||
backingList.[index] | ||
and set index = | ||
raise (new NotSupportedException()) | ||
|
||
member this.IndexOf item = | ||
this.CheckVersion() | ||
backingList.IndexOf(item) | ||
|
||
member this.Insert(index:int, item:'T) = | ||
raise (new NotSupportedException()) | ||
|
||
member this.RemoveAt(index:int) = | ||
raise (new NotSupportedException()) | ||
|
||
member this.Add(item:'T) = | ||
raise (new NotSupportedException()) | ||
|
||
member this.Clear() = | ||
raise (new NotSupportedException()) | ||
|
||
member this.Contains item = | ||
this.CheckVersion() | ||
backingList.Contains(item) | ||
|
||
member this.CopyTo array arrayIndex = | ||
this.CheckVersion() | ||
backingList.CopyTo(array, arrayIndex) | ||
|
||
member this.Remove(item:'T) = | ||
raise (new NotSupportedException()) | ||
|
||
member this.GetEnumerator() = | ||
seq { for i in backingList do yield i } | ||
|
||
// interface IList<'T> with | ||
// member this.Count = this.Count ?? | ||
// ... | ||
|