Checking if elements are already in a Java array - java

The project I am working on right now involves me reading words from a text file and loading them into an array (and eventually a binary tree, but that will be finished later). I must load both the word and the word's frequency (initially 1) into the array, so I have packed both variables into an object WordNode. I am able to load the words into the array, but things fall apart when I try to check if a word is already in the array. If it is, I must increase the frequency by 1. However, my code does not even check the word and simply adds it anyway (I presume it's checking the reference to the variable and not the word itself). Below is my main method and the WordNode class.
Main method:
public class Driver {
/////////////// fields ///////////////
public static ArrayUnorderedList<WordNode> wordArray = new ArrayUnorderedList<WordNode>();
public static LinkedBinarySearchTree<WordNode> wordTree = new LinkedBinarySearchTree<WordNode>(); //tree to hold words
/////////////// methods ///////////////
public static void main(String[] args) throws Exception {
//ask for filename
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Enter the name of the file to read from: ");
Reader file = new FileReader(reader.readLine());
//read file
Scanner input = new Scanner(file);
while(input.hasNext()) {
//get words from file
String word = input.next();
//remove non-word characters and convert to lowercase
word = word.replaceAll("\\W", "");
word = word.toLowerCase();
//create node
WordNode newWord = new WordNode(word);
//if word is already in array
if(wordArray.contains(newWord)) {
System.out.println("Word is already in array");
//increment frequency by 1
int index = wordArray.find(newWord);
wordArray.list[index].setFrequency(wordArray.list[index].getFrequency() + 1);
System.out.println(newWord.getWord() + newWord.getFrequency());
} else {
System.out.println("Word is not yet in array");
//add word to tree
System.out.println(newWord.getWord());
wordArray.addToRear(newWord);
}
}
//insert into tree
//perform traversals on tree
}
WordNode class:
public class WordNode {
protected String word;
protected WordNode left, right;
protected int frequency;
/**
* Creates a new node with the specified data.
* #param obj the element that will become a part of the new node
*/
WordNode(String obj) {
word = obj;
left = null;
right = null;
frequency = 1;
}
/**
* Gets the word.
* #return the word
*/
public String getWord() {
return word;
}
/**
* Sets the word.
* #param word the word to set
*/
public void setWord(String word) {
this.word = word;
}
/**
* Gets the left.
* #return the left
*/
public WordNode getLeft() {
return left;
}
/**
* Sets the left.
* #param left the left to set
*/
public void setLeft(WordNode left) {
this.left = left;
}
/**
* Gets the right.
* #return the right
*/
public WordNode getRight() {
return right;
}
/**
* Sets the right.
* #param right the right to set
*/
public void setRight(WordNode right) {
this.right = right;
}
/**
* Gets the frequency.
* #return the frequency
*/
public int getFrequency() {
return frequency;
}
/**
* Sets the frequency.
* #param frequency the frequency to set
*/
public void setFrequency(int frequency) {
this.frequency = frequency;
}
}
Some methods from the ArrayList class:
/**
* Returns true if this list contains the specified element.
* #param target the element that the list is searched for
* #return true if the target is in the list, false if otherwise
*/
public boolean contains(T target) {
return (find(target) != NOT_FOUND);
}
/**
* Returns the array index of the specified element, or the
* constant NOT_FOUND if it is not found.
* #param target the element that the list will be searched for
* #return the integer index into the array containing the target element, or the NOT_FOUND constant
*/
public int find(T target) {
int scan = 0, result = NOT_FOUND;
boolean found = false;
if (!isEmpty()) {
while (!found && scan < rear) {
if (target.equals(list[scan])) {
found = true;
} else {
scan++;
}
}
}
if (found) {
result = scan;
}
return result;
}

The immediate reason your code doesn't work is that ArrayUnorderedList#contains() probably relies on the equals() method to determine if the entry is in the list. Without seeing the definition of the class it's impossible to know.
Since you haven't provided an override of equals(), it's using object identity (the default from Object) so every WordNode is distinct from every other WordNode.
If you want to use ArrayUnorderedList then you must implement WordNode#equals() with the correct behavior.
However, you should consider using a Map<String,Integer> (or Map<String,WordNode>) instead to store the frequencies. This will be much faster.

You need to override eqauls in your WordNode:
public boolean equals(Object o) {
if(o instanceof WordNode) {
WordNode temp = (WordNode) o;
return(temp.getWord().equals(this.word));
}
else
System.out.println("Object o you passed is not a WordNode");
}
This way if two different WordNode object has the same String as word field they are considered equals
how to call the equals:
WordNode n1 = new WordNode();
n1.setWord("test");
WordNode n2 = new WordNode();
n2.setWord("test");
System.out.println(n1.equals(n2));
So the equals receives an object of type Object but when you call the equals on a WordNode you havo to provide an object which is instance of WordNode too otherwise the cast i made fails (your exception) and of course it makes no sense to verify if an Object is equal to a WordNode

Related

Fibonacci Heap Extract Min Implementation Not Working

I am implementing Fibonacci Heap to improve on my Dijkstra's shortest path algorithm. My insert method works fine, and the next one I needed to do is extract-min. I am following CLRS. Please note some attributes mentioned in the book aren't in my implementation yet, as they are not needed for the functions so far, but I will add them later.
private static class FibonacciHeap {
/**
* Implementation of the node used in
* fibonacci heap. The nodes are stored
* as a circular doubly-linked list, making
* delete and insert operations easy, as
* well as being able to iterate through
* without being forced to keep track of the
* head
*/
private class Node {
/**
* The vertex this node is storing
*/
Vertex val;
/**
* Key used to know the order of vertices
*/
int key;
/**
* The left and right sibling in the list
*/
Node left, right;
/**
* Pointer to one of the child's
*/
Node child;
/**
* The amount of children this node has
*/
int degree;
/**
* Constructs a node with a value and key
*
* #param val the value of this node
* #param key the key of this node
*/
public Node(Vertex val, int key) {
this.val = val;
this.key = key;
}
/**
* Inserts a new node into this node's list.
* Inserts it to the left of this node, while
* maintaining the fact that it's circular
*
* #param newNode The new node to be inserted
*/
public void insert(Node newNode) {
newNode.left = left;
left.right = newNode;
newNode.right = this;
left = newNode;
if(newNode.key < min.key) {
min = newNode;
}
size++;
}
/**
* Removes this node from it's list
*/
public void remove() {
right.left = left;
left.right = right;
}
/**
* Inserts a new child into this nodes
* child list
*
* #param child The new node to be added as a child
*/
public void link(Node child) {
child.remove();
if(this.child == null) {
this.child = child;
} else {
this.child.insert(child);
}
degree ++;
}
/**
* Used for debugging. Will be removed after
* all operations work fine
*
* #return A string representation of this node
*/
#Override
public String toString() {
Node dummy = right;
StringBuilder sb = new StringBuilder();
sb.append(key).append(" -> (");
sb.append(dummy.child);
sb.append(") ");
while(dummy != this) {
sb.append(dummy.key).append(" -> (");
sb.append(dummy.child);
sb.append(") ");
dummy = dummy.right;
}
return sb.toString();
}
}
/**
* Pointer to the node with the smallest key
*/
private Node min;
/**
* Stores the number of nodes in the heap
*/
private int size;
/**
* Creates an empty Fibonacci Heap
*/
public FibonacciHeap() { }
/**
* Gets and returns the key with the
* smallest value
*
* #return the key with the smallest value
*/
public int getMin() {
if(min == null) {
throw new NoSuchElementException("Empty Fibonacci Heap");
}
return min.key;
}
/**
* Inserts a vertex along with a key. The
* key is the one used to measure whether
* this vertex is lesser than another
*
* #param vertex vertex to be added
* #param key key of the vertex
*/
public void insert(Vertex vertex, int key) {
if(min == null) {
min = new Node(vertex, key);
min.left = min;
min.right = min;
size = 1;
} else {
min.insert(new Node(vertex, key));
}
}
/**
* Removes the node with the smallest key from
* the heap, and updates the minimum node if needed
*
* #return The node with the smallest key prior to this method call
*/
public Vertex extractMin() {
if(isEmpty()) {
throw new NoSuchElementException("Empty Fibonacci Heap");
}
Vertex toReturn;
if(min == null) {
toReturn = null;
} else {
toReturn = min.val;
if(min.right == min) {
min = null;
} else {
min.remove();
min = min.right;
consolidate();
}
}
return toReturn;
}
/**
* Consolidates the heap. Consolidation is the process
* making every node in the root list have it's own
* unique degree. That is, every node in the top most
* layer has a unique amount of children
*/
private void consolidate() {
Node[] degrees = new Node[size];
degrees[min.degree] = min;
Node tempMin, dummy = (tempMin = min).right;
while(dummy != tempMin) {
if(dummy.key < min.key) {
min = dummy;
}
while(degrees[dummy.degree] != null) {
Node other = degrees[dummy.degree];
if(other.key < dummy.key) {
Node temp = dummy;
dummy = other;
other = temp;
}
dummy.link(other);
degrees[dummy.degree - 1] = null;
}
degrees[dummy.degree] = dummy;
}
}
/**
* Returns true if and only if the
* heap is empty
*
* #return if the heap is empty
*/
public boolean isEmpty() {
return min == null;
}
/**
* A string representation of this
* heap. Format of string is:
* node1 -> (node1.child.toString()) node2 -> (node2.child.toString()) ... noden -> (noden.child.toString())
* The string representation of the
* heap is the string representation of
* the minimum node
*
* #return A string representation of this heap
*/
#Override
public String toString() {
return min.toString();
}
}
This is the stack trace that it gives:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 10 out of bounds for length 10
at GraphTheory.ShortestPathAlgorithms.DijkstraShortestPath$FibonacciHeap.consolidate(DijkstraShortestPath.java:362)
at GraphTheory.ShortestPathAlgorithms.DijkstraShortestPath$FibonacciHeap.extractMin(DijkstraShortestPath.java:338)
at GraphTheory.ShortestPathAlgorithms.DijkstraShortestPath.main(DijkstraShortestPath.java:104)
The main error is given in the conditional statement of the inner while loop in the consolidate function. I also commented the line in the code. What is going wrong? My main testing method insert 10 random numbers from 1 - 10, and then extracts the minimum until it's empty. The error occurs the first time extract-min is called.
public static void main(String[] args) {
FibonacciHeap f = new FibonacciHeap();
StringBuilder sb = new StringBuilder();
for(int i = 0; i < 10; i ++) {
f.insert(new Vertex(i), (int) (Math.random() * 10));
}
while(!f.isEmpty()) {
System.out.println(f.extractMin());
}
}
Can't pinpoint the exact bug. But, I can tell you from experience that you should not find the minimum while consolidating. You consolidate and then you find the new minimum. You might get into trouble when you have multiple nodes with the same key and the one pointed to by min doesn't end up in the root list.
Also, while testing, don't use a random function. Create an array of arbitrary numbers and insert elements from the array into the heap.
I also don't understand how your implementation handles there being only one heap ordered tree in the Fib heap. What happens when you do an extract-min then?
You can find my Python implementation here if you need it.

Cannot find symbol in Java recursion

I'm trying to help a friend implement a Trie structure in Java although my programming is not that great, let along my Java. I found an implementation here and tried to run it on IDEA IntelliJ.
The error I receive is,
Error:(87, 41) java: cannot find symbol
symbol: method getWords()
location: variable children of type com.company.TrieNode[]
I'm not sure where to start troubleshooting this error. I have a feeling it might have to do with the loop? I want to get the code running before I analyze it but this error is a hurdle.
I've already tried File > Invalidate Caches/Restart within IntelliJ but it comes up with the same error. I think this might be a Java problem.
The following is what I have (credits to the aforementioned link),
Main.java
package com.company;
public class Main {
public static void main(String[] args) {
Trie myTrie = new Trie();
myTrie.addWord("Khalid");
}
}
Trie.java
package com.company;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Khalid on 5 December.
*/
public class Trie
{
private TrieNode root;
/**
* Constructor
*/
public Trie()
{
root = new TrieNode();
}
/**
* Adds a word to the Trie
* #param word
*/
public void addWord(String word)
{
root.addWord(word.toLowerCase());
}
/**
* Get the words in the Trie with the given
* prefix
* #param prefix
* #return a List containing String objects containing the words in
* the Trie with the given prefix.
*/
public List getWords(String prefix)
{
//Find the node which represents the last letter of the prefix
TrieNode lastNode = root;
for (int i=0; i<prefix.length(); i++)
{
lastNode = lastNode.getNode(prefix.charAt(i));
//If no node matches, then no words exist, return empty list
if (lastNode == null) return new ArrayList();
}
//Return the words which eminate from the last node
return lastNode.getWords();
}
}
TrieNode.java
package com.company;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Khalid on 5 December.
*/
public class TrieNode {
private TrieNode parent;
private TrieNode[] children;
private boolean isLeaf; //Quick way to check if any children exist
private boolean isWord; //Does this node represent the last character of a word
private char character; //The character this node represents
/**
* Constructor for top level root node.
*/
public TrieNode() {
children = new TrieNode[26];
isLeaf = true;
isWord = false;
}
/**
* Constructor for child node.
*/
public TrieNode(char character) {
this();
this.character = character;
}
/**
* Adds a word to this node. This method is called recursively and
* adds child nodes for each successive letter in the word, therefore
* recursive calls will be made with partial words.
*
* #param word the word to add
*/
protected void addWord(String word) {
isLeaf = false;
int charPos = word.charAt(0) - 'a';
if (children[charPos] == null) {
children[charPos] = new TrieNode(word.charAt(0));
children[charPos].parent = this;
}
if (word.length() > 1) {
children[charPos].addWord(word.substring(1));
} else {
children[charPos].isWord = true;
}
}
/**
* Returns the child TrieNode representing the given char,
* or null if no node exists.
*
* #param c
* #return
*/
protected TrieNode getNode(char c) {
return children[c - 'a'];
}
/**
* Returns a List of String objects which are lower in the
* hierarchy that this node.
*
* #return
*/
protected List getWords() {
//Create a list to return
List list = new ArrayList();
//If this node represents a word, add it
if (isWord) {
list.add(toString());
}
//If any children
if (!isLeaf) {
//Add any words belonging to any children
for (int i = 0; i < children.length; i++) {
if (children[i] != null)
list.addAll(children.getWords());
}
}
return list;
}
/**
* Gets the String that this node represents.
* For example, if this node represents the character t, whose parent
* represents the charater a, whose parent represents the character
* c, then the String would be "cat".
*
* #return
*/
public String toString() {
if (parent == null) {
return "";
} else {
return parent.toString() + new String(new char[]{character});
}
}
}
Your code is trying to call getWords() on children, which is an array of TrieNode. Presumably the intent is to collect the result of each child node. Since you're already in a loop, you just need to update the code to reference the current item:
list.addAll(children[i].getWords());

Trie datastructure in Java

So I built myself a trie data structure in java but instead of arrays containing LinkedLists to each node's children. But I am having some problems. The first word gets added just fine, but on the second word, it is always comparing the wrong prefixes. For example, I start off by adding "at". This works. Then I add "Hello" and this is the result:
adding 'at'
CURRENT CHAR IS: a
List is empty, can't iterate
List is empty, can't iterate
Can't find this char, adding node...
Returning child
CURRENT CHAR IS: t
List is empty, can't iterate
List is empty, can't iterate
Can't find this char, adding node...
END OF LINE; SET IT TO TRUE--------------
Returning child
adding 'Hello'
CURRENT CHAR IS: H
List is NOT empty
char H lista a?
false
List is empty, can't iterate
List is NOT empty
char H lista a?
false
List is empty, can't iterate
Can't find this char, adding node...
Returning child
CURRENT CHAR IS: e
List is NOT empty
char e lista at?
false
List is empty, can't iterate
List is NOT empty
char e lista at?
false
List is empty, can't iterate
Can't find this char, adding node...
Returning child
CURRENT CHAR IS: l
List is empty, can't iterate
List is empty, can't iterate
Can't find this char, adding node...
Returning child
CURRENT CHAR IS: l
List is empty, can't iterate
List is empty, can't iterate
Can't find this char, adding node...
Returning child
CURRENT CHAR IS: o
List is empty, can't iterate
List is empty, can't iterate
Can't find this char, adding node...
END OF LINE; SET IT TO TRUE--------------
Here is my code(sorry for all the prints and comments, have been debugging for a couple of hours)
Trie
public class Trie {
private Node root;
private int size;
/**
* Creates the root node and sets the size to 0.
*/
public Trie() {
root = new Node();
size = 0;
}
/**
* Adds a new word to the trie.
*
* #param word
* #return
*/
//vi lägger in "Hello"
public boolean add(String word) {
System.out.println("adding " + word);
Node curr = root;
if (curr == null || word == null) {
return false;
}
int i = 0;
char[] chars = word.toCharArray();
// Loop through all letters in the word.
while (i < chars.length) {
System.out.println("lengt = " + chars.length);
LinkedList<Node> children = curr.getChildren();
// If the children nodes does not contain the letter at i.
System.out.println("BEFORE CURRENT CHAR IS: " + chars[i]);
if (!childContain(children, String.valueOf(chars[i]))) {//TODO? listan är tom.
// Insert a new node
insertNode(curr, chars[i]);
System.out.println("Can't find this word, adding...");
// if we have traversed all letters.
if (i == chars.length - 1) {
System.out.println("END OF LINE; SET IT TO TRUE--------------");
// Get the child and set word to true ie we have found it.
getChild(curr, chars[i]).setWord(true);
size++;
return true;
}
}
// get the current child.
curr = getChild(curr, chars[i]); //NOT SURE ABOUT THIS!
// If the current childs text is equal the word or not the word.
if (curr.getText().equals(word) && !curr.isWord()) {
// set the current word to true.
curr.setWord(true);
size++;
return true;
}
i++;
}
return false;
}
/**
* Returns true if the given string is found.
* TODO: FIX!
* #param str
* #return
*/
public boolean find(String str) {
System.out.println(str);
System.out.println("-----------------------------------------");
LinkedList<Node> children = root.getChildren();
Node node = null;
char[] chars = str.toCharArray();
//Loop over all letters.
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
//If child contains c.
if (childContain(children, String.valueOf(c))) {
System.out.println("DET FINNS");
//get the child and it's children.
node = getChild(root, c);
children = node.getChildren();
} else {
System.out.println("DET FINNS INGET");
return false;
}
}
return true;
}
/**
* Inserts a new Node with a char.
*
* #param node
* #param c
* #return
*/
private Node insertNode(Node node, Character c) {
if (childContain(node.getChildren(), String.valueOf(c))) {
return null;
}
Node next = new Node(node.getText() + c.toString());
node.getChildren().add(next);
return next;
}
/**
* Retrieves a given node's child with the character c
*
* #param trie
* #param c
* #return
*/
private Node getChild(Node node, Character c) {
LinkedList<Node> list = node.getChildren();
Iterator<Node> iter = list.iterator();
while (iter.hasNext()) {
Node n = iter.next();
if (n.getText().equals(String.valueOf(c)));
{
System.out.println("Returning child");
return n;
}
}
System.out.println("Returning null"); // This could never happen
return null;
}
/**
* Checks if any child contains the char c.
*
* #param list
* #param c
* #return
*/
private boolean childContain(LinkedList<Node> list, String c) {
Iterator<Node> iter = list.iterator();
while (iter.hasNext()) {
System.out.println("List is NOT empty");
Node n = iter.next();
//GÖr en substräng av den existerande noden
System.out.println("char " + (c) +" lista " + n.getText() + "?");
System.out.println(n.getText().equals(c));
if (n.getText().equals(c))
{
return true;
}
}
System.out.println("List is empty, can't iterate");
return false;
}
/**
* Returns the trie's size.
*
* #return
*/
public int getSize() {
return size;
}
}
Node:
public class Node {
private boolean isWord;
private String text;
private LinkedList<Node> children;
public Node() {
children = new LinkedList<Node>();
text = "";
isWord = false;
}
public Node(String text) {
this();
this.text = text;
}
public LinkedList<Node> getChildren(){
return children;
}
public boolean isWord() {
return isWord;
}
public void setWord(boolean isWord) {
this.isWord = isWord;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
#Override
public String toString(){
return text;
}
}
I found 3 bugs.
Frist, this getChild() method has misplaced semicolon that is causing your method to return at the first node:
if (n.getText().equals(String.valueOf(c)))/*; - remove this semicolon*/
{
System.out.println("Returning child");
return n;
}
Second, I'm assuming you want each node in your trie to only contain a single letter. Therefore, you must correct the insertNode() method like so:
Node next = new Node(/*node.getText() + - remove this*/c.toString());
If you run that code, you will get a NullPointerException trying to find words that you add. This is because in your find method has a few bugs. I rewrote it and added some comments that explain the changes. Please let me know if it's unclear:
public boolean find(String str) {
LinkedList<Node> children = root.getChildren();
// start the node at the root
Node node = root;
char[] chars = str.toCharArray();
//Loop over all letters.
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
//If child contains c.
if (childContain(children, String.valueOf(c))) {
//get the child *of the node, not root* and it's children.
node = getChild(node, c);
// there are better ways to handle this, but I think this explicitly shows what the situations is
if (node == null) {
// we have reached a node that does not have children
if (i == chars.length - 1) {
// we are at the end of the word - it is found
return true;
} else {
// we are in the middle of the word - it is not present
return false;
}
}
// if we have reached the end of the word this will cause NullPointer
children = node.getChildren();
} else {
return false;
}
}
return true;
}
When I run this snippet:
public static void main(String[] args) {
Trie trie = new Trie();
trie.add("at");
trie.add("Hello");
System.out.println(trie.find("at"));
System.out.println(trie.find("Hello"));
System.out.println(trie.find("yea"));
}
I get "true", "true", "false"

Hashmap error is not abstract and does not override method in remove() in iterator

So I am working on a hashmap that uses two distinct hash functions to create it. The problem is in my iterator class I am getting an error that reads <anonymous hashmap.MyHashMap$1> is not abstract and does not override method in remove() in iterator. I have tried everything to figure out how to get this error to go away. I cannot simply "implement all abstract methods" as it suggests as otherwise I can't initialize the hash function and use it to insert values. Below is the entirety of my code
import java.util.Map;
import java.util.Iterator;
public class MyHashMap<KeyType, ValueType> implements
Iterable<Map.Entry<KeyType, ValueType>> {
// The size of the array
int theSize = 0;
// The starting size of the table
public static final int DEFAULT_ARRAY_SIZE = 11;
// Array containing the number of nodes in each index of the array
int lengths[] = null;
// The array used for the hash table
private Node<KeyType, ValueType>[] arr = null;
private HashFunction<KeyType> hash1; //One of the two hash functions
private HashFunction<KeyType> hash2; //One of the two hash functions
/**
* Null constructor for the myHashMap object
*/
public MyHashMap() {
this(null, null);
}
/**
* Accepts two hash functions to generate a hash code
*
* #param h1 The first hash function
* #param h2 The second hash function
*/
public MyHashMap(HashFunction<KeyType> h1, HashFunction<KeyType> h2) {
hash1 = h1;
hash2 = h2;
doClear();
}
/**
* Returns the size of the table
*/
public int size() {
return theSize;
}
/**
* Performs the clear private routine
*/
public void clear() {
doClear();
}
/**
* Clears the table
*/
private void doClear() {
theSize = 0;
arr = new Node[DEFAULT_ARRAY_SIZE];
lengths = new int[DEFAULT_ARRAY_SIZE];
}
/**
* Resizes the hash table if the size passes the default size
*/
private void rehash() {
MyHashMap<KeyType, ValueType> bigger
= new MyHashMap<KeyType, ValueType>(hash1, hash2);
bigger.arr = new Node[arr.length * 2];
bigger.lengths = new int[bigger.arr.length];
for (Node<KeyType, ValueType> lst : arr) {
for (Node<KeyType, ValueType> p = lst; p != null; p = p.next) {
bigger.put(p.key, p.value);
}
}
arr = bigger.arr;
lengths = bigger.lengths;
bigger = null;
}
/**
* Generates a hash code in order to determine where on the table the item
* goes
*
* #param k The key that will be used to generate the code
* #param h The hash function to be used
* #return The index
*/
private int myHash(KeyType k, HashFunction<KeyType> hash) {
if (hash == null) {
return Math.abs(k.hashCode() % arr.length);
} else {
return Math.abs(hash.hashCode(k) % arr.length);
}
}
/**
* Places an item into the hash map. If the key matches an existing one, the
* value is then replaced with the new incoming value
*
* #param k The incoming key
* #param v The incoming value
* #return The the old value removed.
*/
public ValueType put(KeyType k, ValueType v) {
// If the size of the table exceeds the default array size, rehash
if (size() > arr.length) {
rehash();
}
// The hash codes obtained from the key
int thisList1 = myHash(k, hash1);
int thisList2 = myHash(k, hash2);
// Checking if the incoming key matches an existing key, if it does
// replace the value and return the old one
for (Node<KeyType, ValueType> p = arr[thisList1]; p != null; p = p.next) {
if (p.key.equals(k)) {
ValueType old = p.value;
p.value = v;
return old;
}
}
for (Node<KeyType, ValueType> p = arr[thisList2]; p != null; p = p.next) {
if (p.key.equals(k)) {
ValueType old = p.value;
p.value = v;
return old;
}
}
// Adding the incoming data to the index with the least amount of
// nodes in it.
if (numOfNodes(arr[thisList1]) <= numOfNodes(arr[thisList2])) {
arr[thisList1] = new Node<>(k, v, arr[thisList1]);
++lengths[thisList1];
++theSize;
} else {
// Else the second list is the smaller of the two. Add it to this one
arr[thisList2] = new Node<>(k, v, arr[thisList2]);
++lengths[thisList2];
++theSize;
}
// No old value to return
return null;
}
/**
* Counts the number of nodes that exist in a space of the table
*
* #param n The start space
* #return The number of nodes
*/
private int numOfNodes(Node n) {
int size = 0;
// If the space is not empty, then it will step through and count the
// number of nodes present
for (Node<KeyType, ValueType> p = n; p != null; p = p.next) {
++size;
}
return size;
}
/**
* Removes a specified key from the map
* #param k The key that is to be removed
* #return True if the object has been removed, false if it has not
*/
public boolean remove(KeyType k) {
// Getting the hash codes for the list
int thisList1 = myHash(k, hash1);
int thisList2 = myHash(k, hash2);
// If the position specified by hash1 is found, check first element
if (arr[thisList1] != null) {
if (arr[thisList1].key.equals(k)) {
arr[thisList1] = arr[thisList1].next;
--theSize;
return true;
}
for (Node<KeyType, ValueType> p = arr[thisList1]; p.next != null;
p = p.next) {
if (p.next.key.equals(k)) {
p.next = p.next.next;
--theSize;
return true;
}
}
}
// If the position specified by hash2 is found, check first element
if (arr[thisList2] != null) {
if (arr[thisList2].key.equals(k)) {
arr[thisList2] = arr[thisList2].next;
--theSize;
return true;
}
for (Node<KeyType, ValueType> p = arr[thisList2]; p.next != null;
p = p.next) {
if (p.next.key.equals(k)) {
p.next = p.next.next;
--theSize;
return true;
}
}
}
// Else the item that is to removed is never found, therefore return
// false
return false;
}
/**
* Returns the desired value associated with the specified key
*
* #param k The key
* #return The value if found, null if not
*/
public ValueType get(KeyType k) {
// The hash codes obtained from the key
int thisList1 = myHash(k, hash1);
int thisList2 = myHash(k, hash2);
// Using the first hash code, searching the nodes
for (Node<KeyType, ValueType> p = arr[thisList1]; p != null; p = p.next) {
if (p.key.equals(k)) {
return p.value;
}
}
// Using the second hash code, seraching the nodes
for (Node<KeyType, ValueType> p = arr[thisList2]; p != null; p = p.next) {
if (p.key.equals(k)) {
return p.value;
}
}
return null;
}
/**
* Prints out the hashMap
*
* #return The printed hashMap
*/
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[");
for(Map.Entry<KeyType, ValueType> n : this) {
sb.append(n);
sb.append(",");
}
sb.append("]");
return new String(sb);
}
/**
* Creates an iterator for traversing the list.
*
* #return An iterator to traverse the list
*/
#Override
public Iterator<Map.Entry<KeyType, ValueType>> iterator() {
return new Iterator<Map.Entry<KeyType, ValueType>>() {
/**
* Checks if the node has a next link
* #return True if it has a node, false if it does not
*/
#Override
public boolean hasNext() {
return current != null;
}
/**
* Gets the next item on the list
* #return The next node
*/
#Override
public Map.Entry<KeyType, ValueType> next() {
final Node<KeyType, ValueType> theCurrent = current;
current = current.next;
// If the current list has no more nodes, move to the next list
if (current == null) {
++listNum;
advanceToNewList();
}
// Creates a new entry that will hold the next node
Map.Entry<KeyType, ValueType> nextItem = new Map.Entry<KeyType, ValueType>() {
/**
* Returns the current node's key
* #return
*/
#Override
public KeyType getKey() {
return theCurrent.key;
}
/**
* Returns the current node's value
* #return
*/
#Override
public ValueType getValue() {
return theCurrent.value;
}
/**
* Sets a new value to the current node
* #param value The new value that will be placed
* #return The old value that was overwritten
*/
#Override
public ValueType setValue(ValueType value) {
ValueType temp = theCurrent.value;
theCurrent.value = value;
return temp;
}
};
return nextItem;
}
/**
* Advances to the next index of the table
*/
private void advanceToNewList() {
while (listNum < arr.length && arr[ listNum ] == null) {
listNum++;
}
if (listNum != arr.length) {
current = arr[listNum];
}
}
// Initializes the advanceToNewList method {
advanceToNewList();
}
Node<KeyType, ValueType> current; // current node
int listNum; // current list #
};
}
/**
* Creates a node class for the linked list
* #param <KeyType> The key for the map. Can be any type
* #param <ValueType> The value associated with the key. Can be any type
*/
class Node<KeyType, ValueType> {
/**
* Constructs a node object using a key, a value, and a link to the next
* node
* #param k The key
* #param v The value
* #param n The next node
*/
Node(KeyType k, ValueType v, Node<KeyType, ValueType> n) {
key = k;
value = v;
next = n;
}
/**
* Prints out the node
* #return A string containing the key and the value
*/
public String toString() {
return key + "=" + value;
}
KeyType key; // The key of the node
ValueType value; // The value of the node
Node<KeyType, ValueType> next; // The next node
}
/**
* Creates an array that contains the number of entries that have a
* certain length. For example: The number of lists of length 0, 1, 2, etc.
* #return The array containing the distribution of list lengths
*/
public int[] getLengths()
{
int sizeList[] = new int[20];
// Incrementing the count at the index in the array sizeList. It will
// increment for every list of size at lengths[i].
for(int i = 0; i < lengths.length; ++i) {
++sizeList[lengths[i]];
}
return sizeList;
}
}
Below is the specific location where the error occurs
public Iterator<Map.Entry<KeyType, ValueType>> iterator() {
return new Iterator<Map.Entry<KeyType, ValueType>>()
{ <--- Right here is where the error occurs
Any help that can be provided will be greatly appreciated
Short answer: When creating anonymous classes of an interface, you must implement every abstract method. You don't necessarily need to thoroughly implement every method, you must just create it even if it has blank contents. So, you can just do this to rid the error (starting at the arrow where the exception was raised) :
public void remove() {
//No contents
}
and do the same things for any other abstract methods in the Iterator interface. However, it is probably best that you do actually write some code for these...

Creating an Array of Linked list

My program is meant to take a list of words and store each word under a letter reference in an array in ascending order. For example array of A-Z words apple, ape under a linked list under A referenced by 0, Zebra under Z referenced by 25. But when I use the standard first = new Node(word) I am not adding anything. I'm hopelessly lost.
import java.util.LinkedList;
public class ArrayLinkedList
{
/**
The Node class is used to implement the
linked list.
*/
private class Node
{
String value;
Node next;
/**
* Constructor
* #param val The element to store in the node
* #param n The reference to the successor node
*/
Node(String val, Node n)
{
value = val;
next = n;
}
Node(String val)
{
this(val, null);
}
}
private final int MAX = 26; // Number of nodes for letters
private Node first; // List head
private Node last; // Last element in the list
private LinkedList[] alpha; // Linked list of letter references
/**
* Constructor to construct empty array list
*/
public ArrayLinkedList()
{
first = null;
last = null;
alpha = new LinkedList[MAX];
for (int i = 0; i < MAX; i++)
{
alpha[i] = new LinkedList();
}
}
/**
* arrayIsEmpty method
* To check if a specified element is empty
*/
public boolean arrayIsEmpty(int index)
{
return (alpha[index].size() == 0);
}
/**
* The size method returns the length of the list
* #return The number of elements in the list
*/
public int size()
{
int count = 0;
Node p = first;
while (p != null)
{
// There is an element at p
count++;
p = p.next;
}
return count;
}
/**
* add method
* Adds the word to the first position in the linked list
*/
public void add(String e)
{
String word = e.toLowerCase(); // Put String to lowercase
char c = word.charAt(0); // to get first letter of string
int number = c - 'a'; // Index value of letter
// Find position of word and add it to list
if (arrayIsEmpty(number))
{
first = new Node(word);
first = last;
}
else
{
first = sort(first, word, number);
}
}
/**
* nodeSort method
* To sort lists
*/
private Node sort(Node node, String value, int number) {
if (node == null) // End of list
{
return getNode(value, number);
}
int comparison = node.value.compareTo(value);
if (comparison >= 0) // Or > 0 for stable sort.
{
Node newNode = getNode(value, number); // Insert in front.
newNode.next = node;
return newNode;
}
node.next = sort(node.next, value, number); // Insert in the rest.
return node;
}
private Node getNode(String value, int number)
{
return first.next;
}
/**
* get method
* to get each word value from the linked list and return it
* #return value
*/
public LinkedList get(int index)
{
return alpha[index];
}
public String toString()
{
StringBuilder sBuilder = new StringBuilder();
sBuilder.append("Word and occurrence in ascending order\n\n");
Node p = first;
while (p != null)
{
sBuilder.append(p.value + "\n");
p = p.next;
}
return sBuilder.toString();
}
}
Is there a reason you are doing it this way.
I can think of an easier way: use Map which will map a character (e.g. "A") to a LinkedList of Words.

Categories