RedBlackTreeFloat.java :  » Graphic-Library » ImageJ-Plugins-1.4.1 » net » sf » ij_plugins » filters » Java Open Source

Java Open Source » Graphic Library » ImageJ Plugins 1.4.1 
ImageJ Plugins 1.4.1 » net » sf » ij_plugins » filters » RedBlackTreeFloat.java
/*
 * Image/J Plugins
 * Copyright (C) 2002-2009 Jarek Sacha
 * Author's email: jsacha at users dot sourceforge dot net
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Latest release available at http://sourceforge.net/projects/ij-plugins/
 */
package net.sf.ij_plugins.filters;

import java.util.ArrayList;
import java.util.List;

/**
 * Implements a red-black tree.
 *
 * @author Jarek Sacha
 */
public final class RedBlackTreeFloat {
    private Node root;

    private static final int RED = 0;
    private static final int BLACK = 1;


    public RedBlackTreeFloat() {
        root = Node.NULL;
    }


    public void verify() throws IllegalStateException {

        // Rule 2
        if (root.color != BLACK) {
            throw new IllegalStateException("Root node is not black.");
        }

        // Rule 3
        if (Node.NULL.color != BLACK) {
            throw new IllegalStateException("NULL node is not black.");
        }

        verify(root);
    }


    private void verify(final Node node) {
        if (node == Node.NULL) {
            return;
        }

        // Rule 1
        if (!(node.color == RED || node.color == BLACK)) {
            throw new IllegalStateException("Node is neither red nor black: " + node.toString());
        }

        // Rule 4
        if (node.color == RED) {
            if (!(node.left.color == BLACK && node.right.color == BLACK)) {
                throw new IllegalStateException("Red node must have both children black: " + node.toString());
            }
        }

        // FIXME: Rule 5
        final List<Node> leaves = new ArrayList<Node>();
        findLeaves(node, leaves);
        if (leaves.size() > 0) {
            final int blackInPath = countBlackToParent(leaves.get(0), node);
            for (int i = 0; i < leaves.size(); i++) {
                Node c = leaves.get(i);
                final int n = countBlackToParent(c, node);
                if (n != blackInPath) {
                    throw new IllegalStateException("Black path mismatch in sub-tree: "
                            + node.toString() + ". Path 0=" + blackInPath + ", path " + i + "=" + n + ".");
                }
            }
        }

        // FIXME: Rule 6 - size of the sub-tree agrees wit node.size field.

        // Verify children
        verify(node.left);
        verify(node.left);
    }


    private int countBlackToParent(Node leaf, Node node) {

        if (leaf == Node.NULL) {
            throw new IllegalArgumentException("Leaf node cannot be NULL");
        }

        if (leaf == node) {
            return 0;
        }

        final int r = leaf.color == BLACK ? 1 : 0;

        return r + countBlackToParent(leaf.parent, node);
    }


    private void findLeaves(final Node node, final List<Node> leaves) {
        if (node == Node.NULL) {
            return;
        }

        if (node.right == Node.NULL && node.left == Node.NULL) {
            leaves.add(node);
            return;
        }

        findLeaves(node.left, leaves);
        findLeaves(node.right, leaves);
    }


    /**
     * Remove all nodes from the tree.
     */
    public void clear() {
        // Remove one by one to remove circular references and enable garbage collection.
        Node x = root;
        while (x != Node.NULL) {
            remove(x);
            x = root;
        }
    }


    public int size() {
        return root.size;
    }


    public void insert(final float key) {

        Node y = Node.NULL;
        Node x = root;
        final Node z = new Node(key);

        // Find insertion point
        while (x != Node.NULL) {
            ++x.size;
            y = x;
            x = key < x.key ? x.left : x.right;
        }
        // Insert the new node
        z.parent = y;
        if (y == Node.NULL) {
            root = z;
        } else {
            if (key < y.key) {
                y.left = z;
            } else {
                y.right = z;
            }
        }

        insertFixup(z);
    }


    public boolean remove(final float key) {
        return remove(find(root, key));
    }


    private boolean remove(final Node node) {
        final Node z = node;
        if (z == Node.NULL) {
            return false;
        }

        final Node y = z.left == Node.NULL || z.right == Node.NULL
                ? z
                : successor(z);

        final Node x = y.left != Node.NULL
                ? y.left
                : y.right;

        //        if (x != Node.NULL) {
        x.parent = y.parent;
        //        }

        if (y.parent == Node.NULL) {
            root = x;
        } else {
            if (y == y.parent.left) {
                y.parent.left = x;
            } else {
                y.parent.right = x;
            }
        }

        if (y != z) {
            z.key = y.key;
        }

        // Update count
        Node v = y.parent;
        while (v != Node.NULL) {
            --v.size;
            v = v.parent;
        }

        if (y.color == BLACK) {
            deleteFixup(x);
        }

        y.clear();

        return true;

    }


    /**
     * Select <code>i</code>-th key in the tree (key with rank <code>i</code>).
     *
     * @param i rank of the key to elect.
     * @return value of key with rank <code>i</code>.
     */
    public float select(final int i) {
        if (i < 1) {
            throw new IllegalArgumentException("Rank argument i must be larger than zero.");
        }
        Node n = select(root, i);
        if (n == Node.NULL) {
            throw new IllegalArgumentException("Input argument rank is too large.");
        }

        return n.key;
    }


    private Node select(final Node x, final int i) {
        int r = x.left.size + 1;
        if (i == r) {
            return x;
        } else {
            return i < r ? select(x.left, i) : select(x.right, i - r);
        }
    }


    /**
     * Test if tree contains <code>key</code>.
     *
     * @param key the key to search for.
     * @return the matching key or null if not found.
     */
    public boolean contains(final float key) {
        return find(root, key) != Node.NULL;
    }


    /**
     * Test if the tree is logically empty.
     *
     * @return true if empty, false otherwise.
     */
    public boolean isEmpty() {
        return root == Node.NULL;
    }


    public void printTree() {
        printTree(root);
    }


    private void insertFixup(final Node node) {
        Node z = node;
        while (z.parent.color == RED) {
            if (z.parent == z.parent.parent.left) {
                final Node y = z.parent.parent.right;
                if (y.color == RED) {
                    z.parent.color = BLACK;
                    y.color = BLACK;
                    z.parent.parent.color = RED;
                    z = z.parent.parent;
                } else {
                    if (z == z.parent.right) {
                        z = z.parent;
                        leftRotate(z);
                    }
                    z.parent.color = BLACK;
                    z.parent.parent.color = RED;
                    rightRotate(z.parent.parent);
                }
            } else {
                final Node y = z.parent.parent.left;
                if (y.color == RED) {
                    z.parent.color = BLACK;
                    y.color = BLACK;
                    z.parent.parent.color = RED;
                    z = z.parent.parent;
                } else {
                    if (z == z.parent.left) {
                        z = z.parent;
                        rightRotate(z);
                    }
                    z.parent.color = BLACK;
                    z.parent.parent.color = RED;
                    leftRotate(z.parent.parent);
                }
            }
        }
        root.color = BLACK;
    }


    private void rightRotate(final Node x) {
        final Node y = x.left;
        x.left = y.right;

        if (y.right != Node.NULL) {
            y.right.parent = x;
        }

        y.parent = x.parent;
        if (x.parent == Node.NULL) {
            root = y;
        } else {
            if (x == x.parent.right) {
                x.parent.right = y;
            } else {
                x.parent.left = y;
            }
        }

        y.right = x;
        x.parent = y;
        y.size = x.size;
        x.size = x.left.size + x.right.size + 1;
    }

    private void leftRotate(final Node x) {
        final Node y = x.right;
        x.right = y.left;

        if (y.left != Node.NULL) {
            y.left.parent = x;
        }

        y.parent = x.parent;
        if (x.parent == Node.NULL) {
            root = y;
        } else {
            if (x == x.parent.left) {
                x.parent.left = y;
            } else {
                x.parent.right = y;
            }
        }

        y.left = x;
        x.parent = y;
        y.size = x.size;
        x.size = x.left.size + x.right.size + 1;
    }


