Advertisement
vladimirVenkov

UnsortedList Implementation +

Jul 29th, 2018
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 59.65 KB | None | 0 0
  1. import java.io.*;
  2. import java.lang.reflect.Array;
  3. import java.util.*;
  4.  
  5. public class PlayerRanking {
  6.     private static HashMap<String, Data> playersByType = new HashMap<>();
  7.     private static List<Player> allPlayers = new ArrayList<>();
  8.     private static List<Player> playersByPosition = new UnsortedList<>();
  9.     private static  OutputWriter writer = new OutputWriter();
  10.  
  11.     public static void main(String[] args) {
  12.         InputReader reader = new InputReader();
  13.         String input = reader.readLine();
  14.         do {
  15.             if ("add".equals(input)) {
  16.                 String name = reader.readLine();
  17.                 String type = reader.readLine();
  18.                 int age = convert(reader.readLine());
  19.                 int position = convert(reader.readLine());
  20.                 addNewPlayer(name,type,age,position);
  21.  
  22.             } else if ("find".equals(input)) {
  23.                 String type = reader.readLine();
  24.                 find(type);
  25.  
  26.             } else if ("ranklist".equals(input)) {
  27.                 int start = convert(reader.readLine()) - 1;
  28.                 int end = convert(reader.readLine()) - 1;
  29.                 printRanklist(start, end);
  30.             }
  31.  
  32.             input = reader.readLine();
  33.         } while (!"end".equals(input));
  34.  
  35.         writer.close();
  36.     }
  37.  
  38.     private static void addNewPlayer(String name,String type,int age,int position) {
  39.         Player newPlayer = new Player(name, age, position);
  40.  
  41.         if (!playersByType.containsKey(type)) {
  42.             playersByType.put(type, new Data());
  43.         }
  44.         playersByType.get(type).add(newPlayer);
  45.         allPlayers.add(newPlayer);
  46.         writer.printLine("Added player " + name + " to position " + position);
  47.     }
  48.  
  49.     private static void find(String type) {
  50.         writer.print("Type " + type + ": ");
  51.         if (playersByType.containsKey(type)) {
  52.             if (!playersByType.get(type).isSorted) {
  53.                 playersByType.get(type).sortByNameThenAge();
  54.             }
  55.  
  56.             int limit = 5 < playersByType.get(type).getSize() ? 5 : playersByType.get(type).getSize();
  57.  
  58.             for (int index = 0; index < limit - 1; index++) {
  59.                 writer.print(playersByType.get(type).get(index).toString() + "; ");
  60.             }
  61.             writer.print(playersByType.get(type).get(limit - 1).toString());
  62.         }
  63.         writer.printLine();
  64.     }
  65.  
  66.     private static void printRanklist(int start, int end) {
  67.         if (playersByPosition.size() < allPlayers.size()) {
  68.             int index = playersByPosition.size();
  69.             while (index < allPlayers.size()) {
  70.                 Player playerToBeAdded = allPlayers.get(index);
  71.                 int position = playerToBeAdded.getPosition();
  72.                 if (position > index) {
  73.                     playersByPosition.add(playerToBeAdded);
  74.                 } else {
  75.                     playersByPosition.add(position - 1, playerToBeAdded);
  76.                 }
  77.                 index++;
  78.             }
  79.         }
  80.  
  81.         while (start < end) {
  82.             writer.print(start + 1 + ". " + playersByPosition.get(start).toString() + "; ");
  83.             start++;
  84.         }
  85.         writer.printLine(start + 1 + ". " + playersByPosition.get(start).toString());
  86.     }
  87.  
  88.     private static int convert(String s) {
  89.         int value = 0;
  90.         for (int i = 0; i < s.length(); i++) {
  91.             value = value * 10 + (s.charAt(i) - '0');
  92.         }
  93.         return value;
  94.     }
  95.  
  96.     static class Player implements Comparable<Player> {
  97.         private String name;
  98.         private int age;
  99.         private int position;
  100.  
  101.         Player(String name, int age, int position) {
  102.             this.name = name;
  103.             this.age = age;
  104.             this.position = position;
  105.         }
  106.  
  107.         String getName() {
  108.             return name;
  109.         }
  110.  
  111.         int getAge() {
  112.             return age;
  113.         }
  114.  
  115.         int getPosition() {
  116.             return this.position;
  117.         }
  118.  
  119.  
  120.         @Override
  121.         public String toString() {
  122.             return name + "(" + age + ")";
  123.         }
  124.  
  125.         @Override
  126.         public int compareTo(Player other) {
  127.             int result = getName().compareTo(other.getName());
  128.             if (result == 0) {
  129.                 result = Integer.compare(getAge(), other.getAge()) * -1;
  130.             }
  131.             return result;
  132.         }
  133.     }
  134.  
  135.     static class OutputWriter {
  136.         private final PrintWriter writer;
  137.  
  138.         OutputWriter() {
  139.             writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
  140.         }
  141.  
  142.         void print(Object... objects) {
  143.             for (int i = 0; i < objects.length; i++) {
  144.                 if (i != 0)
  145.                     writer.print(' ');
  146.                 writer.print(objects[i]);
  147.             }
  148.         }
  149.  
  150.         void printLine(Object... objects) {
  151.             print(objects);
  152.             writer.println();
  153.         }
  154.  
  155.         void close() {
  156.             writer.close();
  157.         }
  158.     }
  159.  
  160.     static class InputReader {
  161.         private InputStream stream;
  162.         private byte[] buf = new byte[1024];
  163.         private int curChar;
  164.         private int numChars;
  165.  
  166.         InputReader() {
  167.             this.stream = System.in;
  168.         }
  169.  
  170.         int read() {
  171.             if (numChars == -1)
  172.                 throw new InputMismatchException();
  173.             if (curChar >= numChars) {
  174.                 curChar = 0;
  175.                 try {
  176.                     numChars = stream.read(buf);
  177.                 } catch (IOException e) {
  178.                     throw new InputMismatchException();
  179.                 }
  180.                 if (numChars <= 0)
  181.                     return -1;
  182.             }
  183.             return buf[curChar++];
  184.         }
  185.  
  186.         int readInt() {
  187.             int c = read();
  188.             while (isSpaceChar(c)) {
  189.                 c = read();
  190.             }
  191.             int sgn = 1;
  192.             if (c == '-') {
  193.                 sgn = -1;
  194.                 c = read();
  195.             }
  196.             int res = 0;
  197.             do {
  198.                 if (c < '0' || c > '9') {
  199.                     throw new InputMismatchException();
  200.                 }
  201.                 res *= 10;
  202.                 res += c - '0';
  203.                 c = read();
  204.             } while (!isSpaceChar(c));
  205.             return res * sgn;
  206.         }
  207.  
  208.         long readLong() {
  209.             int c = read();
  210.             while (isSpaceChar(c)) {
  211.                 c = read();
  212.             }
  213.             int sgn = 1;
  214.             if (c == '-') {
  215.                 sgn = -1;
  216.                 c = read();
  217.             }
  218.             long res = 0;
  219.             do {
  220.                 if (c < '0' || c > '9') {
  221.                     throw new InputMismatchException();
  222.                 }
  223.                 res *= 10;
  224.                 res += c - '0';
  225.                 c = read();
  226.             } while (!isSpaceChar(c));
  227.             return res * sgn;
  228.         }
  229.  
  230.         double readDouble() {
  231.             int c = read();
  232.             while (isSpaceChar(c)) {
  233.                 c = read();
  234.             }
  235.             int sgn = 1;
  236.             if (c == '-') {
  237.                 sgn = -1;
  238.                 c = read();
  239.             }
  240.             double res = 0;
  241.             while (!isSpaceChar(c) && c != '.' && c != ',') {
  242.                 if (c == 'e' || c == 'E') {
  243.                     return res * Math.pow(10, readInt());
  244.                 }
  245.                 if (c < '0' || c > '9') {
  246.                     throw new InputMismatchException();
  247.                 }
  248.                 res *= 10;
  249.                 res += c - '0';
  250.                 c = read();
  251.             }
  252.             if (c == '.' || c == ',') {
  253.                 c = read();
  254.                 double m = 1;
  255.                 while (!isSpaceChar(c)) {
  256.                     if (c == 'e' || c == 'E') {
  257.                         return res * Math.pow(10, readInt());
  258.                     }
  259.                     if (c < '0' || c > '9') {
  260.                         throw new InputMismatchException();
  261.                     }
  262.                     m /= 10;
  263.                     res += (c - '0') * m;
  264.                     c = read();
  265.                 }
  266.             }
  267.             return res * sgn;
  268.         }
  269.  
  270.         String readLine() {
  271.             int c = read();
  272.             while (isSpaceChar(c))
  273.                 c = read();
  274.             StringBuilder res = new StringBuilder();
  275.             do {
  276.                 res.appendCodePoint(c);
  277.                 c = read();
  278.             } while (!isSpaceChar(c));
  279.             return res.toString();
  280.         }
  281.  
  282.         boolean isSpaceChar(int c) {
  283.             return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
  284.         }
  285.     }
  286.  
  287.     static class Data {
  288.         List<Player> players;
  289.         private int size;
  290.         boolean isSorted;
  291.  
  292.         Data() {
  293.             players = new ArrayList<>();
  294.             size = 0;
  295.             isSorted = false;
  296.         }
  297.  
  298.         public int getSize() {
  299.             return size;
  300.         }
  301.  
  302.         public Player get(int index) {
  303.             return players.get(index);
  304.         }
  305.  
  306.         public void add(Player player) {
  307.             players.add(player);
  308.             size++;
  309.             isSorted = false;
  310.         }
  311.  
  312.         public void add(int index, Player player) {
  313.             players.add(index, player);
  314.             size++;
  315.             isSorted = false;
  316.         }
  317.  
  318.         public void sortByNameThenAge() {
  319.             Collections.sort(players);
  320.             if (size > 30) {
  321.                 setSizeToFive();
  322.             }
  323.             isSorted = true;
  324.         }
  325.  
  326.         public void setSizeToFive() {
  327.             players.subList(5, players.size()).clear();
  328.             size = 5;
  329.         }
  330.     }
  331.     /**
  332.      * SortedList is an implementation of a {@link List}, backed by an AVL tree.
  333.      * Does not support any optional operations, with the exception of: {@code remove(int)},
  334.      * {@code remove(Object)}, {@code clear} and {@code add()}.
  335.      * <p>
  336.      * Performs all the main operations: {@code contains}, {@code add}, {@code remove} and {@code get}
  337.      * in time <i>O(log(n))</i>, where <i>n</i> is the number of elements in the list.
  338.      * <p>
  339.      * This implementation is not synchronised so if you need multi-threaded access then consider wrapping
  340.      * it using the {@link Collections#synchronizedList} method.
  341.      * <p>
  342.      * The iterators this list provides are <i>fail-fast</i>, so any structural
  343.      * modification, other than through the iterator itself, cause it to throw a
  344.      * {@link ConcurrentModificationException}.
  345.      *
  346.      * @author Mark Rhodes
  347.      * @version 1.2
  348.      * @see List
  349.      * @see Collection
  350.      * @see AbstractList
  351.      * @param <T> the type of element that this sorted list will store.
  352.      */
  353.     public static class SortedList<T> extends AbstractList<T> implements Serializable {
  354.  
  355.         private static final long serialVersionUID = -7115342129716877152L;
  356.  
  357.         //to be used as like a static var to get the next node's id..
  358.         private int NEXT_NODE_ID = Integer.MIN_VALUE;
  359.  
  360.         //the entry point into the data structure..
  361.         private Node root;
  362.  
  363.         //The comparator to use when comparing the list elements.
  364.         private final Comparator<? super T> comparator;
  365.  
  366.         /**
  367.          * Constructs a new, empty SortedList which sorts the elements
  368.          * according to the given {@code Comparator}.
  369.          *
  370.          * @param comparator the {@code Comparator} to sort the elements by.
  371.          */
  372.         public SortedList(Comparator<? super T> comparator){
  373.             this.comparator = comparator;
  374.         }
  375.  
  376.         /**
  377.          * Inserts the given object into this {code SortedList} at the appropriate
  378.          * location, so as to ensure that the elements in the list are kept in
  379.          * the order specified by the given {@code Comparator}.
  380.          * <p>
  381.          * This method only allows non-<code>null</code> values to be added, if the given
  382.          * object is <code>null</code>, the list remains unaltered and false returned.
  383.          *
  384.          * @param object the object to add.
  385.          * @return false when the given object is null and true otherwise.
  386.          */
  387.         @Override
  388.         public boolean add(T object){
  389.             boolean treeAltered = false;
  390.             if(object != null){
  391.                 //wrap the value in a node and add it..
  392.                 add(new Node(object)); //will ensure the modcount is increased..
  393.                 treeAltered = true;
  394.             }
  395.             return treeAltered;
  396.         }
  397.  
  398.         /**
  399.          * Add the given Node to this {@code SortedList}.
  400.          * <p>
  401.          * This method can be overridden by a subclass in order to change the definition of the {@code Node}s
  402.          * that this List will store.
  403.          * <p>
  404.          * This implementation uses the {@code Node#compareTo(Node)} method in order to ascertain where the
  405.          * given {@code Node} should be stored. It also increments the modCount for this list.
  406.          *
  407.          * @param toAdd the {@code Node} to add.
  408.          */
  409.         protected void add(Node toAdd){
  410.             if(root == null){ //simple case first..
  411.                 root = toAdd;
  412.  
  413.             } else { //non-null root case..
  414.                 Node current = root;
  415.                 while(current != null) { //should always break!
  416.                     int comparison = toAdd.compareTo(current);
  417.  
  418.                     if(comparison < 0){ //toAdd < node
  419.                         if(current.leftChild == null){
  420.                             current.setLeftChild(toAdd);
  421.                             break;
  422.                         } else {
  423.                             current = current.leftChild;
  424.                         }
  425.                     } else { //toAdd > node (equal should not be possible)
  426.                         if(current.rightChild == null){
  427.                             current.setRightChild(toAdd);
  428.                             break;
  429.                         } else {
  430.                             current = current.rightChild;
  431.                         }
  432.                     }
  433.                 }
  434.             }
  435.             modCount++; //see AbstractList#modCount, incrementing this allows for iterators to be fail-fast..
  436.         }
  437.  
  438.         /**
  439.          * Tests if this tree has exactly the same structure and values as the given one,
  440.          * should only be used for testing.
  441.          *
  442.          * @param other the {@code SortedList} to compare this to.
  443.          * @return true if and only if all this {@code SortedList} are structurally the same with
  444.          *              each node containing the same values.
  445.          */
  446.         boolean structurallyEqualTo(SortedList<T> other){
  447.             return (other == null) ? false : structurallyEqualTo(root, other.root);
  448.         }
  449.         private boolean structurallyEqualTo(Node currentThis, Node currentOther){
  450.             if(currentThis == null){
  451.                 if(currentOther == null){
  452.                     return true;
  453.                 }
  454.                 return false;
  455.             } else if(currentOther == null){
  456.                 return false;
  457.             }
  458.             return currentThis.value.equals(currentOther.value)
  459.                     && structurallyEqualTo(currentThis.leftChild, currentOther.leftChild)
  460.                     && structurallyEqualTo(currentThis.rightChild, currentOther.rightChild);
  461.         }
  462.  
  463.         /**
  464.          * Provides an {@code Iterator} which provides the elements of this {@code SortedList}
  465.          * in the order determined by the given {@code Comparator}.
  466.          * <p>
  467.          * This implementation allows the entire list to be iterated over in time <i>O(n)</i>,
  468.          * where <i>n</i> is the number of elements in the list.
  469.          *
  470.          * @return an {@code Iterator} which provides the elements of this {@code SortedList}
  471.          *         in the order determined by the given {@code Comparator}.
  472.          */
  473.         @Override
  474.         public Iterator<T> iterator(){
  475.             return new Itr();
  476.         }
  477.  
  478.         //Implementation of the Iterator interface that uses the successor method
  479.         //to improve speed - O(n) to iterator through list instead of O(n*long(n))..
  480.         private class Itr implements Iterator<T> {
  481.  
  482.             //the next node to show and it's index..
  483.             private Node nextNode = (isEmpty() ? null : findNodeAtIndex(0));
  484.             private int nextIndex = 0;
  485.  
  486.             //the last one returned..
  487.             private Node lastReturned = null;
  488.  
  489.             //the modCount that is expected by this iterator..
  490.             private int expectedModCount = modCount;
  491.  
  492.             @Override
  493.             public boolean hasNext() {
  494.                 return nextNode != null;
  495.             }
  496.  
  497.             @Override
  498.             public T next() {
  499.                 checkModCount();
  500.  
  501.                 if(nextNode == null){
  502.                     throw new NoSuchElementException();
  503.                 }
  504.  
  505.                 //update fields..
  506.                 lastReturned = nextNode;
  507.                 nextNode = nextNode.successor();
  508.                 nextIndex++;
  509.  
  510.                 return lastReturned.value;
  511.             }
  512.  
  513.             @Override
  514.             public void remove() {
  515.                 checkModCount();
  516.  
  517.                 if(lastReturned == null){
  518.                     throw new IllegalStateException();
  519.                 }
  520.  
  521.                 SortedList.this.remove(lastReturned);
  522.                 lastReturned = null;
  523.  
  524.                 //the nextNode could now be incorrect so need to get it again..
  525.                 nextIndex--;
  526.                 if(nextIndex < size()){ //check that a node with this index actually exists..
  527.                     nextNode = findNodeAtIndex(nextIndex);
  528.                 } else {
  529.                     nextNode = null;
  530.                 }
  531.  
  532.                 expectedModCount = modCount;
  533.             }
  534.  
  535.             //Checks if the expected modcount is what it's expected to be,
  536.             //throws ConcurrentModificationException..
  537.             private void checkModCount(){
  538.                 if(expectedModCount != modCount){
  539.                     throw new ConcurrentModificationException();
  540.                 }
  541.             }
  542.         }
  543.  
  544.         /**
  545.          * Returns the number of elements in this {@code SortedList}.
  546.          *
  547.          * @return the number of elements stored in this {@code SortedList}.
  548.          */
  549.         @Override
  550.         public int size(){
  551.             return (root == null) ? 0 : 1 + root.numChildren;
  552.         }
  553.  
  554.         /**
  555.          * Returns the root node of this {@code SortedList}, which is
  556.          * <code>null</code> in the case that this list is empty.
  557.          *
  558.          * @return the root node of this {@code SortedList}, which is
  559.          *         <code>null</code> in the case that this list is empty.
  560.          */
  561.         protected Node getRoot(){
  562.             return root;
  563.         }
  564.  
  565.         /**
  566.          * Returns whether or not the given object is present in this {@code SortedList}.
  567.          * The comparison check uses the {@code Object#equals(Object)} method and work
  568.          * under the assumption that the given <code>obj</code> must have type <code>T</code>
  569.          * to be equal to the elements in this {@code SortedList}.  Works in time
  570.          * <i>O(log(n))</i>, where <i>n</i> is the number of elements in the list.
  571.          *
  572.          * @param obj the object to check for.
  573.          * @return true if the given object is present in this {code SortedList}.
  574.          */
  575.         @SuppressWarnings("unchecked")
  576.         @Override
  577.         public boolean contains(Object obj){
  578.             return obj != null
  579.                     && !isEmpty()
  580.                     && findFirstNodeWithValue((T) obj) != null;
  581.         }
  582.  
  583.         //Returns the node representing the given value in the tree, which can be null if
  584.         //no such node exists..
  585.         private Node findFirstNodeWithValue(T value){
  586.             Node current = root;
  587.             while(current != null){
  588.                 //use the comparator on the values, rather than nodes..
  589.                 int comparison = comparator.compare(current.value, value);
  590.                 if(comparison == 0){
  591.                     //find the first such node..
  592.                     while(current.leftChild != null
  593.                             && comparator.compare(current.leftChild.value, value) == 0){
  594.                         current = current.leftChild;
  595.                     }
  596.                     break;
  597.                 } else if(comparison < 0){ //need to go right..
  598.                     current = current.rightChild;
  599.                 } else {
  600.                     current = current.leftChild;
  601.                 }
  602.             }
  603.             return current;
  604.         }
  605.  
  606.         /**
  607.          * Removes and returns the element at the given index in this {@code SortedList}.  Since the list
  608.          * is sorted this is the "index"-th smallest element, counting from 0-<i>n</i>-1.
  609.          * <p>
  610.          * For example, calling {@code remove(0)} will remove the smallest element in the list.
  611.          *
  612.          * @param index the index of the element to remove.
  613.          * @return the element which was removed from the list.
  614.          * @throws IllegalArgumentException in the case that the index is not a valid index.
  615.          */
  616.         @Override
  617.         public T remove(int index){
  618.             //get the node at the index, will throw an error if the node index doesn't exist..
  619.             Node nodeAtIndex = findNodeAtIndex(index);
  620.             remove(nodeAtIndex);
  621.             return nodeAtIndex.value;
  622.         }
  623.  
  624.         /**
  625.          * Removes the first element in the list with the given value, if such
  626.          * a node exists, otherwise does nothing.  Comparisons
  627.          * on elements are done using the given comparator.
  628.          * <p>
  629.          * Returns whether or not a matching element was found and removed or not.
  630.          *
  631.          * @param value the object to remove from this {@code SortedList}.
  632.          * @return <code>true</code> if the given object was found in this
  633.          *         {@code SortedList} and removed, <code>false</code> otherwise.
  634.          */
  635.         @Override
  636.         public boolean remove(Object value){
  637.             boolean treeAltered = false;
  638.             try {
  639.                 if(value != null && root != null){
  640.                     @SuppressWarnings("unchecked")
  641.                     Node toRemove = findFirstNodeWithValue((T) value);
  642.                     if(toRemove != null){
  643.                         remove(toRemove);
  644.                         treeAltered = true;
  645.                     }
  646.                 }
  647.             } catch(ClassCastException e){
  648.                 //comparator may throw this error, don't need to do anything..
  649.             }
  650.             return treeAltered;
  651.         }
  652.  
  653.         //removes the given node from the tree, rebalancing if required, adds to modcount too..
  654.         private void remove(Node toRemove){
  655.             if(toRemove.isLeaf()){
  656.                 Node parent = toRemove.parent;
  657.                 if(parent == null){ //case where there is only one element in the list..
  658.                     root = null;
  659.                 } else {
  660.                     toRemove.detachFromParentIfLeaf();
  661.                 }
  662.             } else if(toRemove.hasTwoChildren()){ //interesting case..
  663.                 Node successor = toRemove.successor(); //will not be a non-null leaf or has one child!!
  664.  
  665.                 //switch the values of the nodes over, then delete the switched node..
  666.                 toRemove.switchValuesForThoseIn(successor);
  667.                 remove(successor); //will be one of the simpler cases.
  668.  
  669.             } else if(toRemove.leftChild != null){
  670.                 toRemove.leftChild.contractParent();
  671.             } else { //leftChild is null but right isn't..
  672.                 toRemove.rightChild.contractParent();
  673.             }
  674.             modCount++; //see AbstractList#modCount, incrementing this allows for iterators to be fail-fast..
  675.         }
  676.  
  677.         /**
  678.          * Returns the element at the given index in this {@code SortedList}.  Since the list is sorted,
  679.          * this is the "index"th smallest element, counting from 0-<i>n</i>-1.
  680.          * <p>
  681.          * For example, calling {@code get(0)} will return the smallest element in the list.
  682.          *
  683.          * @param index the index of the element to get.
  684.          * @return the element at the given index in this {@code SortedList}.
  685.          * @throws IllegalArgumentException in the case that the index is not a valid index.
  686.          */
  687.         @Override
  688.         public T get(int index){
  689.             return findNodeAtIndex(index).value;
  690.         }
  691.  
  692.         /**
  693.          * Returns the {@code Node} at the given index.
  694.          *
  695.          * @param index the index to search for.
  696.          * @return the {@code Node} object at the specified index.
  697.          *
  698.          * @throws IllegalArgumentException in the case that the the index is not valid.
  699.          */
  700.         protected Node findNodeAtIndex(int index){
  701.             if(index < 0 || index >= size()){
  702.                 throw new IllegalArgumentException(index + " is not valid index.");
  703.             }
  704.             Node current = root;
  705.             //the the number of smaller elements of the current node as we traverse the tree..
  706.             int totalSmallerElements = (current.leftChild == null) ? 0 : current.leftChild.sizeOfSubTree();
  707.             while(current!= null){  //should always break, due to constraint above..
  708.                 if(totalSmallerElements == index){
  709.                     break;
  710.                 }
  711.                 if(totalSmallerElements > index){ //go left..
  712.                     current = current.leftChild;
  713.                     totalSmallerElements--;
  714.                     totalSmallerElements -= (current.rightChild == null) ? 0 : current.rightChild.sizeOfSubTree();
  715.                 } else { //go right..
  716.                     totalSmallerElements++;
  717.                     current = current.rightChild;
  718.                     totalSmallerElements += (current.leftChild == null) ? 0 : current.leftChild.sizeOfSubTree();
  719.                 }
  720.             }
  721.             return current;
  722.         }
  723.  
  724.         /**
  725.          * Returns whether or not the list contains any elements.
  726.          *
  727.          * @return {@code true} if the list has no element in it
  728.          *         and {@code false} otherwise.
  729.          */
  730.         @Override
  731.         public boolean isEmpty(){
  732.             return root == null;
  733.         }
  734.  
  735.         /**
  736.          * Removes all elements from the list, leaving it empty.
  737.          */
  738.         @Override
  739.         public void clear(){
  740.             root = null; //TF4GC.
  741.         }
  742.  
  743.         /**
  744.          * Returns a new array containing all the elements in this {@code SortedList}.
  745.          *
  746.          * @return an array representation of this list.
  747.          */
  748.         @Override
  749.         public Object[] toArray(){
  750.             Object[] array = new Object[size()];
  751.             int positionToInsert = 0;  //where the next element should be inserted..
  752.  
  753.             if(root != null){
  754.                 Node next = root.smallestNodeInSubTree(); //start with the smallest value.
  755.                 while(next != null){
  756.                     array[positionToInsert] = next.value;
  757.                     positionToInsert++;
  758.  
  759.                     next = next.successor();
  760.                 }
  761.             }
  762.             return array;
  763.         }
  764.  
  765.         /**
  766.          * Copies the elements in the {@code SortedList} to the given array if it is large
  767.          * enough to store them, otherwise it returns a new array of the same type with the
  768.          * elements in it.
  769.          * <p>
  770.          * If the length of the given array is larger than the size of this {@code SortedList}
  771.          * then, the elements in this list are put into the start of the given array and the
  772.          * rest of the array is left untouched.
  773.          *
  774.          * @return an array representation of this list.
  775.          * @throws ClassCastException in the case that the provided array can not hold
  776.          *            objects of this type stored in this {@code SortedList}.
  777.          */
  778.         @SuppressWarnings("unchecked")
  779.         @Override
  780.         public <E> E[] toArray(E[] holder){
  781.             int size = size();
  782.  
  783.             //if it's not big enough to the elements make a new array of the same type..
  784.             if(holder.length < size){
  785.                 Class<?> classOfE = holder.getClass().getComponentType();
  786.                 holder = (E[]) Array.newInstance(classOfE, size);
  787.             }
  788.             //populate the array..
  789.             Iterator<T> itr = iterator();
  790.             int posToAdd = 0;
  791.             while(itr.hasNext()){
  792.                 holder[posToAdd] = (E) itr.next();
  793.                 posToAdd++;
  794.             }
  795.             return holder;
  796.         }
  797.  
  798.         /**
  799.          * Returns the smallest balance factor across the entire list, this serves not other
  800.          * purpose other than for testing.
  801.          *
  802.          * @return the minimum of all balance factors for nodes in this tree, or 0 if this tree is empty.
  803.          */
  804.         int minBalanceFactor(){
  805.             int minBalanceFactor = 0;
  806.             Node current = root;
  807.             while(current != null){
  808.                 minBalanceFactor = Math.min(current.getBalanceFactor(), minBalanceFactor);
  809.                 current = current.successor();
  810.             }
  811.             return minBalanceFactor;
  812.         }
  813.  
  814.         /**
  815.          * Returns the largest balance factor across the entire list, this serves not other
  816.          * purpose other than for testing.
  817.          *
  818.          * @return the maximum of all balance factors for nodes in this tree, or 0 if this tree is empty.
  819.          */
  820.         int maxBalanceFactor(){
  821.             int maxBalanceFactor = 0;
  822.             Node current = root;
  823.             while(current != null){
  824.                 maxBalanceFactor = Math.max(current.getBalanceFactor(), maxBalanceFactor);
  825.                 current = current.successor();
  826.             }
  827.             return maxBalanceFactor;
  828.         }
  829.  
  830.         //Implementation of the AVL tree rebalancing starting at the startNode and working up the tree...
  831.         private void rebalanceTree(Node startNode){
  832.             Node current = startNode;
  833.             while(current!= null){
  834.                 //get the difference between the left and right subtrees at this point..
  835.                 int balanceFactor = current.getBalanceFactor();
  836.  
  837.                 if(balanceFactor == -2){ //the right side is higher than the left.
  838.                     if(current.rightChild.getBalanceFactor() == 1){ //need to do a double rotation..
  839.                         current.rightChild.leftChild.rightRotateAsPivot();
  840.                     }
  841.                     current.rightChild.leftRotateAsPivot();
  842.  
  843.                 } else if(balanceFactor == 2){ //left side higher than the right.
  844.                     if(current.leftChild.getBalanceFactor() == -1){ //need to do a double rotation..
  845.                         current.leftChild.rightChild.leftRotateAsPivot();
  846.                     }
  847.                     current.leftChild.rightRotateAsPivot();
  848.                 }
  849.  
  850.                 if(current.parent == null){ //the root may have changed so this needs to be updated..
  851.                     root = current;
  852.                     break;
  853.                 } else {
  854.                     //make the request go up the tree..
  855.                     current = current.parent;
  856.                 }
  857.             }
  858.         }
  859.  
  860.         /**
  861.          * Inner class used to represent positions in the tree. Each node stores a list of equal values,
  862.          * is aware of their children and parent nodes, the height of the subtree rooted at that point and
  863.          * the total number of children elements they have.
  864.          *
  865.          * @param T the value the node will store.
  866.          */
  867.         protected class Node implements Comparable<Node > {
  868.  
  869.             private T value; //the data value being stored at this node
  870.  
  871.             private Node leftChild;
  872.             private Node rightChild;
  873.             private Node parent;
  874.  
  875.             //The "cached" values used to speed up methods..
  876.             private int height;
  877.             private int numChildren;
  878.  
  879.             /**
  880.              * The unique id of this node: auto generated from the containing tree,
  881.              * the newer the node the higher this value.
  882.              */
  883.             protected final int id;
  884.  
  885.             /**
  886.              * Constructs a new Node which initially just stores the given value.
  887.              *
  888.              * @param t the value which this node will store.
  889.              */
  890.             protected Node(T t){
  891.                 this.value = t;
  892.                 this.id = NEXT_NODE_ID++;
  893.             }
  894.  
  895.             /**
  896.              * Returns whether or not this {@code Node} has two children.
  897.              *
  898.              * @return <code>true</code> if this node has two children and <code>false</code> otherwise.
  899.              */
  900.             protected boolean hasTwoChildren(){
  901.                 return leftChild != null && rightChild != null;
  902.             }
  903.  
  904.             //Removes this node if it's a leaf node and updates the number of children and heights in the tree..
  905.             private void detachFromParentIfLeaf(){
  906.                 if(!isLeaf() || parent == null){
  907.                     throw new RuntimeException("Call made to detachFromParentIfLeaf, but this is not a leaf node with a parent!");
  908.                 }
  909.                 if(isLeftChildOfParent()){
  910.                     parent.setLeftChild(null);
  911.                 } else {
  912.                     parent.setRightChild(null);
  913.                 }
  914.             }
  915.  
  916.             /**
  917.              * Returns the grand parent {@code Node} of this {@code Node}, which may be <code>null</code>.
  918.              *
  919.              * @return the grand parent of this node if there is one and <code>null</code> otherwise.
  920.              */
  921.             protected Node getGrandParent(){
  922.                 return (parent != null && parent.parent != null) ? parent.parent : null;
  923.             }
  924.  
  925.             //Moves this node up the tree one notch, updates values and rebalancing the tree..
  926.             private void contractParent(){
  927.                 if(parent == null || parent.hasTwoChildren()){
  928.                     throw new RuntimeException("Can not call contractParent on root node or when the parent has two children!");
  929.                 }
  930.                 Node grandParent = getGrandParent();
  931.                 if(grandParent != null){
  932.                     if(isLeftChildOfParent()){
  933.                         if(parent.isLeftChildOfParent()){
  934.                             grandParent.leftChild = this;
  935.                         } else {
  936.                             grandParent.rightChild = this;
  937.                         }
  938.                         parent = grandParent;
  939.                     } else {
  940.                         if(parent.isLeftChildOfParent()){
  941.                             grandParent.leftChild = this;
  942.                         } else {
  943.                             grandParent.rightChild = this;
  944.                         }
  945.                         parent = grandParent;
  946.                     }
  947.                 } else { //no grandparent..
  948.                     parent = null;
  949.                     root = this; //update root in case it's not done elsewhere..
  950.                 }
  951.  
  952.                 //finally clean up by updating values and rebalancing..
  953.                 updateCachedValues();
  954.                 rebalanceTree(this);
  955.             }
  956.  
  957.             /**
  958.              * Returns whether or not this not is the left child of its parent node; if this is the
  959.              * root node, then <code>false</code> is returned.
  960.              *
  961.              * @return <code>true</code> if this is the left child of its parent node
  962.              *         and <code>false</code> otherwise.
  963.              */
  964.             public boolean isLeftChildOfParent(){
  965.                 return parent != null && parent.leftChild == this;
  966.             }
  967.  
  968.             /**
  969.              * Returns whether or not this not is the right child of its parent node; if this is the
  970.              * root node, then <code>false</code> is returned.
  971.              *
  972.              * @return <code>true</code> if this is the right child of its parent node
  973.              *         and <code>false</code> otherwise.
  974.              */
  975.             public boolean isRightChildOfParent(){
  976.                 return parent != null && parent.rightChild == this;
  977.             }
  978.  
  979.             /**
  980.              * Returns the left child of this {@code Node}, which may be <code>null</code>.
  981.              *
  982.              * @return the left child of this {@code Node}, which may be <code>null</code>.
  983.              */
  984.             protected Node getLeftChild(){
  985.                 return leftChild;
  986.             }
  987.  
  988.             /**
  989.              * Returns the right child of this {@code Node}, which may be be <code>null</code>.
  990.              *
  991.              * @return the right child of this node, which may be <code>null</code>.
  992.              */
  993.             protected Node getRightChild(){
  994.                 return rightChild;
  995.             }
  996.  
  997.             /**
  998.              * Returns the parent {@code Node} of this node, which will be <code>null</code>
  999.              * in the case that this is the root {@code Node}.
  1000.              *
  1001.              * @return the parent node of this one.
  1002.              */
  1003.             protected Node getParent(){
  1004.                 return parent;
  1005.             }
  1006.  
  1007.             /**
  1008.              * Compares the value stored at this node with the value at the given node using
  1009.              * the comparator, if these values are equal it compares the nodes on their IDs;
  1010.              * older nodes considered to be smaller.
  1011.              *
  1012.              * @return if the comparator returns a non-zero number when comparing the values stored at
  1013.              *         this node and the given node, this number is returned, otherwise this node's id minus
  1014.              *         the given node's id is returned.
  1015.              */
  1016.             public int compareTo(Node other){
  1017.                 int comparison = comparator.compare(value, other.value);
  1018.                 return (comparison == 0) ? (id-other.id) : comparison;
  1019.             }
  1020.  
  1021.             /**
  1022.              * Finds and returns the smallest node in the tree rooted at this node.
  1023.              *
  1024.              * @return the smallest valued node in the tree rooted at this node, which maybe this node.
  1025.              */
  1026.             protected Node smallestNodeInSubTree(){
  1027.                 Node current = this;
  1028.                 while(current != null){
  1029.                     if(current.leftChild == null){
  1030.                         break;
  1031.                     } else {
  1032.                         current = current.leftChild;
  1033.                     }
  1034.                 }
  1035.                 return current;
  1036.             }
  1037.  
  1038.             /**
  1039.              * Finds the largest node in the tree rooted at this node.
  1040.              *
  1041.              * @return the largest valued node in the tree rooted at this node which may be this node.
  1042.              */
  1043.             protected Node largestNodeInSubTree(){
  1044.                 Node current = this;
  1045.                 while(current != null){
  1046.                     if(current.rightChild == null){
  1047.                         break;
  1048.                     } else {
  1049.                         current = current.rightChild;
  1050.                     }
  1051.                 }
  1052.                 return current;
  1053.             }
  1054.  
  1055.             /**
  1056.              * Gets the next biggest node in the tree, which is <code>null</code> if this is
  1057.              * the largest valued node.
  1058.              *
  1059.              * @return the next biggest node in the tree, which is <code>null</code> if this
  1060.              *         is the largest valued node.
  1061.              */
  1062.             protected Node successor(){
  1063.                 Node successor = null;
  1064.                 if(rightChild != null){
  1065.                     successor = rightChild.smallestNodeInSubTree();
  1066.                 } else if(parent != null){
  1067.                     Node current = this;
  1068.                     while(current != null && current.isRightChildOfParent()){
  1069.                         current = current.parent;
  1070.                     }
  1071.                     successor = current.parent;
  1072.                 }
  1073.                 return successor;
  1074.             }
  1075.  
  1076.             /**
  1077.              * Gets the node that is the next smallest in the tree, which is <code>null</code>
  1078.              * if this is the smallest valued node.
  1079.              *
  1080.              * @return the node that is the next smallest in the tree, which is <code>null</code>
  1081.              *         if this is the smallest valued node.
  1082.              */
  1083.             protected Node predecessor(){
  1084.                 Node predecessor = null;
  1085.                 if(leftChild != null){
  1086.                     predecessor = leftChild.largestNodeInSubTree();
  1087.                 } else if(parent != null){
  1088.                     Node current = this;
  1089.                     while(current != null && current.isLeftChildOfParent()){
  1090.                         current = current.parent;
  1091.                     }
  1092.                     predecessor = current.parent;
  1093.                 }
  1094.                 return predecessor;
  1095.             }
  1096.  
  1097.             //Sets the child node to the left/right, should only be used if the given node
  1098.             //is null or a leaf, and the current child is the same..
  1099.             private void setChild(boolean isLeft, Node leaf){
  1100.                 //perform the update..
  1101.                 if(leaf != null){
  1102.                     leaf.parent = this;
  1103.                 }
  1104.                 if(isLeft){
  1105.                     leftChild = leaf;
  1106.                 } else {
  1107.                     rightChild = leaf;
  1108.                 }
  1109.  
  1110.                 //make sure any change to the height of the tree is dealt with..
  1111.                 updateCachedValues();
  1112.                 rebalanceTree(this);
  1113.             }
  1114.  
  1115.             /**
  1116.              * Returns whether or not this {@code Node} is a leaf; this is true in the case that
  1117.              * both its left and right children are set to <code>null</code>.
  1118.              *
  1119.              * @return <code>true</code> if this node is leaf and <code>false</code> otherwise.
  1120.              */
  1121.             public boolean isLeaf(){
  1122.                 return (leftChild == null && rightChild == null);
  1123.             }
  1124.  
  1125.             /**
  1126.              * A (non-recursive) String representation of this {@code Node}.
  1127.              *
  1128.              * @return a {@code String} representing this {@code Node} for debugging.
  1129.              */
  1130.             @Override
  1131.             public String toString(){
  1132.                 StringBuffer sb = new StringBuffer();
  1133.                 sb.append("[Node: value: " + value);
  1134.                 sb.append(", leftChild value: " + ((leftChild == null) ? "null" : leftChild.value));
  1135.                 sb.append(", rightChild value: " + ((rightChild == null) ? "null" : rightChild.value));
  1136.                 sb.append(", height: " + height);
  1137.                 sb.append(", numChildren: " + numChildren + "]\n");
  1138.                 return sb.toString();
  1139.             }
  1140.  
  1141.             //performs a left rotation using this node as a pivot..
  1142.             private void leftRotateAsPivot(){
  1143.                 if(parent == null || parent.rightChild != this){
  1144.                     throw new RuntimeException("Can't left rotate as pivot has no valid parent node.");
  1145.                 }
  1146.  
  1147.                 //first move this node up the tree, detaching parent...
  1148.                 Node oldParent = parent;
  1149.                 Node grandParent = getGrandParent();
  1150.                 if(grandParent != null){
  1151.                     if(parent.isLeftChildOfParent()){
  1152.                         grandParent.leftChild = this;
  1153.                     } else {
  1154.                         grandParent.rightChild = this;
  1155.                     }
  1156.                 }
  1157.                 this.parent = grandParent; //could be null.
  1158.  
  1159.                 //now make old parent left child and put old left child as right child of parent..
  1160.                 Node oldLeftChild = leftChild;
  1161.                 oldParent.parent = this;
  1162.                 leftChild = oldParent;
  1163.                 if(oldLeftChild != null){
  1164.                     oldLeftChild.parent = oldParent;
  1165.                 }
  1166.                 oldParent.rightChild = oldLeftChild;
  1167.  
  1168.                 //now we need to update the values for height and number of children..
  1169.                 oldParent.updateCachedValues();
  1170.             }
  1171.  
  1172.             /**
  1173.              * Returns, the number of children of this {@code Node} plus one.  This method uses
  1174.              * a cached variable ensuring it runs in constant time.
  1175.              *
  1176.              * @return the number of children of this {@code Node} plus one.
  1177.              */
  1178.             public int sizeOfSubTree(){
  1179.                 return 1 + numChildren;
  1180.             }
  1181.  
  1182.             /**
  1183.              * Returns the value stored at this {@code Node}.
  1184.              *
  1185.              * @return the value that this {@code Node} stores.
  1186.              */
  1187.             public T getValue(){
  1188.                 return value;
  1189.             }
  1190.  
  1191.             //performs a left rotation using this node as a pivot..
  1192.             private void rightRotateAsPivot(){
  1193.                 if(parent == null || parent.leftChild != this){
  1194.                     throw new RuntimeException("Can't right rotate as pivot has no valid parent node.");
  1195.                 }
  1196.                 //first move this node up the tree, detaching parent...
  1197.                 Node oldParent = parent;
  1198.                 Node grandParent = getGrandParent();
  1199.                 if(grandParent != null){
  1200.                     if(parent.isLeftChildOfParent()){
  1201.                         grandParent.leftChild = this;
  1202.                     } else {
  1203.                         grandParent.rightChild = this;
  1204.                     }
  1205.                 }
  1206.                 this.parent = grandParent; //could be null.
  1207.  
  1208.                 //now switch right child to left child of old parent..
  1209.                 oldParent.parent = this;
  1210.                 Node oldRightChild = rightChild;
  1211.                 rightChild = oldParent;
  1212.                 if(oldRightChild != null){
  1213.                     oldRightChild.parent = oldParent;
  1214.                 }
  1215.                 oldParent.leftChild = oldRightChild;
  1216.  
  1217.                 //now we need to update the values for height and number of children..
  1218.                 oldParent.updateCachedValues();
  1219.             }
  1220.  
  1221.             //updates the height and the number of children for nodes on the path to this..
  1222.             private void updateCachedValues(){
  1223.                 Node current = this;
  1224.                 while(current != null){
  1225.                     if(current.isLeaf()){
  1226.                         current.height = 0;
  1227.                         current.numChildren = 0;
  1228.                     } else {
  1229.                         //deal with the height..
  1230.                         int leftTreeHeight = (current.leftChild == null) ? 0 : current.leftChild.height;
  1231.                         int rightTreeHeight = (current.rightChild == null) ? 0 : current.rightChild.height;
  1232.                         current.height = 1 + Math.max(leftTreeHeight, rightTreeHeight);
  1233.  
  1234.                         //deal with the number of children..
  1235.                         int leftTreeSize = (current.leftChild == null) ? 0 : current.leftChild.sizeOfSubTree();
  1236.                         int rightTreeSize = (current.rightChild == null) ? 0 : current.rightChild.sizeOfSubTree();
  1237.                         current.numChildren = leftTreeSize + rightTreeSize;
  1238.                     }
  1239.                     //propagate up the tree..
  1240.                     current = current.parent;
  1241.                 }
  1242.             }
  1243.  
  1244.             //Just replaces the values this this node with those in other
  1245.             //and updates the number of children in the tree..
  1246.             //should only be called when this is doing to be removed and has just one value..
  1247.             private void switchValuesForThoseIn(Node other){
  1248.                 this.value = other.value;  //switch the values over, nothing else need change..
  1249.             }
  1250.  
  1251.             //returns (height of the left subtree - the right of the right subtree)..
  1252.             private int getBalanceFactor(){
  1253.                 return ((leftChild == null) ? 0 : leftChild.height + 1) -
  1254.                         ((rightChild == null) ? 0 : rightChild.height + 1);
  1255.             }
  1256.  
  1257.             //Sets the left child node.
  1258.             private void setLeftChild(Node leaf){
  1259.                 if((leaf != null && !leaf.isLeaf()) || (leftChild != null && !leftChild.isLeaf())){
  1260.                     throw new RuntimeException("setLeftChild should only be called with null or a leaf node, to replace a likewise child node.");
  1261.                 }
  1262.                 setChild(true, leaf);
  1263.             }
  1264.  
  1265.             //Sets the right child node.
  1266.             private void setRightChild(Node leaf){
  1267.                 if((leaf != null && !leaf.isLeaf()) || (rightChild != null && !rightChild.isLeaf())){
  1268.                     throw new RuntimeException("setRightChild should only be called with null or a leaf node, to replace a likewise child node.");
  1269.                 }
  1270.                 setChild(false, leaf);
  1271.             }
  1272.         } //End of inner class: Node.
  1273.  
  1274.     }
  1275.  
  1276.     /**
  1277.      * Implementation of a regular list that uses an AVL tree.  Supports
  1278.      * all optional operations.
  1279.      * <p>
  1280.      * Performs the operations: {@code #add(int, Object)}, {@code get} and {@code #remove(int)} operations in
  1281.      * in time <i>O(log(n))</i> and
  1282.      * the {@code #contains(Object)} and {@link #remove(Object)} operations in time <i>O(n)</i>,
  1283.      * where <i>n</i> is the number of elements in the list.
  1284.      * <p>
  1285.      * This implementation is not synchronised so if you need multi-threaded access then consider wrapping
  1286.      * it using the {@link Collections#synchronizedList} method.
  1287.      * <p>
  1288.      * The iterators this list provides are <i>fail-fast</i>, so any structural
  1289.      * modification, other than through the iterator itself, cause it to throw a
  1290.      * {@link ConcurrentModificationException}.
  1291.      *
  1292.      * @author Mark Rhodes
  1293.      * @version 1.0
  1294.      * @see Collection
  1295.      * @see AbstractList
  1296.      * @param <T> the type of element that this sorted list will store.
  1297.      */
  1298.     public static class UnsortedList<T> extends SortedList<T> {
  1299.  
  1300.         private static final long serialVersionUID = 6720718365032108011L;
  1301.  
  1302.         //a dummy comparator which works on any object and simply returns 0..
  1303.         private static Comparator<Object> DUMMY_COMPARATOR = new Comparator<Object>(){
  1304.             @Override
  1305.             public int compare(Object a, Object b){
  1306.                 return 0;
  1307.             }
  1308.         };
  1309.  
  1310.         /**
  1311.          * Constructs a new {@code UnsortedList}.
  1312.          */
  1313.         public UnsortedList(){
  1314.             super(DUMMY_COMPARATOR);
  1315.         }
  1316.  
  1317.         /**
  1318.          * Replaces the element at the specified position in this list with the specified element.
  1319.          *
  1320.          * @param index the index in this {@code UnsortedList} to add this given element.
  1321.          * @param element the object to add to this {@code UnsortedList}.
  1322.          * @return the element that was replaced at the given index.
  1323.          * @throws IllegalArgumentException in the case that the element is <code>null</code>.
  1324.          * @throws IndexOutOfBoundsException in the case that (0 <= index < size()) does not hold.
  1325.          */
  1326.         @Override
  1327.         public T set(int index, T element){
  1328.             T removed = remove(index);
  1329.             add(index, element);
  1330.             return removed;
  1331.         }
  1332.  
  1333.         /**
  1334.          * Returns whether or not the given object whether or not the given object is present
  1335.          * in this {@code UnsortedList}.
  1336.          * <p>
  1337.          * This implementation takes <i>O(n)</i> time, where <i>n</i> is the number of element in this list.
  1338.          *
  1339.          * @return <code>true</code> if the given object is present in this {@code UnsortedList}
  1340.          *         and <code>false</code> otherwise.
  1341.          */
  1342.         @Override
  1343.         public boolean contains(Object obj){
  1344.             boolean found = false;
  1345.             Iterator<T> itr = iterator();
  1346.             while(itr.hasNext()){
  1347.                 if(itr.next().equals(obj)){
  1348.                     found = true;
  1349.                     break;
  1350.                 }
  1351.             }
  1352.             return found;
  1353.         }
  1354.  
  1355.         /**
  1356.          * Removes the first element in the list with the given value, if such
  1357.          * a node exists, otherwise does nothing.  Works in time <i>O(n)</i>, where
  1358.          * <i>i</i> is the number of elements in this {@code UnsortedList}.
  1359.          * <p>
  1360.          * Returns whether or not a matching element was found and removed or not.
  1361.          *
  1362.          * @param value the object to remove from this {@code SortedList}.
  1363.          * @return <code>true</code> if the given object was found in this
  1364.          *         {@code SortedList} and removed, <code>false</code> otherwise.
  1365.          */
  1366.         @Override
  1367.         public boolean remove(Object value){
  1368.             boolean treeAltered = false;
  1369.             int size = size();
  1370.             for(int i = 0; i < size; i++){
  1371.                 Node nodeAtIndex = findNodeAtIndex(i);
  1372.                 if(nodeAtIndex.getValue().equals(value)){ //nulls not allowed in the list, so don't need to deal with that case.
  1373.                     remove(nodeAtIndex);
  1374.                     treeAltered = true;
  1375.                     modCount++;
  1376.                     break;
  1377.                 }
  1378.             }
  1379.             return treeAltered;
  1380.         }
  1381.  
  1382.         /**
  1383.          * Inserts the specified element at the specified position in this list. Shifts the element currently
  1384.          * at that position (if any) and any subsequent elements to the right (adds one to their indices).
  1385.          * <p>
  1386.          * Works in time <i>O(log(n))</i>, where <i>n</i> is the number of elements in the list.
  1387.          *
  1388.          * @param index at which the element should be added.
  1389.          * @param element the object to by inserted.
  1390.          * @throws IllegalArgumentException in the case that the given element is null.
  1391.          * @throws IndexOutOfBoundsException in the case that (0 <= index <= size()) does not hold.
  1392.          */
  1393.         @Override
  1394.         public void add(int index, T element){
  1395.             if(element == null){
  1396.                 throw new IllegalArgumentException("Null elements can  not be added to UnsortedLists.");
  1397.             }
  1398.             UnsortedNode toAdd = new UnsortedNode(element, index);
  1399.             add(toAdd);  //uses the #add(Node) method of the super class..
  1400.         }
  1401.  
  1402.         /**
  1403.          * Adds the given element to the head of this list. Shifts the elements currently
  1404.          * in the list (if any) to the right (adds one to their indices).
  1405.          * <p>
  1406.          * Works in time <i>O(log(n))</i>, where <i>n</i> is the number of elements in the list.
  1407.          *
  1408.          * @param element the object to by inserted.
  1409.          * @throws IllegalArgumentException in the case that the given element is null.
  1410.          */
  1411.         public void addToHead(T element){
  1412.             add(0, element);
  1413.         }
  1414.  
  1415.         /**
  1416.          * Adds the given object to the end of this {@code UnsortedList}, which can be
  1417.          * <code>null</code>.
  1418.          *
  1419.          * @param object the object to add.
  1420.          * @return <code>true</code>.
  1421.          */
  1422.         @Override
  1423.         public boolean add(T object){
  1424.             add(new UnsortedNode(object, size())); //uses the #add(Node) method of the super class..
  1425.             return true;
  1426.         }
  1427.  
  1428.         /**
  1429.          * Class representing the individual nodes of an unsorted list
  1430.          * extends the regular SortedList.Node class by storing the
  1431.          * position of the node in the tree.
  1432.          */
  1433.         private class UnsortedNode extends Node {
  1434.  
  1435.             //"cached" index of this node in the list and the modCount when it was set..
  1436.             private int indexInList;
  1437.             private int modCountWhenIndexSet;
  1438.  
  1439.             //Constructs a new Node object which should be positioned at the
  1440.             //given index when inserted into the tree..
  1441.             UnsortedNode(T obj, int initialIndex){
  1442.                 super(obj);
  1443.                 indexInList = initialIndex;
  1444.                 modCountWhenIndexSet = modCount;
  1445.             }
  1446.  
  1447.             /**
  1448.              * Gets the index of this node in the list, using the cached value if it is not
  1449.              * stale and otherwise calculating it from the ancestor nodes and setting the cached value.
  1450.              */
  1451.             @SuppressWarnings("unchecked")
  1452.             private int getIndexInList(){
  1453.                 //go up the tree till we find a fresh parent or get to the root and store the path on a stack..
  1454.                 LinkedList<UnsortedNode> path = new LinkedList<UnsortedNode>();
  1455.                 UnsortedNode current = this;
  1456.                 while(current != null && current.modCountWhenIndexSet != modCount){
  1457.                     path.push(current);
  1458.                     current = (UnsortedNode) current.getParent();
  1459.                 }
  1460.  
  1461.                 //pop elements off the stack updating them as you go..
  1462.                 while(!path.isEmpty()){
  1463.                     current = path.pop();
  1464.                     UnsortedNode parent = (UnsortedNode) current.getParent(); //this parent can only be fresh or null..
  1465.                     if(parent == null){ //root case..
  1466.                         Node leftChild = current.getLeftChild();
  1467.                         current.indexInList = (leftChild == null) ? 0 : leftChild.sizeOfSubTree();
  1468.                     } else { //non-root case..
  1469.                         if(current.isLeftChildOfParent()){
  1470.                             Node rightChild = current.getRightChild();
  1471.                             current.indexInList = parent.indexInList - (rightChild == null ? 1 : 1 + rightChild.sizeOfSubTree());
  1472.                         } else { //current is right child of parent case..
  1473.                             Node leftChild = current.getLeftChild();
  1474.                             current.indexInList = parent.indexInList + (leftChild == null ? 1 : 1 + leftChild.sizeOfSubTree());
  1475.                         }
  1476.                     }
  1477.                     //register it as being fresh..
  1478.                     current.modCountWhenIndexSet = modCount;
  1479.                 }
  1480.  
  1481.                 //on the last iteration of the above loop this is set correctly..
  1482.                 return indexInList;
  1483.             }
  1484.  
  1485.             //Determines whether this node is actually in the tree already..
  1486.             private boolean isInTree(){
  1487.                 return getParent() != null || getRoot() == this;
  1488.             }
  1489.  
  1490.             /**
  1491.              * Compares this node with the given node - which must be an {@code UnsortedNode} instance
  1492.              * in the same {@code UnsortedList}.  The comparison is based on the current position
  1493.              * of the nodes in the list.
  1494.              * <p>
  1495.              * Nodes with equal indices are compared on whether they are in the tree yet or not; those
  1496.              * in the tree are considered to be larger.
  1497.              *
  1498.              *
  1499.              * @return the index of this node in the list minus the index of the given node in the list.
  1500.              */
  1501.             @SuppressWarnings("unchecked")
  1502.             public int compareTo(Node other){
  1503.                 UnsortedNode otherUS = (UnsortedNode) other;
  1504.                 int cmp = getIndexInList() - otherUS.getIndexInList();
  1505.                 if(cmp == 0){ //indices are equal..
  1506.                     if(isInTree()){
  1507.                         if(!otherUS.isInTree()){
  1508.                             cmp = 1; //treat this as larger..
  1509.                         }
  1510.                     } else {
  1511.                         if(otherUS.isInTree()){
  1512.                             cmp = -1; //treat this as smaller..
  1513.                         }
  1514.                     }
  1515.                 }
  1516.                 return cmp;
  1517.             }
  1518.         }
  1519.     }
  1520. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement