All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jlibs.core.util.LongTreeMap Maven / Gradle / Ivy

There is a newer version: 3.0.1
Show newest version
/**
 * Copyright 2015 Santhosh Kumar Tekuri
 *
 * The JLibs authors license this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

package jlibs.core.util;

import jlibs.core.lang.NotImplementedException;

import java.util.AbstractCollection;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 * Optimized TreeMap implementation whose keys are primitive long.
 * Originally copied from java.util.TreeMap and Optimized further
 *  
 * @author Santhosh Kumar T
 */
public final class LongTreeMap{
    private transient Entry root;
    private transient int size;

    // Red-black mechanics
    private static final boolean RED   = false;
    private static final boolean BLACK = true;

    public static final class Entry{
	    long key;
        public V value;
        Entry left;
        Entry right;
        Entry parent;
        boolean color; // RED

        Entry(long key, V value, Entry parent){
            this.key = key;
            this.value = value;
            this.parent = parent;
        }

        public long getKey(){
            return key;
        }

        public Entry next(){
            if(right!=null){
                Entry p = right;

                Entry q = p.left;
                while(q!=null){
                    p = q;
                    q = q.left;
                }
                return p;
            }else{
                Entry p = parent;
                Entry ch = this;
                while(p!=null && ch==p.right){
                    ch = p;
                    p = p.parent;
                }
                return p;
            }
        }

        @SuppressWarnings({"unchecked"})
        public boolean equals(Object o){
            if(o instanceof Entry){
                Entry e = (Entry)o;
                return valEquals(key, e.key) && valEquals(value, e.value);
            }else
                return false;
        }

        public int hashCode() {
            int keyHash = (int)(key ^ (key >>> 32));
            int valueHash = (value==null ? 0 : value.hashCode());
            return keyHash ^ valueHash;
        }

        public String toString() {
            return key + "=" + value;
        }
    }

    private static boolean valEquals(Object o1, Object o2){
        return o1==null ? o2==null : o1.equals(o2);
    }

    private static  boolean colorOf(Entry p){
        return p==null ? BLACK : p.color;
    }

    private static  void setColor(Entry p, boolean c){
        if(p!=null)
	        p.color = c;
    }

    private static  Entry leftOf(Entry p){
        return p==null ? null: p.left;
    }

    private static  Entry rightOf(Entry p){
        return p==null ? null: p.right;
    }

    public Entry firstEntry(){
        Entry p = root;
        if(p!=null){
            Entry q = p.left;
            while(q!=null){
                p = q;
                q = q.left;
            }
        }
        return p;
    }

    public Entry lastEntry(){
        Entry p = root;
        if(p!=null){
            Entry q = p.right;
            while(q!=null){
                p = q;
                q = q.right;
            }
        }
        return p;
    }

    private Entry rotateLeft(final Entry p){
        final Entry r = p.right;
        Entry rLeft = r.left;
        p.right = rLeft;
        if(rLeft!=null)
            rLeft.parent = p;
        Entry pParent = p.parent;
        r.parent = pParent;
        if(pParent==null)
            root = r;
        else if(pParent.left==p)
            pParent.left = r;
        else
            pParent.right = r;
        r.left = p;
        return p.parent = r;
    }

    private Entry rotateRight(final Entry p){
        Entry l = p.left;
        Entry lRight = l.right;
        p.left = lRight;
        if(lRight!=null)
            lRight.parent = p;
        Entry pParent = p.parent;
        l.parent = pParent;
        if(pParent==null)
            root = l;
        else if(pParent.right==p)
            pParent.right = l;
        else
            pParent.left = l;
        l.right = p;
        return p.parent = l;
    }

