diff --git a/downloads/WBTrees-1.0.4.cs b/downloads/WBTrees-1.0.4.cs index 7968242..432aad4 100644 --- a/downloads/WBTrees-1.0.4.cs +++ b/downloads/WBTrees-1.0.4.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; +// https://github.com/sakapon/WBTrees namespace WBTrees { public static class ComparerHelper diff --git a/source/WBTrees1/TreesLab/AvlTrees301/AvlTree.cs b/source/WBTrees1/TreesLab/AvlTrees301/AvlTree.cs new file mode 100644 index 0000000..c918990 --- /dev/null +++ b/source/WBTrees1/TreesLab/AvlTrees301/AvlTree.cs @@ -0,0 +1,367 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +// A list by a weighted height-balanced binary tree +namespace TreesLab.AvlTrees301 +{ + [System.Diagnostics.DebuggerDisplay(@"\{{Item}\}")] + public class Node + { + #region Properties + + public T Item { get; internal set; } + public Node Parent { get; internal set; } + public Node Left { get; private set; } + public Node Right { get; private set; } + + internal void SetLeft(Node node) + { + Left = node; + if (node != null) node.Parent = this; + } + + internal void SetRight(Node node) + { + Right = node; + if (node != null) node.Parent = this; + } + + public int Height { get; private set; } = 1; + public int LeftHeight => Left?.Height ?? 0; + public int RightHeight => Right?.Height ?? 0; + + public int Count { get; private set; } = 1; + public int LeftCount => Left?.Count ?? 0; + public int RightCount => Right?.Count ?? 0; + + internal void UpdateStates(bool recursive = false) + { + Height = Math.Max(LeftHeight, RightHeight) + 1; + Count = LeftCount + RightCount + 1; + if (recursive) Parent?.UpdateStates(true); + } + + #endregion + + #region Get Node + + public Node GetPrevious() => Left?.GetLast() ?? GetPreviousAncestor(); + public Node GetNext() => Right?.GetFirst() ?? GetNextAncestor(); + + Node GetPreviousAncestor() => Parent?.Right == this ? Parent : Parent?.GetPreviousAncestor(); + Node GetNextAncestor() => Parent?.Left == this ? Parent : Parent?.GetNextAncestor(); + + public Node GetFirst() => Left?.GetFirst() ?? this; + public Node GetLast() => Right?.GetLast() ?? this; + + #endregion + + #region Get Node (by Index) + + // out of range: null + public Node GetAt(int index) + { + var d = index - LeftCount; + if (d == 0) return this; + else if (d < 0) return Left?.GetAt(index); + else return Right?.GetAt(d - 1); + } + + #endregion + + #region Get Index + + public int GetIndex() + { + if (Parent == null) return LeftCount; + else if (Parent.Left == this) return Parent.GetIndex() - RightCount - 1; + else return Parent.GetIndex() + LeftCount + 1; + } + + #endregion + + public void Walk(Action> preorder, Action> inorder, Action> postorder) + { + preorder?.Invoke(this); + Left?.Walk(preorder, inorder, postorder); + inorder?.Invoke(this); + Right?.Walk(preorder, inorder, postorder); + postorder?.Invoke(this); + } + } + + public static class NodeHelper + { + public static bool Exists(this Node node) => node != null; + + public static T GetItemOrDefault(this Node node, T defaultItem = default(T)) => node != null ? node.Item : defaultItem; + public static bool TryGetItem(this Node node, out T item) + { + item = node != null ? node.Item : default(T); + return node != null; + } + } + + [System.Diagnostics.DebuggerDisplay(@"Count = {Count}")] + public class AvlList : IEnumerable + { + #region Properties + + public Node Root { get; private set; } + public int Count => Root?.Count ?? 0; + + // Call this method to update the Root object. + protected void SetRoot(Node node) + { + Root = node; + if (node != null) node.Parent = null; + } + + #endregion + + #region Initialize Tree + + public void Clear() => SetRoot(null); + + public void Initialize(IEnumerable items) + { + if (items == null) throw new ArgumentNullException(nameof(items)); + var a = items as T[] ?? items.ToArray(); + SetRoot(CreateSubtree(a, 0, a.Length)); + } + + static Node CreateSubtree(T[] items, int l, int r) + { + if (r == l) return null; + if (r == l + 1) return new Node { Item = items[l] }; + + var m = (l + r) / 2; + var node = new Node { Item = items[m] }; + node.SetLeft(CreateSubtree(items, l, m)); + node.SetRight(CreateSubtree(items, m + 1, r)); + node.UpdateStates(); + return node; + } + + #endregion + + #region Get/Remove Items + + public IEnumerator GetEnumerator() => GetItems().GetEnumerator(); + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetItems().GetEnumerator(); + public IEnumerable GetItems() + { + for (var n = Root?.GetFirst(); n != null; n = n.GetNext()) + yield return n.Item; + } + + public IEnumerable GetItemsDescending() + { + for (var n = Root?.GetLast(); n != null; n = n.GetPrevious()) + yield return n.Item; + } + + #endregion + + #region Get/Remove Items (by Index) + + public IEnumerable GetItems(int startIndex, int endIndex) + { + if (startIndex < 0) startIndex = 0; + for (var n = Root?.GetAt(startIndex); n != null && startIndex < endIndex; n = n.GetNext(), ++startIndex) + yield return n.Item; + } + + public IEnumerable GetItemsDescending(int startIndex, int endIndex) + { + if (endIndex > Count) endIndex = Count; + for (var n = Root?.GetAt(--endIndex); n != null && startIndex <= endIndex; n = n.GetPrevious(), --endIndex) + yield return n.Item; + } + + public int RemoveItems(int startIndex, int endIndex) + { + if (startIndex < 0) startIndex = 0; + var nodes = new List>(); + for (var n = Root?.GetAt(startIndex); n != null && startIndex < endIndex; n = n.GetNext(), ++startIndex) + nodes.Add(n); + + for (int i = nodes.Count - 1; i >= 0; --i) RemoveNode(nodes[i]); + return nodes.Count; + } + + #endregion + + #region Get/Remove Node + + public Node GetFirst() => Root?.GetFirst(); + public Node GetLast() => Root?.GetLast(); + public Node RemoveFirst() => RemoveNode(GetFirst()); + public Node RemoveLast() => RemoveNode(GetLast()); + + #endregion + + #region Get/Remove Node (by Index) + + public Node GetAt(int index) => Root?.GetAt(index); + public Node RemoveAt(int index) => RemoveNode(GetAt(index)); + + public T this[int index] + { + get + { + var node = GetAt(index) ?? throw new ArgumentOutOfRangeException(nameof(index)); + return node.Item; + } + set + { + var node = GetAt(index) ?? throw new ArgumentOutOfRangeException(nameof(index)); + node.Item = value; + } + } + + #endregion + + #region Insert Item(s) + + public Node Insert(int index, T item) => InsertNode(index, item); + public Node Prepend(T item) => InsertNode(0, item); + public Node Add(T item) => InsertNode(Count, item); + + public int InsertItems(int index, IEnumerable items) + { + if (items == null) throw new ArgumentNullException(nameof(items)); + var c = Count; + foreach (var x in items) InsertNode(index++, x); + return Count - c; + } + public int PrependItems(IEnumerable items) => InsertItems(0, items); + public int AddItems(IEnumerable items) => InsertItems(Count, items); + + #endregion + + #region Protected Methods + + protected Node InsertNode(int index, T item) + { + if (index < 0) throw new ArgumentOutOfRangeException(nameof(index)); + if (index > Count) throw new ArgumentOutOfRangeException(nameof(index)); + + if (Root == null) + { + SetRoot(new Node { Item = item }); + return Root; + } + + Node node = Root, newNode; + while (true) + { + var d = index - node.LeftCount - 1; + if (d < 0) + { + if (node.Left == null) + { + node.SetLeft(newNode = new Node { Item = item }); + break; + } + node = node.Left; + } + else + { + if (node.Right == null) + { + node.SetRight(newNode = new Node { Item = item }); + break; + } + node = node.Right; + index = d; + } + } + + for (; node != null; node = node.Parent) + node = Balance(node); + return newNode; + } + + // The specified instance will be removed from the tree. + protected Node RemoveNode(Node node) + { + if (node == null) return null; + + Node dirty; + if (node.Left == null || node.Right == null) + { + UpdateChild(node, node.Left ?? node.Right); + dirty = node.Parent; + } + else + { + var node2 = dirty = node.Right.GetFirst(); + if (node2 != node.Right) + { + dirty = node2.Parent; + UpdateChild(node2, node2.Right); + node2.SetRight(node.Right); + } + node2.SetLeft(node.Left); + UpdateChild(node, node2); + } + dirty?.UpdateStates(true); + return node; + } + + #endregion + + #region Private Methods + + // Suppose node != null. + void UpdateChild(Node node, Node newNode) + { + var parent = node.Parent; + if (parent == null) SetRoot(newNode); + else if (parent.Left == node) parent.SetLeft(newNode); + else parent.SetRight(newNode); + } + + // Suppose t != null. + Node Balance(Node t) + { + var lrh = t.LeftHeight - t.RightHeight; + if (lrh > 2 || lrh == 2 && t.Left.LeftHeight >= t.Left.RightHeight) + { + t = RotateToRight(t); + } + else if (lrh < -2 || lrh == -2 && t.Right.LeftHeight <= t.Right.RightHeight) + { + t = RotateToLeft(t); + } + t.UpdateStates(); + return t; + } + + // Suppose t != null. + Node RotateToRight(Node t) + { + var p = t.Left; + UpdateChild(t, p); + t.SetLeft(p.Right); + p.SetRight(t); + t.UpdateStates(); + return p; + } + + // Suppose t != null. + Node RotateToLeft(Node t) + { + var p = t.Right; + UpdateChild(t, p); + t.SetRight(p.Left); + p.SetLeft(t); + t.UpdateStates(); + return p; + } + + #endregion + } +} diff --git a/source/WBTrees1/TreesLab/WBTrees/WBTree.cs b/source/WBTrees1/TreesLab/WBTrees/WBTree.cs index 4ffcfce..9fa360c 100644 --- a/source/WBTrees1/TreesLab/WBTrees/WBTree.cs +++ b/source/WBTrees1/TreesLab/WBTrees/WBTree.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; +// https://github.com/sakapon/WBTrees namespace TreesLab.WBTrees { [System.Diagnostics.DebuggerDisplay(@"\{{Item}\}")]