C# - 支持红黑树中的非密集排名

时间:2016-07-18 15:45:06

标签: c# algorithm binary-search-tree ranking red-black-tree

以下是普林斯顿大学课程资料中左倾红黑树实施的C#改编版。原始评论已被剥离以节省视觉空间。树使用HashSet在单个节点中存储多个值,以便跟踪来自不同源的重复值。

现在,Rank()密集。我们使用的是SQL Server术语,所以我们所说的密集是指给定值[1,1,2,3],值为1的密集排名将排名第1,2排名第2,3排名第3 。非密集等级将产生:1作为第1,2作为第3,3作为第4。换句话说,重复数据将计入正在进行的排名。

我们如何实现这一目标?

我已经为排名添加了boolean dense参数,因此我们可以选择执行密集排名。下面给出的实现被打破,并且不能按预期工作。

using System;
using System.Collections.Generic;

namespace Example
{
    public class RankTree<TKey, TValue>
    {

        private static bool RED = true;
        private static bool BLACK = false;
        private Node root;
        private IComparer<TKey> comparer;

        private class Node
        {

            public TKey key;
            public HashSet<TValue> values;
            public Node left;
            public Node right;
            public bool color;
            public int size;
            public int duplicates = 0;

            public Node(TKey key, bool color, int size)
            {
                this.key = key;
                this.values = new HashSet<TValue>();
                this.color = color;
                this.size = size;
            }

            public void AddValue(TValue val)
            {
                this.values.Add(val);
            }

            public void RemoveValue(TValue val)
            {
                this.values.Remove(val);
            }
        }

        public RankTree(IComparer<TKey> comparer) {
            this.comparer = comparer;
        }

        //  is node x red; false if x is null ?
        private bool IsRed(Node x)
        {
            if (x == null) return false;
            return (x.color == RED);
        }

        public int Duplicates() {
            return Duplicates(this.root);
        }
        private int Duplicates(Node x)
        {
            if (x == null) return 0;
            return x.duplicates;
        }

        //  number of node in subtree rooted at x; 0 if x is null
        private int Size(Node x)
        {
            if (x == null) return 0;
            return x.size;
        }

        public int Size()
        {
            return Size(this.root);
        }

        public bool IsEmpty()
        {
            return this.root == null;
        }

        public HashSet<TValue> Get(TKey key)
        {
            if (key == null) throw new NullReferenceException("argument to get() is null");
            return Get(this.root, key);
        }

        //  value associated with the given key in subtree rooted at x; null if no such key
        private HashSet<TValue> Get(Node x, TKey key)
        {
            while (x != null)
            {
                int cmp = comparer.Compare(key, x.key);
                if (cmp < 0) x = x.left;
                else if (cmp > 0) x = x.right;
                else return x.values;
            }

            return null;
        }

        public bool Contains(TKey key)
        {
            return Get(key) != null;
        }

        public void Put(TKey key, TValue val)
        {
            if (key == null) throw new NullReferenceException("first argument to put() is null");

            if (val == null)
            {
                Delete(key, val);
                return;
            }

            this.root = Put(this.root, key, val);
            this.root.color = BLACK;
            //  assert check();
        }

        //  insert the key-value pair in the subtree rooted at h
        private Node Put(Node h, TKey key, TValue val)
        {
            if (h == null)
            {
                Node node = new Node(key, RED, 1);
                node.AddValue(val);
                return node;
            }

            int cmp = comparer.Compare(key, h.key);
            if (cmp < 0)
            {
                h.left = Put(h.left, key, val);
            }
            else if (cmp > 0)
            {
                h.right = Put(h.right, key, val);
            }
            else {
                h.AddValue(val);
            }

            //  fix-up any right-leaning links
            if (IsRed(h.right) && !IsRed(h.left)) h = RotateLeft(h);
            if (IsRed(h.left) && IsRed(h.left.left)) h = RotateRight(h);
            if (IsRed(h.left) && IsRed(h.right)) FlipColors(h);

            h.size = Size(h.left) + Size(h.right) + 1;
            h.duplicates = Duplicates(h.left) + Duplicates(h.right) + h.values.Count - 1;
            return h;
        }

        public void DeleteMin()
        {
            if (IsEmpty()) return;

            if (!IsRed(this.root.left) && !IsRed(this.root.right))
            {
                this.root.color = RED;
            }

            this.root = DeleteMin(this.root);
            if (!IsEmpty())
            {
                this.root.color = BLACK;
            }

            //  assert check();
        }

        //  delete the key-value pair with the minimum key rooted at h
        private Node DeleteMin(Node h)
        {
            if (h.left == null) return null;

            if (!IsRed(h.left) && !IsRed(h.left.left)) h = MoveRedLeft(h);

            h.left = DeleteMin(h.left);
            return Balance(h);
        }

        public void DeleteMax()
        {
            if (IsEmpty()) return;

            if (!IsRed(this.root.left) && !IsRed(this.root.right)) this.root.color = RED;

            this.root = DeleteMax(this.root);
            if (!IsEmpty())
            {
                this.root.color = BLACK;
            }

            //  assert check();
        }