    private void fixAfterInsertion(Entry x){
        do{
            Entry px = x.parent;
            Entry ppx = px.parent;
            Entry ppxLeft = ppx!=null ? ppx.left : null;
            if(px==ppxLeft){
                if(ppx.right!=null && !ppx.right.color){ // !colorOf(ppxRight)
                    px.color = BLACK;
                    ppx.color = RED;
                    ppx.right.color = BLACK;
                    x = ppx;
                }else{
                    if(x==px.right){
                        x = px;
                        px = rotateLeft(x); // ppx wont change after this
                    }
                    px.color = BLACK;
                    ppx.color = RED;
                    rotateRight(ppx);
                }
            }else{
                if(ppxLeft!=null && !ppxLeft.color){ // !colorOf(ppxLeft)
                    px.color = BLACK;
                    ppx.color = RED;
                    ppxLeft.color = BLACK;
                    x = ppx;
                }else{
                    if(x==px.left){
                        x = px;
                        px = rotateRight(x);  // ppx wont change after this
                    }
                    px.color = BLACK;
                    if(ppx!=null){
                        ppx.color = RED;
                        rotateLeft(ppx);
                    }
                }
            }
        }while(x!=root && !x.parent.color);
        root.color = BLACK;
    }

    private void fixAfterDeletion(Entry x){
        while(x!=root && x.color){
            Entry px = x.parent;
            Entry pxLeft = px.left;
            if(x==pxLeft){
                Entry sib = px.right;

                if(sib!=null && !sib.color){ // !colorOf(sib)
                    sib.color = BLACK;
                    px.color = RED;
                    rotateLeft(px);
                    sib = rightOf(x.parent);
                }

                Entry sibLeft = sib!=null ? sib.left : null;
                Entry sibRight = sib!=null ? sib.right : null;
                boolean sibRightColor = sibRight==null || sibRight.color;
                if(colorOf(sibLeft) && sibRightColor){
                    setColor(sib, RED);
                    x = x.parent;
                }else{
                    if(sibRightColor){
                        if(sib!=null){
                            setColor(sibLeft, BLACK);
                            sib.color = RED;
                            rotateRight(sib);
                        }
                        sib = rightOf(x.parent);
                    }
                    px = x.parent;
                    if(sib!=null){
                        sib.color = colorOf(px);
                        setColor(sib.right, BLACK);
                    }
                    if(px!=null){
                        px.color = BLACK;
                        rotateLeft(px);
                    }
                    x = root;
                }
            }else{ // symmetric
                Entry sib = pxLeft;

                if(sib!=null && !sib.color){ // !colorOf(sib)
                    sib.color = BLACK;
                    px.color = RED;
                    rotateRight(px);
                    sib = leftOf(x.parent);
                }

                Entry sibLeft = sib!=null ? sib.left : null;
                Entry sibRight = sib!=null ? sib.right : null;
                boolean sibLeftColor = sibLeft==null || sibLeft.color;
                if(colorOf(sibRight) && sibLeftColor){
                    setColor(sib, RED);
                    x = x.parent;
                }else{
                    if(sibLeftColor){
                        if(sib!=null){
                            setColor(sibRight, BLACK);
                            sib.color = RED;
                            rotateLeft(sib);
                        }
                        sib = leftOf(x.parent);
                    }
                    px = x.parent;
                    if(sib!=null){
                        sib.color = colorOf(px);
                        setColor(sib.left, BLACK);
                    }
                    if(px!=null){
                        px.color = BLACK;
                        rotateRight(px);
                    }
                    x = root;
                }
            }
        }

        if(x!=null)
            x.color = BLACK;
    }

    public int size(){
        return size;
    }

    public boolean isEmpty(){
        return size==0;
    }

    public V put(long key, V value){
        assert value!=null;

        Entry t = root;
        if(t==null){
            root = new Entry(key, value, null);
            root.color = BLACK;
            size = 1;
            return null;
        }

        boolean cmp;
        Entry parent;
        do{
            parent = t;
            long tkey = t.key;
            if(keytkey){
                t = t.right;
                cmp = false;
            }else{
                V oldValue = t.value;
                t.value = value;
                return oldValue;
            }
        }while(t!=null);

        Entry e = new Entry(key, value, parent);
        if(cmp)
            parent.left = e;
        else
            parent.right = e;

        if(!parent.color)
            fixAfterInsertion(e);

        size++;
        return null;
    }

    public void deleteEntry(Entry p){
        size--;

        // If strictly internal, copy successor's element to p and then make p
        // point to successor.
        if(p.left!=null && p.right!=null){
            Entry s = p.next();
            p.key = s.key;
            p.value = s.value;
            p = s;
        } // p has 2 children

        // Start fixup at replacement node, if it exists.
        Entry replacement = (p.left!=null ? p.left : p.right);
        Entry pp = p.parent;

        if(replacement!=null){
            // Link replacement to parent
            replacement.parent = pp;
            if(pp==null)
                root = replacement;
            else if(p==pp.left)
                pp.left = replacement;
            else
                pp.right = replacement;

            // Null out links so they are OK to use by fixAfterDeletion.
            p.left = p.right = p.parent = null;

            // Fix replacement
            if(p.color)
                fixAfterDeletion(replacement);
        }else if(pp==null) // return if we are the only node.
            root = null;
        else{ //  No children. Use self as phantom replacement and unlink.
            if(p.color)
                fixAfterDeletion(p);

            pp = p.parent;
            if(pp!=null){
                if(p==pp.left)
                    pp.left = null;
                else if(p==pp.right)
                    pp.right = null;
                p.parent = null;
            }
        }
    }

    public V remove(long key){
        Entry p = getEntry(key);
        if(p==null)
            return null;

        V oldValue = p.value;
        deleteEntry(p);
        return oldValue;
    }

    public void clear(){
        size = 0;
        root = null;
    }

    public void putAll(LongTreeMap map){
        Entry q = null;
        Entry p = map.root;
        do{
            // traverse down left branches as far as possible
            while(p!=null){
                q = p;
                p = p.left;
            }
            if(q!=null){
                put(q.key, q.value);
                p = q.right;
            }
            while(q!=null && p==null){
                do{
                    p = q;
                    q = p.parent;
                }while(q!=null && q.right==p);
                if(q!=null){
                    put(q.key, q.value);
                    p = q.right;
                }
            }
        }while(q!=null);
    }

    public Entry getEntry(long key){
        Entry p = root;
        while(p!=null){
            if(keyp.key)
                p = p.right;
            else
                return p;
        }
        return null;
    }

    public V get(long key){
        Entry entry = getEntry(key);
        return entry!=null ? entry.value : null;
    }

    static final class ValuesIterator implements Iterator{
        Entry next;

        ValuesIterator(Entry firstEntry){
            next = firstEntry;
        }

        @Override
        public boolean hasNext(){
            return next!=null;
        }

        @Override
        public V next(){
            if(next==null)
                throw new NoSuchElementException();
            V value = next.value;
            next = next.next();
            return value;
        }

        @Override
        public void remove(){
            throw new NotImplementedException();
        }
    }

    class Values extends AbstractCollection{
        public Iterator iterator(){
            return new ValuesIterator(firstEntry());
        }

        public int size(){
            return size;
        }

        @Override
        public boolean contains(Object value){
            assert value!=null;

            Entry q = null;
            Entry p = root;
            do{
                // traverse down left branches as far as possible
                while(p!=null){
                    q = p;
                    p = p.left;
                }
                if(q!=null){
                    if(q.value.equals(value))
                        return true;
                    p = q.right;
                }
                while(q!=null && p==null){
                    do{
                        p = q;
                        q = p.parent;
                    }while(q!=null && q.right==p);
                    if(q!=null){
                        if(q.value.equals(value))
                            return true;
                        p = q.right;
                    }
                }
            }while(q!=null);

            return false;
        }

        @Override
        public Object[] toArray(){
            Object array[] = new Object[size];

            int i = 0;
            Entry q = null;
            Entry p = root;
            do{
                // traverse down left branches as far as possible
                while(p!=null){
                    q = p;
                    p = p.left;
                }
                if(q!=null){
                    array[i++] = q.value;
                    p = q.right;
                }
                while(q!=null && p==null){
                    do{
                        p = q;
                        q = p.parent;
                    }while(q!=null && q.right==p);
                    if(q!=null){
                        array[i++] = q.value;
                        p = q.right;
                    }
                }
            }while(q!=null);
            return array;
        }

        public void clear(){
            LongTreeMap.this.clear();
        }
    }

    private Values values;
    public Collection values(){
        if(values==null)
            return values = new Values();
    	return values;
    }

    public static void main(String[] args){
        LongTreeMap map = new LongTreeMap();
        for(int i=0; i<10; i++)
            map.put(1, "value");
        map.put(5, "five");
        map.put(3, "three");
        map.put(9, "nine");
        System.out.println(map.firstEntry());
        System.out.println(map.lastEntry());

        for(Entry entry=map.firstEntry(); entry!=null; entry=entry.next())
            System.out.println(entry);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy