Ranides Atterwim 11 gadi atpakaļ
vecāks
revīzija
77242d74aa

+ 381 - 63
assira/src/main/java/net/ranides/assira/collection/maps/ASortedMap.java

@@ -9,10 +9,13 @@ package net.ranides.assira.collection.maps;
 import java.util.Collection;
 import java.util.Comparator;
 import java.util.Iterator;
+import java.util.ListIterator;
 import java.util.Map;
 import java.util.SortedMap;
 import net.ranides.assira.collection.ACollection;
+import net.ranides.assira.collection.iterators.AListIterator;
 import net.ranides.assira.collection.sets.ASortedSet;
+import net.ranides.assira.generic.ValueUtils;
 
 /**
  * An abstract class providing basic methods for sorted maps.
@@ -20,58 +23,131 @@ import net.ranides.assira.collection.sets.ASortedSet;
 public abstract class ASortedMap<K, V> extends AMap<K, V> implements SortedMap<K, V> {
 
     private static final long serialVersionUID = 2L;
-
-    protected ASortedMap() {
-        // do nothing
+    
+    /**
+     * This map's ecmp, as provided in the constructor.
+     */
+    private final Comparator<? super K> acmp;
+    
+    protected transient boolean modified;
+    
+    protected ASortedMap(Comparator<? super K> comparator) {
+        this.acmp = comparator;
     }
+    
+    /**
+     * Returns the entry corresponding end the given key, if it is in the tree;
+ <code>null</code>, otherwise.
+     *
+     * @param key the key end search for.
+     * @return the corresponding entry, or <code>null</code> if no entry with
+     * the given key exists.
+     */
+    protected abstract Entry<K, V> findEntry(K key);
 
+    /**
+     * Locates key key.
+     *
+     * @param k a key.
+     * @return the last entry on a search for the given key; this will be the
+     * given key, if it present; otherwise, it will be either the smallest
+     * greater key or the greatest smaller key.
+     */
+    protected abstract Entry<K, V> locateEntry(K key);
+    
+    protected abstract Entry<K, V> firstEntry();
+
+    protected abstract Entry<K, V> lastEntry();
+    
+    protected abstract ListIterator<Entry<K, V>> entryIterator();
+    
+    protected abstract ListIterator<Entry<K, V>> entryIterator(K begin);
+    
+    protected abstract ASortedMap<K, V> submap(K begin, boolean bottom, K end, boolean top);
+    
+    protected final int compare(K key1, K key2) {
+        return ValueUtils.cmp(acmp, key1, key2);
+    }
+    
+    protected final K lower(K key1, K key2) {
+        return ValueUtils.lower(acmp, key1, key2);
+    }
+    
+    protected final K higher(K key1, K key2) {
+        return ValueUtils.higher(acmp, key1, key2);
+    }
+    
+    @Override
+    public final Comparator<? super K> comparator() {
+        return acmp;
+    }
+    
+    @Override
+    public final ASortedSet<Entry<K, V>> entrySet() {
+        return new EntrySet();
+    }
+    
     @Override
