Advertisement
fireviper33

WordList

Apr 19th, 2017
254
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 12.00 KB | None | 0 0
  1. /**
  2.  * Doubly linked list of WordsEntry objects that is kept sorted by
  3.  * either frequency or alphabetically.
  4.  *
  5.  * @author ■. ■■■■■■■
  6.  * Last Modified: 19/4/17
  7.  */
  8. import java.util.Iterator;
  9. import java.util.NoSuchElementException;
  10.  
  11. public class WordList implements Iterable<WordEntry> {
  12.  
  13.     /** Size of the list */
  14.     private int size;
  15.  
  16.     /** If it is currently sorted by frequency */
  17.     private boolean isFrequencySorted;
  18.  
  19.     private WNode head;
  20.     private WNode tail;
  21.  
  22.     /**
  23.      * Construct an empty LinkedList of WordEntry objects
  24.      * @param isFrequencySorted If the list should be kept sorted by frequency
  25.      *        (true) or alphabetically (false).
  26.      */
  27.     public WordList(boolean isFrequencySorted) {
  28.         this.isFrequencySorted = isFrequencySorted;
  29.  
  30.         head = new WNode(null, null, null);
  31.         tail = new WNode(null, head, null);
  32.         head.next = tail;
  33.  
  34.         size = 0;
  35.     }
  36.  
  37.     /**
  38.      * Returns a String representation of the list's sorting order.
  39.      * @return "freq" if sorted by frequency, "alpha" otherwise
  40.      */
  41.     public String getSortType() {
  42.         return isFrequencySorted ? "freq":"alpha";
  43.     }
  44.  
  45.     /**
  46.      * Returns the number of items in this collection.
  47.      * @return the number of items in this collection.
  48.      */
  49.     public int size() {
  50.         return size;
  51.     }
  52.  
  53.     /**
  54.      * Add the String to the list
  55.      * Creates a new WordEntry for it if it is not already in the list,
  56.      * otherwise it increments the counter associated with the word.
  57.      *
  58.      * @param str String to add to the list
  59.      */
  60.     public void addWord(String str) {
  61.         WordEntry newWordEntry = new WordEntry(str);
  62.         boolean alreadyExists = false;
  63.         WNode curNode = head.next;
  64.         if (!isFrequencySorted){
  65.             while(curNode != tail && newWordEntry.compareByWord(curNode.entry) >= 0){
  66.                 /* Make sure that the curNode is not the tail
  67.                  * This loop also only advances if the newWordEntry object belongs on
  68.                  * the right side of the curNode.
  69.                  */
  70.                 if (newWordEntry.compareByWord(curNode.entry) == 0){
  71.                     /* Checks to see whether or not the newWordEntry word(str) is equal
  72.                      * to the curNode word. If they are equal it increments the count
  73.                      * on the already existing WordEntry.
  74.                      */
  75.                     curNode.entry.setCount(curNode.entry.getCount() + 1);
  76.                     alreadyExists = true;
  77.                 }
  78.                 curNode = curNode.next;      
  79.             }
  80.             if(!alreadyExists){
  81.                 /* If the newWordEntry hasn't updated the count on an existing word
  82.                  * the addBefore method is used to create a WNode and link it into
  83.                  * the WordList at the curNode position.
  84.                  */
  85.                 addBefore(curNode, newWordEntry);
  86.             }
  87.         }else if (isFrequencySorted){
  88.             WNode addOrUpdate = null;
  89.             while(curNode != tail && newWordEntry.compareByWord(curNode.entry) != 0){
  90.                 /* Changes the position in the WordList until curNode is equal to the tail
  91.                  * OR until the loop finds an equivalent WordEntry already existing in the list.
  92.                  */
  93.                 curNode = curNode.next;      
  94.             }
  95.             if (curNode != tail && newWordEntry.equals(curNode.entry)){
  96.                 /* If the curNode is not equal to the tail then it must mean newWordEntry
  97.                  * is equal to curNode.entry (there is a safety check)
  98.                  * This then updates the count and stores the WNode position in order
  99.                  * to bubble the WNode up or down the list to the correct frequency position.
  100.                  */
  101.                 curNode.entry.setCount(curNode.entry.getCount() + 1);
  102.                 alreadyExists = true;
  103.                 addOrUpdate = curNode;
  104.             }else {
  105.                 //curNode is equal to the tail so this creates a new WNode and adds to list
  106.                 addBefore(tail, newWordEntry);
  107.                 addOrUpdate = tail.prev;
  108.             }
  109.             while(addOrUpdate.prev != head &&
  110.                     addOrUpdate.entry.compareByFrequency(addOrUpdate.prev.entry) < 0){
  111.                 //Loop to bubble up or down the WNode of the addOrUpdate WNode to the correct
  112.                 //Position in the WordList
  113.                 swap(addOrUpdate.prev, addOrUpdate);
  114.             }
  115.         }
  116.  
  117.     }
  118.    
  119.     /**addBefore takes a WNode for position in WordList
  120.      * creates a new WNode containing the WordEntry
  121.      * updates the next and prev references for this new WNode
  122.      *
  123.      * @param pos WNode for the WordEntry to be added before
  124.      * @param w WordEntry to convert to new WNode
  125.      */
  126.     private void addBefore(WNode pos, WordEntry w) {
  127.         WNode newNode = new WNode(w, pos.prev, pos);
  128.         newNode.prev.next = newNode;
  129.         pos.prev = newNode;
  130.         size++;
  131.     }
  132.  
  133.     /**
  134.      * Swap two nodes in the list
  135.      *
  136.      * @param left Left node
  137.      * @param right Right node
  138.      */
  139.     private void swap(WNode left, WNode right) {
  140.         left.prev.next = right;
  141.         right.prev = left.prev;
  142.         left.next = right.next;
  143.         right.next.prev = left;
  144.         right.next = left;
  145.         left.prev = right;
  146.     }
  147.  
  148.     /**
  149.      * Search for the word specified
  150.      *
  151.      * @param str String to find
  152.      * @return The word entry found, or null if nothing is found
  153.      */
  154.     public WordEntry find(String str) {
  155.         WNode pos = head.next;
  156.         while (pos != tail) {
  157.             //if (pos.data == element) {
  158.             if (pos.entry.getWord().toLowerCase().equals(str)) {
  159.                 return pos.entry;
  160.             }
  161.             pos = pos.next;
  162.         }
  163.         return null;
  164.     }
  165.  
  166.  
  167.     /**
  168.      * Find all entries that start with the specified letter.
  169.      *
  170.      * @param c Letter to find
  171.      * @return List of words starting with the specified letter
  172.      */
  173.     public WordList findWordsStartingWith(char c) {
  174.         WNode curNode = head.next;
  175.         WordList wordsWith = new WordList(this.isFrequencySorted);
  176.         while (curNode != tail){
  177.             if(curNode.entry.getWord().charAt(0) == c){
  178.                 wordsWith.addBefore(wordsWith.tail, curNode.entry);
  179.             }
  180.             curNode = curNode.next;
  181.         }
  182.         return wordsWith;
  183.     }
  184.    
  185.     /**addFrequency adds a WordEntry object inserted into a WordList
  186.      * in a frequency sorted insertion
  187.      *
  188.      * Works only with fully counted WordEntry objects
  189.      *
  190.      * @param w WordEntry
  191.      */
  192.     private void addFrequency(WordEntry w){
  193.         WNode curNode = head.next;
  194.         while (curNode != tail && w.compareByFrequency(curNode.entry) > 0){
  195.             curNode = curNode.next;
  196.         }
  197.         addBefore(curNode, w);
  198.     }
  199.    
  200.     /**addAlphabetical adds a WordEntry object inserted into a WordList
  201.      * in an alphabetically sorted insertion
  202.      *
  203.      * Works only with fully counted WordEntry objects
  204.      *
  205.      * @param w WordEntry
  206.      */
  207.     private void addAlphabetical(WordEntry w){
  208.         WNode curNode = head.next;
  209.         while(curNode != tail && w.compareByWord(curNode.entry) >= 0){
  210.             curNode = curNode.next;      
  211.         }
  212.         addBefore(curNode, w);
  213.     }
  214.  
  215.     /**
  216.      * Find all entries with a given frequency
  217.      *
  218.      * @param freq Frequency to find
  219.      * @return List of matching words
  220.      */
  221.     public WordList findWordsAtFrequency(int freq) {
  222.         if (isFrequencySorted){
  223.             WNode curNode = head.next;
  224.             WordList wordsWith = new WordList(this.isFrequencySorted);
  225.             while (curNode.entry.getCount() >= freq){
  226.                 if(curNode.entry.getCount() == freq){
  227.                     wordsWith.addBefore(wordsWith.tail, curNode.entry);
  228.                 }
  229.                 curNode = curNode.next;
  230.             }
  231.             return wordsWith;
  232.         }else {
  233.             WNode curNode = head.next;
  234.             WordList wordsWith = new WordList(this.isFrequencySorted);
  235.             while (curNode != tail){
  236.                 if(curNode.entry.getCount() == freq){
  237.                     wordsWith.addBefore(wordsWith.tail, curNode.entry);
  238.                 }
  239.                 curNode = curNode.next;
  240.             }
  241.             return wordsWith;
  242.         }
  243.     }
  244.  
  245.     /**
  246.      * Get the first N most frequently occurring words
  247.      *
  248.      * @param n Number of words
  249.      * @return List of most frequent words
  250.      */
  251.     public WordList getMostFrequentlyUsed(int n) {
  252.         if (isFrequencySorted){//WordList is sorted by Frequency
  253.             WNode curNode = head.next;
  254.             int count = 0;
  255.             WordList wordsWith = new WordList(this.isFrequencySorted);
  256.             while (count < n){
  257.                 /* Find the n Most Frequent words in list since it is frequency sorted
  258.                  * We can take the first n items from our list
  259.                  */
  260.                 wordsWith.addBefore(wordsWith.tail, curNode.entry);
  261.  
  262.                 curNode = curNode.next;
  263.                 count++;
  264.             }
  265.             return wordsWith;
  266.         }else {//WordList is sorted alphabetically
  267.             WordList toFreq = new WordList(this.isFrequencySorted);
  268.             WNode curNode = head.next;
  269.             while (curNode != tail){
  270.                 //Loop converts alphabetically sorted list to frequency sorted
  271.                 toFreq.addFrequency(curNode.entry);
  272.                 curNode = curNode.next;
  273.             }
  274.             curNode = toFreq.head.next;
  275.             int count = 0;
  276.             WordList nMostFreq = new WordList(this.isFrequencySorted);
  277.             while (count < n){
  278.                 /* Find the n Most Frequent words in list since it is frequency sorted
  279.                  * We can take the first n items from our list
  280.                  */
  281.                 nMostFreq.addBefore(nMostFreq.tail, curNode.entry);
  282.  
  283.                 curNode = curNode.next;
  284.                 count++;
  285.             }
  286.             WordList backToAlpha = new WordList(this.isFrequencySorted);
  287.             curNode = nMostFreq.head.next;
  288.             while (curNode != nMostFreq.tail){
  289.                 /* Loop converts frequency sorted list of n Most Frequent back to
  290.                  * an Alphabetically sorted WordList
  291.                  */
  292.                 backToAlpha.addAlphabetical(curNode.entry);
  293.                 curNode = curNode.next;
  294.             }
  295.             return backToAlpha;
  296.         }
  297.     }
  298.  
  299.     /**
  300.      * Get the N least frequently occurring words
  301.      *
  302.      * @param n Number of words
  303.      * @return List of least frequent words
  304.      */
  305.     public WordList getLeastFrequentlyUsed(int n) {
  306.         if (isFrequencySorted){//Word list is sorted by frequency
  307.             WNode curNode = tail.prev;
  308.             int count = 0;
  309.             WordList wordsWith = new WordList(this.isFrequencySorted);
  310.             while (count < n){
  311.                 wordsWith.addBefore(wordsWith.head.next, curNode.entry);
  312.                 curNode = curNode.prev;
  313.                 count++;
  314.             }
  315.             return wordsWith;
  316.         }else {//WordList is sorted alphabetically
  317.             WordList toFreq = new WordList(this.isFrequencySorted);
  318.             WNode curNode = head.next;
  319.             while (curNode != tail){
  320.                 //Loop converts alphabetically sorted list to frequency sorted
  321.                 toFreq.addFrequency(curNode.entry);
  322.                 curNode = curNode.next;
  323.             }
  324.             curNode = toFreq.tail.prev;
  325.             int count = 0;
  326.             WordList nLeastFreq = new WordList(this.isFrequencySorted);
  327.             while (count < n){
  328.                 /* Find the n Least Frequent words in list since it is frequency sorted
  329.                  * We can take the first n items from our list
  330.                  */
  331.                 nLeastFreq.addBefore(nLeastFreq.tail, curNode.entry);
  332.                 curNode = curNode.prev;
  333.                 count++;
  334.             }
  335.             WordList backToAlpha = new WordList(this.isFrequencySorted);
  336.             curNode = nLeastFreq.head.next;
  337.             while (curNode != nLeastFreq.tail){
  338.                 /* Loop converts frequency sorted list of n Least Frequent back to
  339.                  * an Alphabetically sorted WordList
  340.                  */
  341.                 backToAlpha.addAlphabetical(curNode.entry);
  342.                 curNode = curNode.next;
  343.             }
  344.             return backToAlpha;
  345.         }
  346.     }
  347.  
  348.     /**
  349.      * Overrides object version so that this list can be printed.
  350.      */
  351.     public String toString() {
  352.         if (head.next == tail) {
  353.             return "()";
  354.         }
  355.  
  356.         String listContents = "(\n";
  357.         WNode pos = head.next;
  358.         while (pos.next != tail) {
  359.             listContents += "    " + pos.entry.toString() + "\n";
  360.             pos = pos.next;
  361.         }
  362.         // make sure that last thing in list gets added
  363.         // without a comma after it's occurrence
  364.         listContents += "    " + pos.entry;
  365.         return listContents + "\n)";
  366.     }
  367.  
  368.     /**
  369.      * Method to allow outside classes to have access to list elements one by
  370.      * one for things like looping, by giving them an iterator that they can
  371.      * advance one element at a time.
  372.      *
  373.      * @see java.lang.Iterable#iterator()
  374.      * @return An iterator over this list.
  375.      */
  376.     public Iterator<WordEntry> iterator() {
  377.         return new WIterator();
  378.     }
  379.  
  380.     /**
  381.      * This is the list iterator.
  382.      */
  383.     private class WIterator implements Iterator<WordEntry> {
  384.  
  385.         private WNode pos;
  386.  
  387.         public WIterator(){
  388.             pos = head;
  389.         }
  390.  
  391.         /**
  392.          * @return true if the iterator has more content, false otherwise
  393.          */
  394.         public boolean hasNext() {
  395.             return (pos.next != tail);
  396.         }
  397.  
  398.         /**
  399.          * @return the next entry in the list
  400.          * @throws NoSuchElementException if no entries remain
  401.          */
  402.         public WordEntry next() {
  403.             if (!hasNext()){
  404.                 throw new NoSuchElementException("Nothing left");
  405.             }
  406.             pos = pos.next;
  407.             return pos.entry;
  408.         }
  409.     }
  410.  
  411.     /**
  412.      * This is the doubly-linked list node.
  413.      */
  414.     private class WNode {
  415.         WordEntry entry;
  416.         WNode prev;
  417.         WNode next;
  418.  
  419.         public WNode(WordEntry entry, WNode prev, WNode next){
  420.             this.entry = entry;
  421.             this.prev = prev;
  422.             this.next = next;
  423.         }
  424.     }
  425.  
  426. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement