以下是普林斯顿大学课程资料中左倾红黑树实施的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);
}
}
}