        //  delete the key-value pair with the maximum key rooted at h
        private Node DeleteMax(Node h)
        {
            if (IsRed(h.left)) h = RotateRight(h);
            if (h.right == null) return null;

            if (!IsRed(h.right) && !IsRed(h.right.left)) h = MoveRedRight(h);

            h.right = DeleteMax(h.right);
            return Balance(h);
        }

        public void Delete(TKey key, TValue val)
        {
            if (key == null) throw new NullReferenceException("argument to delete() is null");

            if (!Contains(key)) return;

            //  if both children of root are black, set root to red
            if (!IsRed(this.root.left) && !IsRed(this.root.right)) this.root.color = RED;

            this.root = Delete(this.root, key, val);
            if (!IsEmpty()) this.root.color = BLACK;

            //  assert check();
        }

        //  delete the key-value pair with the given key rooted at h
        private Node Delete(Node h, TKey key, TValue val)
        {
            //  assert get(h, key) != null;
            if (comparer.Compare(key, h.key) < 0)
            {
                if (!IsRed(h.left) && !IsRed(h.left.left)) h = MoveRedLeft(h);
                h.left = Delete(h.left, key, val);
            }
            else {
                if (IsRed(h.left)) h = RotateRight(h);
                if (comparer.Compare(key, h.key) == 0 && h.right == null) return null;
                if (!IsRed(h.right) && !IsRed(h.right.left)) h = MoveRedRight(h);

                if (comparer.Compare(key, h.key) == 0)
                {
                    Node x = Min(h.right);
                    h.key = x.key;
                    h.values = x.values; // FIXME: Potentially wrong?
                                        //  h.val = get(h.right, min(h.right).key);
                                        //  h.key = min(h.right).key;
                    h.right = DeleteMin(h.right);
                }
                else {
                    h.right = Delete(h.right, key, val);
                }
            }

            return Balance(h);
        }

        //  make a left-leaning link lean to the right
        private Node RotateRight(Node h)
        {
            //  assert (h != null) && isRed(h.left);
            Node x = h.left;
            h.left = x.right;
            x.right = h;
            x.color = x.right.color;
            x.right.color = RED;
            x.size = h.size;
            x.duplicates = h.duplicates;
            h.size = Size(h.left) + Size(h.right) + 1;
            h.duplicates = Duplicates(h.left) + Duplicates(h.right) + h.values.Count - 1;
            return x;
        }

        //  make a right-leaning link lean to the left
        private Node RotateLeft(Node h)
        {
            //  assert (h != null) && isRed(h.right);
            Node x = h.right;
            h.right = x.left;
            x.left = h;
            x.color = x.left.color;
            x.left.color = RED;
            x.size = h.size;
            x.duplicates = h.duplicates;
            h.size = Size(h.left) + Size(h.right) + 1;
            h.duplicates = Duplicates(h.left) + Duplicates(h.right) + h.values.Count - 1;
            return x;
        }

        //  flip the colors of a node and its two children
        private void FlipColors(Node h)
        {
            //  h must have opposite color of its two children
            //  assert (h != null) && (h.left != null) && (h.right != null);
            //  assert (!isRed(h) &&  isRed(h.left) &&  isRed(h.right))
            //     || (isRed(h)  && !isRed(h.left) && !isRed(h.right));
            h.color = !h.color;
            h.left.color = !h.left.color;
            h.right.color = !h.right.color;
        }

        //  Assuming that h is red and both h.left and h.left.left
        //  are black, make h.left or one of its children red.
        private Node MoveRedLeft(Node h)
        {
            //  assert (h != null);
            //  assert isRed(h) && !isRed(h.left) && !isRed(h.left.left);
            FlipColors(h);
            if (IsRed(h.right.left))
            {
                h.right = RotateRight(h.right);
                h = RotateLeft(h);
                FlipColors(h);
            }

            return h;
        }

        //  Assuming that h is red and both h.right and h.right.left
        //  are black, make h.right or one of its children red.
        private Node MoveRedRight(Node h)
        {
            //  assert (h != null);
            //  assert isRed(h) && !isRed(h.right) && !isRed(h.right.left);
            FlipColors(h);
            if (IsRed(h.left.left))
            {
                h = RotateRight(h);
                FlipColors(h);
            }

            return h;
        }

        //  restore red-black tree invariant
        private Node Balance(Node h)
        {
            //  assert (h != null);
            if (IsRed(h.right)) h = RotateLeft(h);
            if (IsRed(h.left) && IsRed(h.left.left)) h = RotateRight(h);
            if (IsRed(h.left) && IsRed(h.right)) FlipColors(h);

            h.size = Size(h.left) + Size(h.right) + 1;
            h.duplicates = Duplicates(h.left) + Duplicates(h.right) + h.values.Count - 1;
            return h;
        }

        public int Height()
        {
            return Height(this.root);
        }

        private int Height(Node x)
        {
            if (x == null) return -1;
            return 1 + Math.Max(Height(x.left), Height(x.right));
        }

        public TKey Min()
        {
            if (IsEmpty()) return default(TKey);
            return Min(this.root).key;
        }

        //  the smallest key in subtree rooted at x; null if no such key
        private Node Min(Node x)
        {
            //  assert x != null;
            if (x.left == null) return x;
            else return Min(x.left);
        }

        public TKey Max()
        {
            if (IsEmpty()) return default(TKey);
            return Max(this.root).key;
        }

        //  the largest key in the subtree rooted at x; null if no such key
        private Node Max(Node x)
        {
            //  assert x != null;
            if (x.right == null) return x;
            else return Max(x.right);
        }

        public TKey Floor(TKey key)
        {
            if (key == null) throw new NullReferenceException("argument to floor() is null");

            if (IsEmpty()) return default(TKey);

            Node x = Floor(this.root, key);
            if (x == null) return default(TKey);
            else return x.key;
        }

        //  the largest key in the subtree rooted at x less than or equal to the given key
        private Node Floor(Node x, TKey key)
        {
            if (x == null) return null;

            int cmp = comparer.Compare(key, x.key);
            if (cmp == 0) return x;

            if (cmp < 0) return Floor(x.left, key);

            Node t = Floor(x.right, key);
            if (t != null) return t;
            else return x;
        }

        public TKey Ceiling(TKey key)
        {
            if (key == null) throw new NullReferenceException("argument to ceiling() is null");

            if (IsEmpty()) return default(TKey);

            Node x = Ceiling(this.root, key);
            if (x == null) return default(TKey);
            else return x.key;
        }

        //  the smallest key in the subtree rooted at x greater than or equal to the given key
        private Node Ceiling(Node x, TKey key)
        {
            if (x == null) return null;

            int cmp = comparer.Compare(key, x.key);
            if (cmp == 0) return x;

            if (cmp > 0) return Ceiling(x.right, key);

            Node t = Ceiling(x.left, key);
            if (t != null) return t;
            else return x;
        }

        public TKey Select(int k)
        {
            if (k < 0 || k >= Size()) throw new ArgumentException();

            Node x = Select(this.root, k);
            return x.key;
        }

        //  the key of rank k in the subtree rooted at x
        private Node Select(Node x, int k)
        {
            //  assert x != null;
            //  assert k >= 0 && k < size(x);
            int t = Size(x.left);
            if (t > k) return Select(x.left, k);
            else if (t < k) return Select(x.right, (k - (t - 1)));
            else return x;
        }

        public int Rank(TKey key)
        {
            if (key == null) throw new NullReferenceException("argument to rank() is null");
            return Rank(key, true);
        }

        public int Rank(TKey key, bool dense)
        {
            if (key == null) throw new NullReferenceException("argument to rank() is null");
            return Rank(key, this.root, dense);
        }

        //  number of keys less than key in the subtree rooted at x
        private int Rank(TKey key, Node x, bool dense)
        {
            if (x == null) return 0;

            int cmp = comparer.Compare(key, x.key);
            //         StdOut.println(x.key + ": " + duplicates(x.left));
            if (cmp < 0) return Rank(key, x.left, dense);
            else if (cmp > 0) return 1 + Size(x.left) + (dense ? 0 : Duplicates(x.left)) + Rank(key, x.right, dense);
            else return Size(x.left) + (dense ? 0 : Duplicates(x.left));
        }

        public IEnumerable<TKey> Keys()
        {
            if (IsEmpty()) return new Queue<TKey>();

            return Keys(Min(), Max());
        }

        public IEnumerable<TKey> Keys(TKey lo, TKey hi)
        {
            if (lo == null) throw new NullReferenceException("first argument to keys() is null");
            if (hi == null) throw new NullReferenceException("second argument to keys() is null");

            Queue<TKey> queue = new Queue<TKey>();
            //  if (isEmpty() || lo.compareTo(hi) > 0) return queue;
            Keys(this.root, queue, lo, hi);
            return queue;
        }

        //  add the keys between lo and hi in the subtree rooted at x
        //  to the queue
        private void Keys(Node x, Queue<TKey> queue, TKey lo, TKey hi)
        {
            if (x == null) return;

            int cmplo = comparer.Compare(lo, x.key);
            int cmphi = comparer.Compare(hi, x.key);
            if (cmplo < 0)
            {
                Keys(x.left, queue, lo, hi);
            }

            if (cmplo <= 0 && cmphi >= 0)
            {
                queue.Enqueue(x.key);
            }

            if (cmphi > 0)
            {
                Keys(x.right, queue, lo, hi);
            }
        }

        public int Size(TKey lo, TKey hi)
        {
            if (lo == null) throw new NullReferenceException("first argument to size() is null");
            if (hi == null) throw new NullReferenceException("second argument to size() is null");

            if (comparer.Compare(lo, hi) > 0) return 0;
            if (Contains(hi)) return Rank(hi) - Rank(lo) + 1;
            else return Rank(hi) - Rank(lo);
        }
    }
}

0 个答案:

没有答案