    /**
     * Finds node with a smallest key greater than key of given <code>node</code>.
     *
     * @param node node to find successor for.
     * @return node that is successor of the input node.
     */
    private Node successor(final Node node) {
        Node x = node;
        if (x.right != Node.NULL) {
            return treeMinimum(x.right);
        }
        Node y = x.parent;
        while (y != Node.NULL && x == y.right) {
            x = y;
            y = y.parent;
        }

        return y;
    }


    private Node treeMinimum(final Node node) {
        Node x = node;
        while (x.left != Node.NULL) {
            x = x.left;
        }

        return x;
    }


    private void deleteFixup(final Node node) {
        Node x = node;
        while (x != root && x.color == BLACK) {
            if (x == x.parent.left) {
                Node w = x.parent.right;
                if (w.color == RED) {
                    w.color = BLACK;
                    x.parent.color = RED;
                    leftRotate(x.parent);
                    w = x.parent.right;
                }
                if (w.left.color == BLACK && w.right.color == BLACK) {
                    w.color = RED;
                    x = x.parent;
                } else {
                    if (w.right.color == BLACK) {
                        w.left.color = BLACK;
                        w.color = RED;
                        rightRotate(w);
                        w = x.parent.right;
                    }
                    w.color = x.parent.color;
                    x.parent.color = BLACK;
                    w.right.color = BLACK;
                    leftRotate(x.parent);
                    x = root;
                }
            } else {
                Node w = x.parent.left;
                if (w.color == RED) {
                    w.color = BLACK;
                    x.parent.color = RED;
                    rightRotate(x.parent);
                    w = x.parent.left;
                }
                if (w.right.color == BLACK && w.left.color == BLACK) {
                    w.color = RED;
                    x = x.parent;
                } else {
                    if (w.left.color == BLACK) {
                        w.right.color = BLACK;
                        w.color = RED;
                        leftRotate(w);
                        w = x.parent.left;
                    }
                    w.color = x.parent.color;
                    x.parent.color = BLACK;
                    w.left.color = BLACK;
                    rightRotate(x.parent);
                    x = root;
                }
            }
        }
        x.color = BLACK;
    }


    private Node find(final Node node, final float key) {
        Node x = node;
        //        if (x == Node.NULL || key == x.key) {
        //            return x;
        //        }
        //
        //        return (key < x.key) ? find(x.left, key) : find(x.right, key);

        while (x != Node.NULL && key != x.key) {
            x = (key < x.key) ? x.left : x.right;
        }

        return x;
    }


    private void printTree(final Node node) {
        if (node != Node.NULL) {
            printTree(node.left);
            System.out.println(node);
            printTree(node.right);
        }
    }


    /**
     * Tree node.
     */
    private static final class Node {
        public static final Node NULL;

        /**
         * Data stored by the node
         */
        float key;
        /**
         * Left child
         */
        Node left;
        /**
         * Right child
         */
        Node right;
        Node parent;
        int color;
        int size;


        static {
            NULL = new Node(Float.NaN);
            NULL.key = Float.NaN;
            NULL.left = NULL;
            NULL.right = NULL;
            NULL.parent = NULL;
            NULL.color = BLACK;
            NULL.size = 0;
        }


        Node(float element) {
            this.key = element;
            this.left = NULL;
            this.right = NULL;
            this.parent = NULL;
            this.color = RedBlackTreeFloat.RED;
            this.size = 1;
        }


        @Override
        public String toString() {
            final StringBuilder builder = new StringBuilder();
            builder.append("key: ");
            builder.append(key);
            builder.append(", size: ");
            builder.append(size);
            builder.append(", color: ");
            builder.append(color == RED ? "RED" : color == BLACK ? "BLACK" : "?");
            return builder.toString();
        }


        public void clear() {
            if (this != NULL) {
                this.key = Float.NaN;
                this.left = NULL;
                this.right = NULL;
                this.color = RedBlackTreeFloat.RED;
                this.parent = NULL;
                this.size = 1;
            }
        }


        static boolean verifyNull() {
            assert Float.isNaN(NULL.key);
            assert NULL.left == NULL;
            assert NULL.right == NULL;
            assert NULL.parent == NULL;
            assert NULL.color == BLACK;
            assert NULL.size == 0;
            return true;
        }
    }
}


java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.