left-leaning red-black tree
DO++に紹介してあったleft-leaning red-black treeという赤黒木の一種で実装が簡単なものを実装してみた.get,put,deleteを実装したところ156行となった.アルゴリズムイントロダクションの実装が疑似コードで150行程度なので*1.
また,JavaのTreeMapと挿入+検索+削除の合計の実行時間を比較したところオーダー的にはほぼ同程度の性能となった*2.
public class LLRB <Key extends Comparable<Key> , Value>{ private static final boolean RED = true; private static final boolean BLACK = false; private Node root; private class Node{ private Key key; private Value val; private Node left , right; private boolean color; Node(Key key , Value val , boolean color){ this.key = key; this.val = val; this.color = color; } } public Value get(Key key){ return get(root , key); } public void put(Key key , Value value){ root = put(root, key , value); root.color = BLACK; } public boolean isEmpty(){ return root == null; } public boolean containsKey(Key key){ return get(key) != null; } public void delete(Key key){ root = delete(root , key); if(root != null)root.color = BLACK; } private Value get(Node x , Key key){ while(x != null){ int cmp = key.compareTo(x.key); if(cmp == 0)return x.val; else if(cmp < 0)x = x.left; else x = x.right; } return null; } private Node put(Node h , Key key , Value value){ if(h == null)return new Node(key , value , RED); int cmp = key.compareTo(h.key); if(cmp == 0) h.val = value; else if(cmp < 0) h.left = put(h.left, key, value); else h.right = put(h.right , key , value); 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); return h; } private Node delete(Node h , Key key){ if(key.compareTo(h.key) < 0){ if(!isRed(h.left) && !isRed(h.left.left)) h = moveRedLeft(h); h.left = delete(h.left, key); }else{ if(isRed(h.left)) h = rotateRight(h); if(key.compareTo(h.key) == 0 && h.right == null) return null; if(!isRed(h.right) && !isRed(h.right.left)) h = moveRedRight(h); if(key.compareTo(h.key) == 0){ h.val = get(h.right , min(h.right)); h.key = min(h.right); h.right = deleteMin(h.right); }else h.right = delete(h.right , key); } return fixUp(h); } private Key min(Node h){ if(h.left == null)return h.key; return min(h.left); } 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 fixUp(h); } private Node moveRedLeft(Node h){ flipColors(h); if(isRed(h.right.left)){ h.right = rotateRight(h.right); h = rotateLeft(h); flipColors(h); } return h; } private Node moveRedRight(Node h){ flipColors(h); if(isRed(h.left.left)){ h = rotateRight(h); flipColors(h); } return h; } private Node fixUp(Node h){ 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); return h; } private Node rotateLeft(Node h){ Node x = h.right; h.right = x.left; x.left = h; x.color = h.color; h.color = RED; return x; } private Node rotateRight(Node h){ Node x = h.left; h.left = x.right; x.right = h; x.color = h.color; h.color = RED; return x; } private void flipColors(Node h){ h.color = !h.color; h.left.color = !h.left.color; h.right.color = !h.right.color; } private boolean isRed(Node h){ if(h == null)return false; return h.color == RED; } }