-    public ASortedSet<K> keySet() {
+    public final ASortedSet<K> keySet() {
         return new KeySet();
     }
 
     @Override
-    public Collection<V> values() {
+    public final Collection<V> values() {
         return new ValuesCollection();
     }
-
     
-    /**
-     * Returns a sorted-set view of the mappings contained in this
-     * map. Note that this specification strengthens the one given in the
-     * corresponding type-specific unsorted map.
-     *
-     * @return sorted-set view of the mappings contained in this map.
-     * @see #entrySet()
-     */
     @Override
-    public abstract ASortedSet<Entry<K, V>> entrySet();
+    public final K firstKey() {
+        return firstEntry().getKey();
+    }
 
-    /**
-     * Returns the comparator associated with this sorted set, or null if it
-     * uses its keys' natural ordering.
-     *
-     * <P>Note that this specification strengthens the one given in
-     * {@link SortedMap#comparator()}.
-     *
-     * @see SortedMap#comparator()
-     */
     @Override
-    public abstract Comparator<? super K> comparator();
+    public final K lastKey() {
+        return lastEntry().getKey();
+    }
+    
+    @SuppressWarnings("unchecked")
+    @Override
+    public final boolean containsKey(Object k) {
+        return findEntry((K) k) != null;
+    }
+    
+    @Override
+    public boolean containsValue(Object value) {
+        final Iterator<Entry<K,V>> i = entryIterator();
+        int j = size();
+        while (j-- != 0) {
+            Entry<K,V> entry = i.next();
+            if( ValueUtils.equals(value, entry.getValue())) {
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    @SuppressWarnings("unchecked")
+    @Override
+    public final V get(Object k) {
+        Entry<K, V> entry = findEntry((K) k);
+        return entry == null ? defRetValue : entry.getValue();
+    }
 
     @Override
-    public abstract ASortedMap<K, V> subMap(K fromKey, K toKey);
+    public ASortedMap<K, V> headMap(K to) {
+        return submap(null, true, to, false);
+    }
 
     @Override
-    public abstract ASortedMap<K, V> headMap(K toKey);
+    public ASortedMap<K, V> tailMap(K from) {
+        return submap(from, false, null, true);
+    }
 
     @Override
-    public abstract ASortedMap<K, V> tailMap(K fromKey);
-    
-    
-    /**
-     * A wrapper exhibiting the keys of a map.
-     */
+    public ASortedMap<K, V> subMap(K from, K to) {
+        return submap(from, false, to, false);
+    }
+            
     protected class KeySet extends ASortedSet<K> {
 
         @Override
@@ -122,37 +198,31 @@ public abstract class ASortedMap<K, V> extends AMap<K, V> implements SortedMap<K
 
         @Override
         public Iterator<K> iterator(K from) {
-            return new KeySetIterator<>(entrySet().iterator(new BasicEntry<K, V>(from, null)));
+            return new KeySetIterator<>(entryIterator(from));
         }
 
         @Override
         public Iterator<K> iterator() {
-            return new KeySetIterator<>(entrySet().iterator());
+            return new KeySetIterator<>(entryIterator());
         }
     }
 
-    /**
-     * A wrapper exhibiting a map iterator as an iterator on keys.
-     *
-     * <P>To provide an iterator on keys, just create an instance of this class
-     * using the corresponding iterator on entries.
-     */
     protected static class KeySetIterator<K, V> implements Iterator<K> {
 
-        private final Iterator<Map.Entry<K, V>> riv;
+        private final Iterator<Map.Entry<K, V>> adapter;
 
         public KeySetIterator(Iterator<Map.Entry<K, V>> riv) {
-            this.riv = riv;
+            this.adapter = riv;
         }
 
         @Override
         public K next() {
-            return riv.next().getKey();
+            return adapter.next().getKey();
         }
 
         @Override
         public boolean hasNext() {
-            return riv.hasNext();
+            return adapter.hasNext();
         }
 
         @Override
@@ -161,14 +231,11 @@ public abstract class ASortedMap<K, V> extends AMap<K, V> implements SortedMap<K
         }
     }
 
-    /**
-     * A wrapper exhibiting the values of a map.
-     */
     protected class ValuesCollection extends ACollection<V> {
 
         @Override
         public Iterator<V> iterator() {
-            return new ValuesIterator<>(entrySet().iterator());
+            return new ValuesIterator<>(entryIterator());
         }
 
         @Override
@@ -188,35 +255,286 @@ public abstract class ASortedMap<K, V> extends AMap<K, V> implements SortedMap<K
         }
     }
 
-    /**
-     * A wrapper exhibiting a map iterator as an iterator on values.
-     *
-     * <P>To provide an iterator on values, just create an instance of this
-     * class using the corresponding iterator on entries.
-     */
-    protected static class ValuesIterator<K, V> implements Iterator<V> {
+    protected static class ValuesIterator<K, V> extends AListIterator<V> {
 
-        private final Iterator<Map.Entry<K, V>> riv;
+        private final ListIterator<Map.Entry<K, V>> adapter;
 
-        public ValuesIterator(Iterator<Map.Entry<K, V>> riv) {
-            this.riv = riv;
+        public ValuesIterator(ListIterator<Map.Entry<K, V>> riv) {
+            this.adapter = riv;
         }
 
         @Override
         public V next() {
-            return riv.next().getValue();
+            return adapter.next().getValue();
+        }
+        
+        @Override
+        public V previous() {
+            return adapter.previous().getValue();
         }
 
         @Override
         public boolean hasNext() {
-            return riv.hasNext();
+            return adapter.hasNext();
         }
 
         @Override
-        public void remove() {
-            throw new UnsupportedOperationException();
+        public boolean hasPrevious() {
+            return adapter.hasPrevious();
+        }
+
+        @Override
+        public int nextIndex() {
+            return adapter.nextIndex();
+        }
+
+        @Override
+        public int previousIndex() {
+            return adapter.previousIndex();
+        }
+        
+    }
+    
+    protected class EntrySet extends ASortedSet<Entry<K, V>> {
+
+        // @todo (assira # 2) cmp / move end parent
+        
+        final Comparator<? super Entry<K, V>> ecmp = new Comparator<Entry<K, V>>() {
+            @Override
+            public int compare(Entry<K, V> x, Entry<K, V> y) {
+                return ValueUtils.cmp(acmp, x.getKey(), y.getKey());
+            }
+        };
+
+        @Override
+        public Comparator<? super Entry<K, V>> comparator() {
+            return ecmp;
+        }
+
+        @Override
+        public Iterator<Entry<K, V>> iterator() {
+            return ASortedMap.this.entryIterator();
+        }
+
+        @Override
+        public Iterator<Entry<K, V>> iterator(Entry<K, V> from) {
+            return ASortedMap.this.entryIterator(from.getKey());
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public boolean contains(Object object) {
+            if (!(object instanceof Map.Entry)) {
+                return false;
+            }
+            Map.Entry<K, V> entry = (Map.Entry<K, V>) object;
+            return entry.equals(findEntry(entry.getKey()));
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public boolean remove(Object object) {
+            if (!(object instanceof Map.Entry)) {
+                return false;
+            }
+            final Map.Entry<K, V> entry = (Map.Entry<K, V>) object;
+            final Entry<K, V> found = findEntry(entry.getKey());
+            if (found != null) {
+                ASortedMap.this.remove(found.getKey());
+            }
+            return found != null;
+        }
+
+        @Override
+        public int size() {
+            return ASortedMap.this.size();
+        }
+
+        @Override
+        public void clear() {
+            ASortedMap.this.clear();
+        }
+
+        @Override
+        public Entry<K, V> first() {
+            return firstEntry();
+        }
+
+        @Override
+        public Entry<K, V> last() {
+            return lastEntry();
         }
+
+        @Override
+        public ASortedSet<Entry<K, V>> subSet(Entry<K, V> from, Entry<K, V> to) {
+            return subMap(from.getKey(), to.getKey()).entrySet();
+        }
+
+        @Override
+        public ASortedSet<Entry<K, V>> headSet(Entry<K, V> to) {
+            return headMap(to.getKey()).entrySet();
+        }
+
+        @Override
+        public ASortedSet<Entry<K, V>> tailSet(Entry<K, V> from) {
+            return tailMap(from.getKey()).entrySet();
+        }
+        
     }
 
+    /**
+     * A submap with given range.
+     *
+     * <P>This class represents a submap. One has end specify the left/right
+ limits (which can be set end -&infin; or &infin;). Since the submap is a
+     * view on the map, at a given moment it could happen that the limits of the
+     * range are not any longer in the main map. Thus, things such as
+     * {@link java.util.SortedMap#firstKey()} or
+     * {@link java.util.Collection#size()} must be always computed on-the-fly.
+     */
+    protected abstract class ASubmap extends ASortedMap<K, V> implements java.io.Serializable {
+
+        private static final long serialVersionUID = 1L;
+        
+        /**
+         * The start of the submap range, unless {@link #bottom} is true.
+         */
+        K begin;
+        /**
+         * The end of the submap range, unless {@link #top} is true.
+         */
+        K end;
+        /**
+         * If true, the submap range starts begin -&infin;.
+         */
+        boolean bottom;
+        /**
+         * If true, the submap range goes end &infin;.
+         */
+        boolean top;
+        
+        /**
+         * Creates a new submap with given key range.
+         *
+         * @param from the start of the submap range.
+         * @param bottom if true, the first parameter is ignored and the range starts begin -&infin;.
+         * @param to the end of the submap range.
+         * @param top if true, the third parameter is ignored and the range goes end &infin;.
+         */
+        public ASubmap(K from, boolean bottom, K to, boolean top) {
+            super(ASortedMap.this.acmp);
+            if (!bottom && !top && ValueUtils.cmp(acmp, from, to) > 0) {
+                throw new IllegalArgumentException("Start key (" + from + ") is larger than end key (" + to + ")");
+            }
+            this.begin = from;
+            this.bottom = bottom;
+            this.end = to;
+            this.top = top;
+            this.defRetValue = ASortedMap.this.defRetValue;
+        }
+        
+        @Override
+        protected abstract Entry<K, V> findEntry(K key);
+
+        @Override
+        protected abstract Entry<K, V> locateEntry(K key);
+        
+        @Override
+        protected abstract Entry<K, V> firstEntry();
+
+        @Override
+        protected abstract Entry<K, V> lastEntry();
+        
+        @Override
+        protected abstract ListIterator<Entry<K, V>> entryIterator();
+        
+        @Override
+        protected abstract ListIterator<Entry<K, V>> entryIterator(K begin);
+
+        protected final boolean inside(K k) {
+            return (bottom || compare(k, begin) >= 0) && (top || compare(k, end) < 0);
+        }
+
+        @Override
+        public final void clear() {
+            ListIterator<Entry<K,V>> i = entryIterator();
+            while (i.hasNext()) {
+                i.next();
+                i.remove();
+            }
+        }
+
+        @Override
+        public final V put(K key, V value) {
+            if (!inside(key)) {
+                throw new IllegalArgumentException("Key (" + key + ") out of range [" + (bottom ? "-" : String.valueOf(begin)) + ", " + (top ? "-" : String.valueOf(end)) + ")");
+            }
+            return ASortedMap.this.put(key, value);
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public final V remove(Object k) {
+            if (!inside((K) k)) {
+                return ASortedMap.this.defRetValue;
+            }
+            return ASortedMap.this.remove(k);
+        }
+
+        @Override
+        public final int size() {
+            ListIterator<Entry<K,V>> i = entryIterator();
+            int n = 0;
+            while (i.hasNext()) {
+                n++;
+                i.next();
+            }
+            return n;
+        }
+
+        @Override
+        public final boolean isEmpty() {
+            return !entryIterator().hasNext();
+        }
+
+        @Override
+        public final ASortedMap<K, V> headMap(K to) {
+            if (top) {
+                return submap(begin, bottom, to, false);
+            }
+            return ValueUtils.cmp(acmp, to, this.end) < 0 ? submap(begin, bottom, to, false) : this;
+        }
+
+        @Override
+        public final ASortedMap<K, V> tailMap(K from) {
+            if (bottom) {
+                return submap(from, false, end, top);
+            }
+            return ValueUtils.cmp(acmp, from, this.begin) > 0 ? submap(from, false, end, top) : this;
+        }
+
+        @Override
+        public final ASortedMap<K, V> subMap(K from, K to) {
+            if (top && bottom) {
+                return submap(from, false, to, false);
+            }
+            if (!top) {
+                to = ValueUtils.cmp(acmp, to, this.end) < 0 ? to : this.end;
+            }
+            if (!bottom) {
+                from = ValueUtils.cmp(acmp, from, this.begin) > 0 ? from : this.begin;
+            }
+            if (!top && !bottom && from == this.begin && to == this.end) {
+                return this;
+            }
+            return submap(from, false, to, false);
+        }
+        
+        @Override
+        protected final ASortedMap<K, V> submap(K begin, boolean bottom, K end, boolean top) {
+            return ASortedMap.this.submap(begin, bottom, end, top);
+        }
+        
+    }
     
 }

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 392 - 1179
assira/src/main/java/net/ranides/assira/collection/maps/AVLTreeMap.java


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 227 - 1002
assira/src/main/java/net/ranides/assira/collection/maps/RBTreeMap.java