Package lupos.datastructures.simplifiedfractaltree

Source Code of lupos.datastructures.simplifiedfractaltree.SimplifiedFractalTree$PrefixElement

/**
* Copyright (c) 2013, Institute of Information Systems (Sven Groppe and contributors of LUPOSDATE), University of Luebeck
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
*   - Redistributions of source code must retain the above copyright notice, this list of conditions and the following
*     disclaimer.
*   - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
*     following disclaimer in the documentation and/or other materials provided with the distribution.
*   - Neither the name of the University of Luebeck nor the names of its contributors may be used to endorse or promote
*     products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package lupos.datastructures.simplifiedfractaltree;

import java.io.File;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedMap;

import lupos.datastructures.dbmergesortedds.heap.SequentialHeap;
import lupos.datastructures.paged_dbbptree.PrefixSearchMinMax;
import lupos.datastructures.simplifiedfractaltree.buffermanager.BufferedList;
import lupos.datastructures.simplifiedfractaltree.buffermanager.BufferedList_LuposSerialization;
import lupos.io.Registration;
import lupos.io.Registration.DeSerializerConsideringSubClasses;
import lupos.io.serializer.FRACTALTREEENTRY;
import sun.reflect.generics.reflectiveObjects.NotImplementedException;

/**
* This class is an implementation of the simplified fractaltree.
* @author Denis F�cke
*
* @param <K> Key
* @param <V> Value
* @see BufferedList_LuposSerialization
* @see FractalTreeEntry
*/
public class SimplifiedFractalTree<K extends Comparable<K> & Serializable, V extends Serializable> implements SortedMap<K, V>, Serializable,
    PrefixSearchMinMax<K, V> {
  /**
   * Serial Version ID.
   */
  protected static final long serialVersionUID = 7099147649283724775L;
  protected File file = new File("bufferedlist");
  protected File file2 = new File("mergelist");
  protected File file3 = new File("removelist");
  protected BufferedList_LuposSerialization<FractalTreeEntry<K, V>> bufferedList;
  protected MergeList mergeList;
  protected BufferedList_LuposSerialization<FractalTreeEntry<K, V>> removeList;
  protected ArrayList<Integer> rCount = new ArrayList<>();

  @SuppressWarnings("rawtypes")
  private static DeSerializerConsideringSubClasses<FractalTreeEntry> fractalTreeEntryDeSerializer = new FRACTALTREEENTRY();
  private static boolean deSerializerAdded = false;

  /**
   * Must be called before any FractalTree is constructed to take any effect
   * @param fractalTreeEntryDeSerializer
   */
  @SuppressWarnings({ "unchecked", "rawtypes" })
  public static<K extends Comparable<K>, V> void setDeSerializerForFractalTreeEntry(final DeSerializerConsideringSubClasses<FractalTreeEntry<K, V>> fractalTreeEntryDeSerializer){
    SimplifiedFractalTree.fractalTreeEntryDeSerializer = (DeSerializerConsideringSubClasses) fractalTreeEntryDeSerializer;
  }

  private static void addDeSerializer(){
    if(!SimplifiedFractalTree.deSerializerAdded){
      Registration.addDeSerializer(SimplifiedFractalTree.fractalTreeEntryDeSerializer);
      SimplifiedFractalTree.deSerializerAdded = true;
    }
  }

  /**
   * Constructs am empty fractal tree using a default page size of 8192.
   *
   * @see BufferedList
   */
  public SimplifiedFractalTree() {
    SimplifiedFractalTree.addDeSerializer();
    final FractalTreeEntry<K, V> entry = new FractalTreeEntry<>();
    this.bufferedList = new BufferedList_LuposSerialization<FractalTreeEntry<K, V>>(8 * 1024, this.file.getAbsoluteFile(), entry);
    this.mergeList = new MergeList(entry);
    this.removeList = new BufferedList_LuposSerialization<FractalTreeEntry<K, V>>(8 * 1024, this.file3.getAbsoluteFile(), entry);
  }

  /**
   * Constructs am empty fractal tree using a default page size of 8192.
   *
   * @param file a file specifying the name and the storage location on the disk.
   *
   * @see BufferedList
   */
  public SimplifiedFractalTree(final File file) {
    SimplifiedFractalTree.addDeSerializer();
    final FractalTreeEntry<K, V> entry = new FractalTreeEntry<>();
    this.bufferedList = new BufferedList_LuposSerialization<>(8 * 1024, new File(file.getAbsolutePath() + "bl"), entry);
    this.mergeList = new MergeList(entry, file);
    this.removeList = new BufferedList_LuposSerialization<>(8 * 1024, new File(file.getAbsolutePath() + "rl"), entry);
  }

  /**
   * Constructs am empty fractal tree.
   *
   * @param file a file specifying the name and the storage location on the disk.
   * @param pageSize the size of a page; greater than <tt>0</tt>
   *
   * @throws NegativeArraySizeException if pageSize is less or equal <tt>0</tt>
   *
   * @see BufferedList
   */
  public SimplifiedFractalTree(final File file, final int pageSize) {
    assert pageSize > 0;

    SimplifiedFractalTree.addDeSerializer();
    final FractalTreeEntry<K, V> entry = new FractalTreeEntry<>();
    this.bufferedList = new BufferedList_LuposSerialization<>(pageSize, new File(file.getAbsolutePath() + "bl"), entry);
    this.mergeList = new MergeList(entry, pageSize, file);
    this.removeList = new BufferedList_LuposSerialization<>(pageSize, new File(file.getAbsolutePath() + "rl"), entry);
  }

  /**
   * Constructs am empty fractal tree.
   *
   * @param pageSize the size of a page; greater than <tt>0</tt>
   *
   * @throws NegativeArraySizeException if pageSize is less or equal <tt>0</tt>
   *
   * @see BufferedList
   */
  public SimplifiedFractalTree(final int pageSize) {
    assert pageSize > 0;

    SimplifiedFractalTree.addDeSerializer();
    final FractalTreeEntry<K, V> entry = new FractalTreeEntry<>();
    this.bufferedList = new BufferedList_LuposSerialization<>(pageSize, this.file.getAbsoluteFile(), entry);
    this.mergeList = new MergeList(entry, pageSize);
    this.removeList = new BufferedList_LuposSerialization<>(pageSize, this.file3.getAbsoluteFile(), entry);
  }

  @Override
  public void clear() {
    this.bufferedList.clear();
    this.mergeList.clear();
    this.removeList.clear();
  }

  @SuppressWarnings("unchecked")
  @Override
  public boolean containsKey(final Object key) {
    assert key != null;

    return this.indexOf(0, (K) key, new FractalTreeEntry<K, V>(), 0) > -1;
  }

  @Override
  public boolean containsValue(final Object value) {
    for (final V v : this.values()) {
      if (v.equals(value)) {
        return true;
      }
    }
    return false;
  }

  @Override
  public V get(final Object key) {
    assert key != null;
    @SuppressWarnings("unchecked")
    final
    int index = this.indexOf(0, (K) key, new FractalTreeEntry<K, V>(), 0);

    if (index > -1) {
      return this.bufferedList.get(index).value;
    }
    return null;
  }

  @Override
  public boolean isEmpty() {
    return this.size() == 0;
  }

  @Override
  public V put(final K key, final V value) {
    assert key != null;

    V oldValue = null;
    FractalTreeEntry<K, V> oldEntry = null;
    final int index = this.indexOf(0, key, new FractalTreeEntry<K, V>(), 0);

    if (index >= 0) {
      oldEntry = this.bufferedList.get(index);
      oldValue = oldEntry.value;
      this.bufferedList.setNoReturn(index, new FractalTreeEntry<K, V>(key, value, oldEntry.pointer));
    } else {
      this.merge(new FractalTreeEntry<K, V>(key, value));
    }

    return oldValue;
  }

  @Override
  public void putAll(final Map<? extends K, ? extends V> map) {
    for (final K key : map.keySet()) {
      this.put(key, map.get(key));
    }
  }

  @Override
  public V remove(final Object key) {
    assert key != null;

    @SuppressWarnings("unchecked")
    final
    int oldIndex = this.indexOf(0, (K) key, new FractalTreeEntry<K, V>(), 0);
    V oldValue = null;
    if (oldIndex != -1) {
      oldValue = this.bufferedList.get(oldIndex).value;

      // Verschieben in mergelist
      final int imax = this.getNextPosition(oldIndex);
      final int imin = this.getArrayStart(oldIndex);
      int counter = 0;
      for (int j = this.getDeepth(oldIndex); j >= 0; j--) {
        boolean beyondOldElement = false;
        for (int i = (int) (Math.pow(2, j) - 1) + imin; i < imax; i += Math.pow(2, j + 1)) {
          if (!beyondOldElement && i >= oldIndex) {
            if (i == oldIndex) {
              this.bufferedList.set(oldIndex, new FractalTreeEntry<K, V>());
            }
            i++;
            beyondOldElement = true;
          }
          if (i < imax) {
            final FractalTreeEntry<K, V> entry = this.bufferedList.set(i, new FractalTreeEntry<K, V>());
            entry.pointer = -1;
            this.removeList.add(counter, entry);
            counter++;
          }
        }
      }

      // ggf. mergen
      if (this.removeList.size() > 0) {
        this.removeMerge(0);
        if (this.bufferedList.size() == imax) {
          for (; this.mergeList.size() < this.bufferedList.size();) {
            this.bufferedList.remove(this.bufferedList.size() - 1);
          }
        }
        this.copyFromMergeList();
      }
      // mergelist leeren
      this.mergeList.clear();
      this.removeList.clear();
    }
    return oldValue;
  }

  protected int getDeepth(final int index) {
    return (int) Math.floor(Math.log10(index + 1) / Math.log10(2));
  }

  private void copyFromMergeList() {
    final int size = this.mergeList.size();

    for (int i = 0; i < size; i++) {
      if (this.mergeList.get(i).key == null) {
        i = i * 2;
        continue;
      }

      this.bufferedList.set(i, this.mergeList.get(i));
    }

    for (int i = 0; i < size; i = i * 2 + 1) {
      if (this.bufferedList.get(i).key != null && this.bufferedList.get(i).pointer < 0) {
        this.calcPointers(i);
      }
    }
  }

  protected void calcPointers(final int index) {
    if (this.bufferedList.get(index).key == null) {
      return;
    }

    int i = index;
    int j = this.getNextPosition(index);
    final int imax = i * 2 + 1;
    int jmax = j * 2 + 1;
    final int size = this.bufferedList.size();

    if (j >= size) {
      for (; i < imax; i++) {
        final FractalTreeEntry<K, V> entry = this.bufferedList.get(i);
        entry.pointer = -1;
        this.bufferedList.set(i, entry);
      }
      return;
    } else {
      for (; this.bufferedList.get(j).key == null;) {
        j = j * 2 + 1;
        jmax = j * 2 + 1;
      }
    }

    for (; i < imax; i++) {
      final FractalTreeEntry<K, V> entry = this.bufferedList.get(i);

      for (;;) {
        if (j + 1 < jmax && entry.key.compareTo(this.bufferedList.get(j).key) >= 0) {
          j++;
        } else {
          entry.pointer = j;
          break;
        }
      }
      this.bufferedList.set(i, entry);
    }
  }

  private void removeMerge(final int index) {
    if (this.bufferedList.get(index).key == null && this.mergeList.size() == index) { // fall 1
      final int imax = index * 2 + 1;
      for (int i = index; i < imax; i++) {
        this.mergeList.add(this.removeList.get(i));
      }
    } else if (this.bufferedList.get(index).key != null && this.mergeList.size() == index * 2 + 1) { // fall 3
      int b = index;
      int m = index;
      final int imax = 2 * index;
      for (;;) {
        if (b > imax && m > imax) {
          break;
        }
        if (b <= imax && m <= imax) {
          final FractalTreeEntry<K, V> bEntry = this.bufferedList.get(b);
          bEntry.pointer = -1;
          final FractalTreeEntry<K, V> mEntry = this.removeList.get(m);
          mEntry.pointer = -1;
          if (bEntry.key.compareTo(mEntry.key) < 0) {
            this.bufferedList.setNoReturn(b, new FractalTreeEntry<K, V>());
            this.mergeList.add(bEntry);
            b++;
          } else {
            this.removeList.setNoReturn(m, new FractalTreeEntry<K, V>());
            this.mergeList.add(mEntry);
            m++;
          }
        } else {
          if (b <= imax) {
            this.mergeList.add(this.bufferedList.set(b, new FractalTreeEntry<K, V>()));
            b++;
          }
          if (m <= imax) {
            this.mergeList.add(this.removeList.set(m, new FractalTreeEntry<K, V>()));
            m++;
          }
        }
      }
    } else if (this.bufferedList.get(index).key != null && this.mergeList.size() == index) { // fall 2
      for (; this.mergeList.size() < index * 2 + 1;) {
        this.mergeList.add(new FractalTreeEntry<K, V>());
      }

      int b = index;
      int m = index;
      final int imax = 2 * index;
      for (;;) {
        if (b > imax && m > imax) {
          break;
        }
        if (b <= imax && m <= imax) {
          final FractalTreeEntry<K, V> bEntry = this.bufferedList.get(b);
          bEntry.pointer = -1;
          final FractalTreeEntry<K, V> mEntry = this.removeList.get(m);
          mEntry.pointer = -1;
          if (bEntry.key.compareTo(mEntry.key) < 0) {
            this.bufferedList.setNoReturn(b, new FractalTreeEntry<K, V>());
            this.mergeList.add(bEntry);
            b++;
          } else {
            this.removeList.setNoReturn(m, new FractalTreeEntry<K, V>());
            this.mergeList.add(mEntry);
            m++;
          }
        } else {
          if (b <= imax) {
            this.mergeList.add(this.bufferedList.set(b, new FractalTreeEntry<K, V>()));
            b++;
          }
          if (m <= imax) {
            this.mergeList.add(this.removeList.set(m, new FractalTreeEntry<K, V>()));
            m++;
          }
        }
      }
      // printMergelist();
    } else if (this.bufferedList.get(index).key == null && this.mergeList.size() == index * 2 + 1) {
      int b = index;
      int m = index;
      final int imax = 2 * index;
      for (;;) {
        if (b > imax && m > imax) {
          break;
        }
        if (b <= imax && m <= imax) {
          final FractalTreeEntry<K, V> bEntry = this.removeList.get(b);
          bEntry.pointer = -1;
          final FractalTreeEntry<K, V> mEntry = this.mergeList.get(m);
          mEntry.pointer = -1;
          if (bEntry.key.compareTo(mEntry.key) < 0) {
            this.removeList.setNoReturn(b, new FractalTreeEntry<K, V>());
            this.mergeList.add(bEntry);
            b++;
          } else {
            this.mergeList.setNoReturn(m, new FractalTreeEntry<K, V>());
            this.mergeList.add(mEntry);
            m++;
          }
        } else {
          if (b <= imax) {
            this.mergeList.add(this.removeList.set(b, new FractalTreeEntry<K, V>()));
            b++;
          }
          if (m <= imax) {
            this.mergeList.add(this.mergeList.set(m, new FractalTreeEntry<K, V>()));
            m++;
          }
        }
      }
    } else {
      System.out.println("Error");
    }
    // print();
    if (index * 2 + 1 < this.removeList.size()) {
      this.removeMerge(index * 2 + 1);
    }
  }

  protected int getHeigth(final int size) {
    if(size == 0) {
      return 0;
    }
    return (int) Math.ceil(Math.log10(size) / Math.log10(2));
  }

  @Override
  public int size() {
    int index = 0;
    int size = 0;
    for (;;) {
      if (this.bufferedList.size() > index) {
        if (this.bufferedList.get(index).key != null) {
          size += index + 1;
          index = index * 2 + 1;
        } else {
          index = index * 2 + 1;
        }
      } else {
        return size;
      }
    }
  }

  @Override
  public Object[] getClosestElements(final K key) {
    assert key != null;

    final ArrayList<K> closestKeys = new ArrayList<>();

    return this.getClosestElements(0, key, closestKeys).toArray();
  }

  private ArrayList<K> getClosestElements(final int index, final K key, ArrayList<K> closestKeys) {
    K closest = null;
    if (closestKeys.size() > 0) {
      closest = closestKeys.get(0);
    }
    if (this.isCloserThanClosestKey(closest, key, this.bufferedList.get(index).key)) {
      closestKeys.clear();
      closestKeys.add(this.bufferedList.get(index).key);
    } else if (this.isEqualToClosestKey(closest, this.bufferedList.get(index).key)) {
      closestKeys.add(this.bufferedList.get(index).key);
    }

    final int imin = this.getArrayStart(index);
    final int imax = this.getNextPosition(index) - 1;

    final int pointer = -1;
    if (index + 1 <= imax) {
      closestKeys = this.getClosestElementRight(index + 1, key, closestKeys, pointer);
    }
    if (index - 1 >= imin) {
      closestKeys = this.getClosestElementLeft(index - 1, key, closestKeys, pointer);
    }

    if (pointer != -1) {
      closestKeys = this.getClosestElements(pointer, key, closestKeys);
    } else if (this.bufferedList.get(index).pointer != -1) {
      closestKeys = this.getClosestElements(this.bufferedList.get(index).pointer, key, closestKeys);
    }

    return closestKeys;
  }

  private ArrayList<K> getClosestElementRight(final int index, final K key, ArrayList<K> closestKeys, int pointer) {
    K closest = null;
    if (closestKeys.size() > 0) {
      closest = closestKeys.get(0);
    }
    if (this.isCloserThanClosestKey(closest, key, this.bufferedList.get(index).key)) {
      closestKeys.clear();
      closestKeys.add(this.bufferedList.get(index).key);
      pointer = this.bufferedList.get(index).pointer;
    } else if (this.isEqualToClosestKey(closest, this.bufferedList.get(index).key)) {
      closestKeys.add(this.bufferedList.get(index).key);
      pointer = this.bufferedList.get(index).pointer;
    } else if (this.isNotClosestKey(closest, key, this.bufferedList.get(index).key)) {
      pointer = this.bufferedList.get(index - 1).pointer;
    }

    final int imax = this.getNextPosition(index) - 1;

    if (index + 1 <= imax) {
      closestKeys = this.getClosestElementRight(index + 1, key, closestKeys, pointer);
    }

    return closestKeys;
  }

  private boolean isNotClosestKey(final K closest, final K key, final K newKey) {
    if (closest.compareTo(key) > 0) {
      if (newKey.compareTo(newKey) > 0) {
        return true;
      }
    } else if (closest.compareTo(key) < 0) {
      if (newKey.compareTo(newKey) < 0) {
        return true;
      }
    }
    return false;
  }

  private ArrayList<K> getClosestElementLeft(final int index, final K key, ArrayList<K> closestKeys, int pointer) {
    K closest = null;
    if (closestKeys.size() > 0) {
      closest = closestKeys.get(0);
    }
    if (this.isCloserThanClosestKey(closest, key, this.bufferedList.get(index).key)) {
      closestKeys.clear();
      closestKeys.add(this.bufferedList.get(index).key);
      pointer = this.bufferedList.get(index).pointer;
    } else if (this.isEqualToClosestKey(closest, this.bufferedList.get(index).key)) {
      closestKeys.add(this.bufferedList.get(index).key);
      pointer = this.bufferedList.get(index).pointer;
    } else if (this.isNotClosestKey(closest, key, this.bufferedList.get(index).key)) {
      pointer = this.bufferedList.get(index + 1).pointer;
    }

    final int imin = this.getArrayStart(index);

    if (index - 1 >= imin) {
      closestKeys = this.getClosestElementLeft(index - 1, key, closestKeys, pointer);
    }

    return closestKeys;
  }

  private boolean isCloserThanClosestKey(final K closest, final K key, final K newKey) {
    if (closest == null) {
      return true;
    }
    if (key.compareTo(newKey) != 0) {
      if (key.compareTo(newKey) < 0) {
        if (closest.compareTo(newKey) > 0) {
          return true;
        }
      } else if (key.compareTo(newKey) > 0) {
        if (closest.compareTo(newKey) < 0) {
          return true;
        }
      }
    }
    return false;
  }

  private boolean isEqualToClosestKey(final K closest, final K newKey) {
    return closest.compareTo(newKey) == 0;
  }

  /**
   * Searches all values whose corresponded entrys matching the specified prefix. Returns an Iterator of these values.
   *
   * <p>
   * The user must ensure <tt>prefix.compareTo(anOtherKey) == 0</tt> if the prefix is matching another key by implementing a class that allows to
   * specify a <tt>Comparator</tt> that is used for the implementation of the <tt>compareTo</tt> method.
   *
   * @param prefix a prefix
   * @return an Iterator containing all values whose entrys having the specified prefix.
   *
   * @throws NullPointerException if the specified key is null
   *
   * @see Comparator
   * @see Comparable
   */
  @Override
  public Iterator<V> prefixSearch(final K prefix) {
    assert prefix != null;

    this.heap = new SequentialHeap<>(this.getDeepth(this.bufferedList.size()));

    this.prefixSearch(0, prefix, null, null);
    return new PrefixIterator(prefix, null, null);
  }

  /**
   * Searches all values whose corresponded entrys matching the specified prefix and minimum. Returns an Iterator of these values.
   *
   * <p>
   * The user must ensure <tt>prefix.compareTo(anOtherKey) == 0</tt> if the prefix is matching another key by implementing a class that allows to
   * specify a <tt>Comparator</tt> that is used for the implementation of the <tt>compareTo</tt> method.
   *
   * @param prefix a prefix
   * @param min a key specifying a minimum
   * @return an Iterator containing all values whose entrys having the specified prefix.
   *
   * @throws NullPointerException if the specified key is null
   *
   * @see Comparator
   * @see Comparable
   */
  @Override
  public Iterator<V> prefixSearch(final K prefix, final K min) {
    assert prefix != null;
    assert min != null;

    this.heap = new SequentialHeap<>(this.getDeepth(this.bufferedList.size()));

    this.prefixSearch(0, prefix, min, null);
    return new PrefixIterator(prefix, min, null);
  }

  /**
   * Searches all values whose corresponded entrys matching the specified prefix, minimum and maximum. Returns an Iterator of these values.
   *
   * <p>
   * The user must ensure <tt>prefix.compareTo(anOtherKey) == 0</tt> if the prefix is matching another key by implementing a class that allows to
   * specify a <tt>Comparator</tt> that is used for the implementation of the <tt>compareTo</tt> method.
   *
   * @param prefix a prefix
   * @param min a key specifying a minimum
   * @param max a key specifying a maximum
   * @return an Iterator containing all values whose entrys having the specified prefix.
   *
   * @throws NullPointerException if the specified key is null
   *
   * @see Comparator
   * @see Comparable
   */
  @Override
  public Iterator<V> prefixSearch(final K prefix, final K min, final K max) {
    assert prefix != null;
    assert min != null;
    assert max != null;

    this.heap = new SequentialHeap<>(this.getDeepth(this.bufferedList.size()));

    this.prefixSearch(0, prefix, min, max);
    return new PrefixIterator(prefix, null, max);
  }

  /**
   * Searches all values whose corresponded entrys matching the specified prefix and maximum. Returns an Iterator of these values.
   *
   * <p>
   * The user must ensure <tt>prefix.compareTo(anOtherKey) == 0</tt> if the prefix is matching another key by implementing a class that allows to
   * specify a <tt>Comparator</tt> that is used for the implementation of the <tt>compareTo</tt> method.
   *
   * @param prefix a prefix
   * @param max a key specifying a maximum
   * @return an Iterator containing all values whose entrys having the specified prefix.
   *
   * @throws NullPointerException if the specified key is null
   *
   * @see Comparator
   * @see Comparable
   */
  @Override
  public Iterator<V> prefixSearchMax(final K prefix, final K max) {
    assert prefix != null;
    assert max != null;

    this.heap = new SequentialHeap<>(this.getDeepth(this.bufferedList.size()));

    this.prefixSearch(0, prefix, null, max);
    return new PrefixIterator(prefix, null, max);
  }

  private class PrefixIterator implements Iterator<V> {
    private final K prefix;
    private final K min;
    private final K max;

    public PrefixIterator(final K prefix, final K min, final K max) {
      this.prefix = prefix;
      this.min = min;
      this.max = max;
    }

    @Override
    public boolean hasNext() {
      return !SimplifiedFractalTree.this.heap.isEmpty();
    }

    @Override
    public V next() {
      final PrefixElement e = SimplifiedFractalTree.this.heap.pop();
      if (e.position + 1 < SimplifiedFractalTree.this.getNextPosition(e.position) && SimplifiedFractalTree.this.prefixCompare(e.position + 1, this.prefix, this.min, this.max) == 0) {
        SimplifiedFractalTree.this.heap.add(new PrefixElement(e.position + 1, SimplifiedFractalTree.this.bufferedList.get(e.position + 1).key));
      }
      return SimplifiedFractalTree.this.bufferedList.get(e.position).value;
    }

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

  @Override
  public Comparator<? super K> comparator() {
    return new Comparator<K>() {
      @Override
      public int compare(final K o1, final K o2) {
        return o1.compareTo(o2);
      }
    };
  }

  @Override
  public Set<java.util.Map.Entry<K, V>> entrySet() {
    return new EntrySet();
  }

  private class SetEntry implements Entry<K, V> {
    K key;
    V value;

    public SetEntry(final K key, final V value) {
      SetEntry.this.value = value;
      SetEntry.this.key = key;
    }

    @Override
    public K getKey() {
      return this.key;
    }

    @Override
    public V getValue() {
      return this.value;
    }

    @Override
    public V setValue(final V value) {
      final V oldValue = SetEntry.this.value;
      SetEntry.this.value = value;
      return oldValue;
    }

  }

  private class EntrySet implements Set<Map.Entry<K, V>> {
    @Override
    public int size() {
      return SimplifiedFractalTree.this.size();
    }

    @Override
    public void clear() {
      SimplifiedFractalTree.this.clear();
    }

    @Override
    public boolean isEmpty() {
      return SimplifiedFractalTree.this.isEmpty();
    }

    @Override
    public boolean contains(final Object key) {
      return SimplifiedFractalTree.this.containsKey(key);
    }

    @Override
    public Iterator<Map.Entry<K, V>> iterator() {
      return new EntryIterator();
    }

    @Override
    public Object[] toArray() {
      throw new NotImplementedException();
    }

    @Override
    public <T> T[] toArray(final T[] a) {
      throw new NotImplementedException();
    }

    @Override
    public boolean add(final java.util.Map.Entry<K, V> entry) {
      SimplifiedFractalTree.this.put(entry.getKey(), entry.getValue());
      return true;
    }

    @Override
    public boolean remove(final Object key) {
      SimplifiedFractalTree.this.remove(key);
      return true;
    }

    @Override
    public boolean containsAll(final Collection<?> c) {
      final Iterator<?> iterator = c.iterator();
      for (; iterator.hasNext();) {
        if (!SimplifiedFractalTree.this.containsKey(iterator.next())) {
          return false;
        }
      }
      return false;
    }

    @Override
    public boolean addAll(final Collection<? extends java.util.Map.Entry<K, V>> c) {
      final Iterator<? extends Entry<K, V>> iterator = c.iterator();
      boolean changed = false;
      for (; iterator.hasNext();) {
        final Map.Entry<K, V> entry = iterator.next();
        SimplifiedFractalTree.this.put(entry.getKey(), entry.getValue());
        changed = true;
      }
      return changed;
    }

    @Override
    public boolean retainAll(final Collection<?> c) {
      final Iterator<?> iterator = c.iterator();
      for (; iterator.hasNext();) {
        final Object key = iterator.next();
        if (!this.contains(key)) {
          SimplifiedFractalTree.this.remove(key);
        }
      }
      return false;
    }

    @Override
    public boolean removeAll(final Collection<?> c) {
      final Iterator<?> iterator = c.iterator();
      boolean changed = false;
      for (; iterator.hasNext();) {
        this.remove(iterator.next());
        changed = true;
      }
      return changed;
    }
  }

  @Override
  public K firstKey() {
    K firstKey = null;
    final int size = this.bufferedList.size();
    for (int next = 0; next < size; next = this.getNextPosition(next)) {
      if (this.bufferedList.get(next).key != null) {
        if (firstKey == null) {
          firstKey = this.bufferedList.get(next).key;
        } else if (this.bufferedList.get(next).key.compareTo(firstKey) < 0) {
          firstKey = this.bufferedList.get(next).key;
        }
      }
    }
    return firstKey;
  }

  private transient ArrayList<FractalTreeEntry<K, V>> entrys = new ArrayList<>();

  private class EntryIterator implements Iterator<Map.Entry<K, V>> {
    private int index = 0;

    public EntryIterator() {
      final int size = SimplifiedFractalTree.this.bufferedList.size();
      for (int i = 0; i < size; i++) {
        if (SimplifiedFractalTree.this.bufferedList.get(i).key != null) {
          SimplifiedFractalTree.this.entrys.add(SimplifiedFractalTree.this.bufferedList.get(i));
        }
      }
      Collections.sort(SimplifiedFractalTree.this.entrys);
    }

    @Override
    public boolean hasNext() {
      return this.index < SimplifiedFractalTree.this.entrys.size();
    }

    @Override
    public Map.Entry<K, V> next() {
      if (this.hasNext()) {
        this.index++;
        return new SetEntry(SimplifiedFractalTree.this.entrys.get(this.index).key, SimplifiedFractalTree.this.entrys.get(this.index).value);
      } else {
        throw new NoSuchElementException();
      }
    }

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

  @Override
  public SortedMap<K, V> headMap(final K toKey) {
    throw new NotImplementedException();
  }

  @Override
  public Set<K> keySet() {
    return new KeySet();
  }

  private class KeySet implements Set<K> {
    ArrayList<K> keys = new ArrayList<>();

    public KeySet() {
      final int size = SimplifiedFractalTree.this.bufferedList.size();
      for (int i = 0; i < size; i++) {
        if (SimplifiedFractalTree.this.bufferedList.get(i).key != null) {
          this.keys.add(SimplifiedFractalTree.this.bufferedList.get(i).key);
        }
      }
      Collections.sort(this.keys);
    }

    @Override
    public int size() {
      return this.keys.size();
    }

    @Override
    public boolean isEmpty() {
      return this.keys.isEmpty();
    }

    @Override
    public boolean contains(final Object key) {
      return this.keys.contains(key);
    }

    @Override
    public Iterator<K> iterator() {
      return this.keys.iterator();
    }

    @Override
    public Object[] toArray() {
      return this.keys.toArray();
    }

    @Override
    public <T> T[] toArray(final T[] a) {
      return this.keys.toArray(a);
    }

    @Override
    public boolean add(final K key) {
      throw new NotImplementedException();
    }

    @Override
    public boolean remove(final Object key) {
      this.keys.remove(key);
      SimplifiedFractalTree.this.remove(key);
      return true;
    }

    @Override
    public boolean containsAll(final Collection<?> c) {
      return this.keys.containsAll(c);
    }

    @Override
    public boolean addAll(final Collection<? extends K> c) {
      throw new NotImplementedException();
    }

    @Override
    public boolean retainAll(final Collection<?> c) {
      throw new NotImplementedException();
    }

    @Override
    public boolean removeAll(final Collection<?> c) {
      throw new NotImplementedException();
    }

    @Override
    public void clear() {
      this.keys.clear();
      SimplifiedFractalTree.this.clear();
    }
  }

  @Override
  public K lastKey() {
    K lastKey = null;
    final int size = this.bufferedList.size();
    for (int next = 0; next < size; next = this.getNextPosition(next) * 2) {
      if (this.bufferedList.get(next).key != null) {
        if (lastKey == null) {
          lastKey = this.bufferedList.get(next).key;
        } else if (this.bufferedList.get(next).key.compareTo(lastKey) > 0) {
          lastKey = this.bufferedList.get(next).key;
        }
      }
    }
    return lastKey;
  }

  @Override
  public SortedMap<K, V> subMap(final K fromKey, final K toKey) {
    throw new NotImplementedException();
  }

  @Override
  public SortedMap<K, V> tailMap(final K arg0) {
    throw new NotImplementedException();
  }

  @Override
  public Collection<V> values() {
    final ArrayList<V> values = new ArrayList<>();

    final int size = this.bufferedList.size();
    for (int i = 0; i < size; i++) {
      if (this.bufferedList.get(i).key != null) {
        this.entrys.add(this.bufferedList.get(i));
      }
    }
    Collections.sort(this.entrys);
    for (int i = 0; i < size; i++) {
      values.add(this.entrys.get(0).value);
    }
    return values;
  }

  private void prefixSearch(final int index, final K prefix, final K min, final K max) {
    if (this.bufferedList.size() > index) {
      int nextArrayIndex = index;
      if (this.bufferedList.get(nextArrayIndex).key == null) {
        for (; nextArrayIndex < this.bufferedList.size();) {
          if (this.bufferedList.get(nextArrayIndex).key != null) {
            break;
          } else {
            nextArrayIndex = nextArrayIndex * 2 + 1;
          }
        }
        this.prefixSearch(nextArrayIndex, prefix, min, max);
      } else {
        nextArrayIndex = this.getNextPosition(index);
        if (this.prefixCompare(index, prefix, min, max) >= 0) {
          final int res = this.prefixBinarySearch(this.getArrayStart(index), index, prefix, min, max);
          if (this.prefixCompare(res, prefix, min, max) == 0) {
            this.heap.add(new PrefixElement(res, this.bufferedList.get(res).key));
          }
          if (this.bufferedList.get(res).pointer > -1) {
            this.prefixSearch(this.bufferedList.get(res).pointer, prefix, min, max);
          }
        } else if (this.prefixCompare(index, prefix, min, max) < 0) {
          final int res = this.prefixBinarySearch(index, this.getNextPosition(index) - 1, prefix, min, max);
          if (this.prefixCompare(res, prefix, min, max) == 0) {
            this.heap.add(new PrefixElement(res, this.bufferedList.get(res).key));
          }
          if (this.bufferedList.get(res).pointer > -1) {
            this.prefixSearch(this.bufferedList.get(res).pointer, prefix, min, max);
          }
        }
      }
    }
  }

  /**
   * Does a binary search for the prefix search.
   * @param imin The left border of the interval
   * @param imax The right border of the interval
   * @param prefix The prefix
   * @param min A minimum
   * @param max A maximum
   * @return The position of the result
   */
  private int prefixBinarySearch(final int imin, final int imax, final K prefix, final K min, final K max) {
    if (imax == imin) {
      return imax;
    } else {
      final int imid = this.midpoint(imin, imax);
      if (this.prefixCompare(imin, prefix, min, max) == 0) {
        return imin;
      } else if (this.prefixCompare(imid - 1, prefix, min, max) >= 0) {
        return this.prefixBinarySearch(imin, imid - 1, prefix, min, max);
      } else if (this.prefixCompare(imax, prefix, min, max) <= 0) {
        return this.prefixBinarySearch(imid, imax, prefix, min, max);
      } else {
        return imax;
      }
    }
  }

  private transient SequentialHeap<PrefixElement> heap;

  private class PrefixElement implements Comparable<PrefixElement> {
    int position = -1;
    K key;

    public PrefixElement(final int position, final K key) {
      PrefixElement.this.position = position;
      PrefixElement.this.key = key;
    }

    @Override
    public int compareTo(final PrefixElement o) {
      return this.key.compareTo(o.key);
    }
  }

  private int prefixCompare(final int index, final K prefix, final K min, final K max) {
    if (prefix.compareTo(this.bufferedList.get(index).key) > 0) {
      return 1;

    } else if (prefix.compareTo(this.bufferedList.get(index).key) < 0) {
      return -1;
    } else {
      if (min == null && max == null) {
        return 0;
      } else if (min != null && max == null) {
        if (this.bufferedList.get(index).key.compareTo(min) >= 0) {
          return 0;
        }
      } else if (min == null && max != null) {
        if (this.bufferedList.get(index).key.compareTo(max) <= 0) {
          return 0;
        }
      } else if (min != null && max != null) {
        if (this.bufferedList.get(index).key.compareTo(min) >= 0 && this.bufferedList.get(index).key.compareTo(max) <= 0) {
          return 0;
        }
      }
    }
    return 0;
  }

  protected int getNextPosition(final int index) {
    final double a = Math.pow(2, Math.floor(Math.log10(index + 1) / Math.log10(2)));
    final int nextArrayIndex = (int) (((index + 1) - ((index + 1) % a)) * 2 - 1);
    return nextArrayIndex;
  }

  protected int getArrayStart(final int index) {
    if (index == 0) {
      return 0;
    }
    return (this.getNextPosition(index) - 1) / 2;
  }

  public int indexOf(final int index, final K key, FractalTreeEntry<K, V> entry, int nextArrayIndex) {
    if (index >= this.bufferedList.size()) {
      return -1;
    }
    if (this.bufferedList.size() > 0) {
      entry = this.bufferedList.get(index);
      if (entry.key != null && entry.key.compareTo(key) == 0) {
        return index;
      } else {
        nextArrayIndex = index;
        if (this.bufferedList.get(nextArrayIndex).key == null) {
          for (; nextArrayIndex < this.bufferedList.size();) {
            if (this.bufferedList.get(nextArrayIndex).key != null) {
              break;
            } else {
              nextArrayIndex = nextArrayIndex * 2 + 1;
            }
          }
          return this.indexOf(nextArrayIndex, key, entry, nextArrayIndex);
        } else {
          nextArrayIndex = this.getNextPosition(index);
          if (entry.pointer < 0) {
            if (entry.key.compareTo(key) > 0) {
              final int newindex = this.binarySearch(this.getArrayStart(index), index, key);
              if (newindex == -1) {
                return -1;
              } else {
                if (this.bufferedList.get(newindex).key.compareTo(key) == 0) {
                  return newindex;
                } else {
                  return -1;
                }
              }
            } else {
              final int newindex = this.binarySearch(index, this.getNextPosition(index) - 1, key);
              if (newindex == -1) {
                return -1;
              } else {
                if (this.bufferedList.get(newindex).key.compareTo(key) == 0) {
                  return newindex;
                } else {
                  return -1;
                }
              }
            }
          } else {
            if (entry.key.compareTo(key) > 0) {
              final int newindex = this.binarySearch(this.getArrayStart(index), index, key);
              if (this.bufferedList.get(newindex).key.compareTo(key) == 0) {
                return newindex;
              } else {
                return this.indexOf(this.bufferedList.get(newindex).pointer, key, entry, nextArrayIndex);
              }
            } else {
              final int newindex = this.binarySearch(index, this.getNextPosition(index) - 1, key);
              if (this.bufferedList.get(newindex).key.compareTo(key) == 0) {
                return newindex;
              } else {
                return this.indexOf(this.bufferedList.get(newindex).pointer, key, entry, nextArrayIndex);
              }
            }
          }
        }
      }
    } else {
      return -1;
    }
  }

  protected int binarySearch(final int imin, final int imax, final K key) {
    if (imax == imin) {
      return imax;
    } else {
      final int imid = this.midpoint(imin, imax);
      if (this.bufferedList.get(imin).key.compareTo(key) >= 0) {
        return imin;
      } else if (this.bufferedList.get(imid - 1).key.compareTo(key) >= 0) {
        return this.binarySearch(imin, imid - 1, key);
      } else if (this.bufferedList.get(imax).key.compareTo(key) >= 0) {
        return this.binarySearch(imid, imax, key);
      } else {
        return imax;
      }
    }
  }

  private int midpoint(final int imin, final int imax) {
    return (int) (imin + Math.ceil((double) (imax - imin) / 2));
  }

  protected void merge(final int index) {
    if (this.bufferedList.size() <= index || this.bufferedList.get(index).key == null) {
      final int imax = 2 * index;

      for (int i = index; i <= imax; i++) {
        if (this.bufferedList.size() > i) {
          this.bufferedList.set(i, this.mergeList.get(i));
        } else {
          this.bufferedList.add(this.mergeList.get(i));
        }
      }
      this.calcPointers(index);
      this.mergeList.clear();
    } else {
      int b = index;
      int m = index;
      final int imax = 2 * index;
      if (this.bufferedList.size() == index * 2 + 1) {
        for (;;) {
          if (b > imax && m > imax) {
            break;
          }
          if (b <= imax && m <= imax) {
            final FractalTreeEntry<K, V> bEntry = this.bufferedList.get(b);
            final FractalTreeEntry<K, V> mEntry = this.mergeList.get(m);
            if (bEntry.key.compareTo(mEntry.key) < 0) {
              this.bufferedList.setNoReturn(b, new FractalTreeEntry<K, V>());
              this.bufferedList.add(bEntry);
              b++;
            } else {
              this.mergeList.setNoReturn(m, new FractalTreeEntry<K, V>());
              this.bufferedList.add(mEntry);
              m++;
            }
          } else {
            if (b <= imax) {
              this.bufferedList.add(this.bufferedList.set(b, new FractalTreeEntry<K, V>()));
              b++;
            }
            if (m <= imax) {
              this.bufferedList.add(this.mergeList.set(m, new FractalTreeEntry<K, V>()));
              m++;
            }
          }
        }
        this.calcPointers(index*2+1);
        this.mergeList.clear();
      } else if (this.bufferedList.get(index * 2 + 1).key == null) {
        for (int i = index * 2 + 1;;) {
          if (b > imax && m > imax) {
            break;
          }
          if (b <= imax && m <= imax) {
            final FractalTreeEntry<K, V> bEntry = this.bufferedList.get(b);
            final FractalTreeEntry<K, V> mEntry = this.mergeList.get(m);
            if (bEntry.key.compareTo(mEntry.key) < 0) {
              this.bufferedList.setNoReturn(b, new FractalTreeEntry<K, V>());
              this.bufferedList.set(i, bEntry);
              b++;
              i++;
            } else {
              this.mergeList.setNoReturn(m, new FractalTreeEntry<K, V>());
              this.bufferedList.set(i, mEntry);
              m++;
              i++;
            }
          } else {
            if (b <= imax) {
              this.bufferedList.set(i, this.bufferedList.set(b, new FractalTreeEntry<K, V>()));
              b++;
              i++;
            }
            if (m <= imax) {
              this.bufferedList.set(i, this.mergeList.set(m, new FractalTreeEntry<K, V>()));
              m++;
              i++;
            }
          }
        }
        this.calcPointers(index*2+1);
        this.mergeList.clear();
      } else {
        for (;;) {
          if (b > imax && m > imax) {
            break;
          }
          if (b <= imax && m <= imax) {
            final FractalTreeEntry<K, V> bEntry = this.bufferedList.get(b);
            final FractalTreeEntry<K, V> mEntry = this.mergeList.get(m);
            if (bEntry.key.compareTo(mEntry.key) < 0) {
              this.bufferedList.setNoReturn(b, new FractalTreeEntry<K, V>());
              this.mergeList.add(bEntry);
              b++;
            } else {
              this.mergeList.setNoReturn(m, new FractalTreeEntry<K, V>());
              this.mergeList.add(mEntry);
              m++;
            }
          } else {
            if (b <= imax) {
              this.mergeList.add(this.bufferedList.set(b, new FractalTreeEntry<K, V>()));
              b++;
            }
            if (m <= imax) {
              this.mergeList.add(this.mergeList.set(m, new FractalTreeEntry<K, V>()));
              m++;
            }
          }
        }

        this.merge(index * 2 + 1);
      }
    }
  }

  protected int getPreviousPosition(final int index) {
    return (index - 1) / 2;
  }

  protected int calcPointer(final int index, final K key) {
    int j = this.getNextPosition(index); // Startposition des nächsten Arrays ermitteln
    final int size = this.bufferedList.size(); // Größe zwischenspeichern

    if (j >= size) {
      // keinen Pointer
      return -1;
    }

    if (this.bufferedList.get(j).key == null) {
      for (;;) {
        // Wenn das nächste Array leer ist gehe zum n�chsten Array
        if (this.bufferedList.get(j).key != null) {
          break;
        }
        j = j * 2 + 1;

        if (j >= size) {
          return -1;
        } else {
          continue;
        }

      }
    }

    final int imax = j * 2;
    for (int i = j; i <= imax; i++) {
      if (key.compareTo(this.bufferedList.get(i).key) <= 0 || i == imax) {
        return i;
      }
    }
    return -1;
  }

  protected void merge(final FractalTreeEntry<K, V> element) {
    if (this.bufferedList.size() == 0) {
      this.bufferedList.add(0, element);
    } else if (this.bufferedList.get(0).key == null) {
      final FractalTreeEntry<K, V> tmp = element;
      tmp.pointer = this.calcPointer(0, tmp.key);
      this.bufferedList.set(0, tmp);
    } else {
      this.mergeList.add(element);
      this.merge(0);
    }
  }

  public void print2() {
    System.out.print("fractal list (" + this.bufferedList.size() + "): ");
    for (int i = 0; i < this.bufferedList.size(); i++) {
      System.out.print(this.bufferedList.get(i) + "| ");
    }
    System.out.println("");
  }

  public void print3() {
    System.out.print("remove list (" + this.removeList.size() + "): ");
    for (int i = 0; i < this.removeList.size(); i++) {
      System.out.print(this.removeList.get(i) + "| ");
    }
    System.out.println("");
  }

  public void printMergelist() {
    System.out.print("merge list: ");
    final int size = this.mergeList.size();
    for (int i = 0; i < size; i++) {
      System.out.print(this.mergeList.get(i) + "| ");
    }
    System.out.println("");
  }

  protected class MergeList {
    private final BufferedList_LuposSerialization<FractalTreeEntry<K, V>> diskMemory;
    private ArrayList<FractalTreeEntry<K, V>> mainMemory = new ArrayList<>();
    public int threshold = (int) (Math.pow(2, 10) - 1);

    public MergeList(final FractalTreeEntry<K, V> entry) {
      this.diskMemory = new BufferedList_LuposSerialization<FractalTreeEntry<K, V>>(8 * 1024, SimplifiedFractalTree.this.file2.getAbsoluteFile(), entry);
      this.mainMemory = new ArrayList<>();
    }

    public void setNoReturn(final int index, final FractalTreeEntry<K, V> fractalTreeEntry) {
      if (index < this.threshold) {
        this.mainMemory.set(index, fractalTreeEntry);
      } else {
        this.diskMemory.setNoReturn(index - this.threshold, fractalTreeEntry);
      }
    }

    public MergeList(final FractalTreeEntry<K, V> entry, final File file) {
      this.diskMemory = new BufferedList_LuposSerialization<>(8 * 1024, new File(file.getAbsolutePath() + "ml"), entry);
      this.mainMemory = new ArrayList<>();
    }

    public MergeList(final FractalTreeEntry<K, V> entry, final int pageSize) {
      this.diskMemory = new BufferedList_LuposSerialization<>(pageSize, SimplifiedFractalTree.this.file2.getAbsoluteFile(), entry);
      this.mainMemory = new ArrayList<>();
    }

    public MergeList(final FractalTreeEntry<K, V> entry, final int pageSize, final File file) {
      this.diskMemory = new BufferedList_LuposSerialization<>(pageSize, new File(file.getAbsolutePath() + "ml"), entry);
      this.mainMemory = new ArrayList<>();
    }

    public void clear() {
      this.diskMemory.clear();
      this.mainMemory.clear();
    }

    public FractalTreeEntry<K, V> set(final int index, final FractalTreeEntry<K, V> entry) {
      FractalTreeEntry<K, V> oldEntry = null;
      if (index < this.threshold) {
        oldEntry = this.mainMemory.get(index);
        this.mainMemory.set(index, entry);
      } else {
        oldEntry = this.diskMemory.set(index - this.threshold, entry);
      }
      return oldEntry;
    }

    public void add(final int index, final FractalTreeEntry<K, V> entry) {
      if (index < this.threshold) {
        this.mainMemory.add(index, entry);
      } else {
        this.diskMemory.add(index - this.threshold, entry);
      }
    }

    public void add(final FractalTreeEntry<K, V> entry) {
      if (this.mainMemory.size() < this.threshold) {
        this.mainMemory.add(entry);
      } else {
        this.diskMemory.add(entry);
      }
    }

    public FractalTreeEntry<K, V> get(final int index) {
      if (index < this.threshold) {
        return this.mainMemory.get(index);
      } else {
        return this.diskMemory.get(index - this.threshold);
      }
    }

    public int size() {
      return this.diskMemory.size() + this.mainMemory.size();
    }
  }

  public static void main(final String[] args) throws InterruptedException {

    final SimplifiedFractalTree<StringKey, Integer> fractalTree = new SimplifiedFractalTree<StringKey, Integer>(new File("fttest"));
    fractalTree.clear();
    fractalTree.put(new StringKey("T1"), 0);
    fractalTree.print2();
    fractalTree.put(new StringKey("T6"), 84);
    fractalTree.print2();
    fractalTree.put(new StringKey("T4"), 3);
    fractalTree.print2();
    fractalTree.put(new StringKey("T5"), -8);
    fractalTree.print2();
    fractalTree.put(new StringKey("T9"), 111);
    fractalTree.print2();
    fractalTree.put(new StringKey("T6"), 67);
    fractalTree.print2();
    fractalTree.put(new StringKey("T1"), 47);
    fractalTree.print2();
    fractalTree.put(new StringKey("T7"), 27);
    fractalTree.print2();
    fractalTree.put(new StringKey("T3"), 4);
    fractalTree.print2();
    fractalTree.put(new StringKey("T13"), 351);
    fractalTree.print2();
    fractalTree.put(new StringKey("T8"), 45);
    fractalTree.print2();
    fractalTree.put(new StringKey("T2"), 4);
    fractalTree.print2();
    fractalTree.put(new StringKey("T10"), -11);
    fractalTree.print2();
    fractalTree.put(new StringKey("T11"), -12);
    System.out.println("Search:");
    fractalTree.print2();
    System.out.println("T8:  "+ fractalTree.get(new StringKey("T8")));
    System.out.println("T2:  "+ fractalTree.get(new StringKey("T2")));
    System.out.println("T10: "+ fractalTree.get(new StringKey("T10")));
    System.out.println("T3:  "+ fractalTree.get(new StringKey("T3")));
    System.out.println("T6:  "+ fractalTree.get(new StringKey("T6")));
    System.out.println("T5:  "+ fractalTree.get(new StringKey("T5")));
    System.out.println("T9:  "+ fractalTree.get(new StringKey("T9")));
    System.out.println("Size:");
    System.out.println(fractalTree.size());
    System.out.println("Last Key:");
    System.out.println(fractalTree.lastKey());
    System.out.println("First Key:");
    System.out.println(fractalTree.firstKey());
    System.out.println("Empty?:");
    System.out.println(fractalTree.isEmpty());
    System.out.println("Contains key T6:");
    System.out.println(fractalTree.containsKey(new StringKey("T6")));
    System.out.println("Contains key T699:");
    System.out.println(fractalTree.containsKey(new StringKey("T699")));
    System.out.println("Prefix Search:");
    final Comparator<StringKey> comp = new Comparator<StringKey>() {

      @Override
      public int compare(final StringKey o1, final StringKey o2) {
        return o1.string.substring(0, 1).compareTo(o2.string.substring(0, 1));
      }
    };
    final StringKey prefix = new StringKey("T", comp);
    final Iterator<Integer> iterator = fractalTree.prefixSearch(prefix);
    for(;iterator.hasNext();){
      System.out.println(iterator.next());
    }
    System.out.println("Remove:");
    fractalTree.print2();
    System.out.println("T2:  "+ fractalTree.remove(new StringKey("T2")));
    fractalTree.print2();
    System.out.println("T1:  "+ fractalTree.remove(new StringKey("T1")));
    fractalTree.print2();
    System.out.println("T7:  "+ fractalTree.remove(new StringKey("T7")));
    fractalTree.print2();
    System.out.println("T5:  "+ fractalTree.remove(new StringKey("T5")));
    fractalTree.print2();
    System.out.println("T4:  "+ fractalTree.remove(new StringKey("T4")));
    fractalTree.print2();
    System.out.println("T3:  "+ fractalTree.remove(new StringKey("T3")));
    fractalTree.print2();
    System.out.println("T9:  "+ fractalTree.remove(new StringKey("T9")));
    fractalTree.print2();
    System.out.println("T6:  "+ fractalTree.remove(new StringKey("T6")));
    fractalTree.print2();
    System.out.println("T13:  "+ fractalTree.remove(new StringKey("T13")));
    fractalTree.print2();
    System.out.println("T8:  "+ fractalTree.remove(new StringKey("T8")));
    fractalTree.print2();
    System.out.println("T10:  "+ fractalTree.remove(new StringKey("T10")));
    fractalTree.print2();
  }
}
TOP

Related Classes of lupos.datastructures.simplifiedfractaltree.SimplifiedFractalTree$PrefixElement

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.