I need to analyze a text that fulfils the following problem:
Generate an output that shows a count of how many times each word occurs in the text. The report should be sorted first by word length, followed a natural sort.
I was docked points for my solution given below. Is there a better solution available? I have not used maps or any collection because we were told that extra credit will be due for those who don't use collections.
My POJO
/**
* An instance of this object represents the string that occurs in a sentence
* and the number of times it occurs in a single string.
*/
public class Word implements Comparable<Word> {
private final String word;
private int counter = 1;
public Word(String word) {
this.word = word;
}
public void incrementCounter() {
this.counter ++;
}
public String getWord() {
return word;
}
public int getCounter() {
return counter;
}
/**
* Overrides the default hashcode function.
*/
#Override
public int hashCode() {
int hashCode = 103034;
hashCode += this.word != null ? this.word.hashCode() ^ 3 : 0;
hashCode += this.counter ^ 2;
return hashCode;
}
/**
* Overrides the default equals function.
*/
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (this == obj) {
return true;
}
if (!(obj instanceof Word)) {
return false;
}
Word otherWord = (Word) obj;
if (this.word != null && this.word.equals(otherWord.getWord())) {
return true;
}
return false;
}
#Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("Word");
sb.append("{word='").append(word).append('\'');
sb.append(", counter=").append(counter);
sb.append('}');
return sb.toString();
}
/**
* The implementation checks for the order of comparison.
* The implementation first compares by presence of word string.
*
* #param w Word to be compared
* #return calculated order of comparison.
*/
#Override
public int compareTo(Word w) {
if (w == null) {
return -1;
}
if (this.word == null && w.getWord() != null) {
return 1;
}
if (this.word != null && w.getWord() == null) {
return -1;
}
return StringUtils.compareString(this.word, w.getWord());
}
}
import java.util.Comparator;
/**
* An instance of this class is responsible for comparing the instances of two word
* instances by comparing against the word string.
*/
public class WordComparator implements Comparator<Word> {
/**
* Compares two instances of words first by length of the word string and then by the
* word itself.
*
* #param firstWord first word to be compared
* #param secondWord second word to be compared
* #return negative number if the first word is less than the second word;
* positive if the first word is greater than the second word; 0 if equal.
*/
#Override
public int compare(Word firstWord, Word secondWord) {
if (firstWord == secondWord) {
return 0;
}
if (firstWord != null && secondWord == null) {
return -1;
}
if (firstWord == null && secondWord != null) {
return 1;
}
return StringUtils.compareString(firstWord.getWord(), secondWord.getWord());
}
}
Utility class.
public class StringUtils {
// Not to be instantiated.
private StringUtils() {}
/**
* Compares the string first by word length and then by string.
*
* #param first First string to be compared.
* #param second Second string to be compared
* #return integer representing the output of comparison.
*/
public static int compareString(String first, String second) {
if (first == second) {
return 0;
}
if (first == null && second != null) {
return 1;
}
if (first != null && second == null) {
return -1;
}
int wordLengthDifference = first.length() - second.length();
if (wordLengthDifference == 0) {
return first.compareTo(second);
}
return wordLengthDifference;
}
}
Main method:
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
/**
* Finds the number of occurrences of word a in given string. The implementation expects
* the input to be passed adsingle string argument.
*/
public class StringWordOccurences {
/**
* Finds the number of occurrences of a word in a string. The implementation relies
* on the following assumptions.
*
* <p>The word is passed as separate strings as in {#code "Hello" "World"} instead of
* a single string {#code "Hello World"}.
*
* #param args Arguments to be sorted by first word length and then by string.
*/
public static void main(String[] args) {
if (args == null || args.length == 0) {
System.out.println("There were no words. The count is 0");
return;
}
// Find the number of unique words and put them in an array.
Comparator<Word> wordComparator = new WordComparator();
Arrays.sort(args, new Comparator<String>() {
#Override
public int compare(String first, String second) {
return StringUtils.compareString(first, second);
}
});
Word [] words = new Word[args.length];
int numberOfUniqueWords = 0;
for (String wordAsString : args) {
Word word = new Word(wordAsString);
int index = Arrays.binarySearch(words, word, wordComparator);
if (index > -1) {
words[index].incrementCounter();
} else {
words[numberOfUniqueWords ++] = word;
}
}
Word [] filteredWords = Arrays.copyOf(words, numberOfUniqueWords);
// The display output.
for (Word word : filteredWords) {
System.out.println(word);
}
}
}
You don't need the binary searches after you have sorted your words in the desired order, because the identical words will be next to each other. Just go over all the words and compare each with the previous one. If they are equal, increment the counter. If they are not equal, you can print the results for the finished previous word right away (no need to store the results in an array). You also don't really need the Word class, you can do it with Strings.
A few points I can think of but obviously these are second guesses...
You have 3 places where there is similar logic for doing the Word compare.
Ditch the Arrays.sort, Arrays.binarySearch and Arrays.copyOf. Do the searching yourself - might be simpler
You could actually sort after you have reduced to unique values
Related
I am tasked with creating a postFixEvaluator in java and everytime i try to pop an operand using the evaluateTwoOperations method, my program ends and produces the below error. What is causing this? to my knowledge, I have everything typecasted to be a Complex and not a Integer.
"Couldn't run PostfixEvaluator! java.lang.ClassCastException: java.lang.Integer cannot be cast to Complex"
Start of my postFixEvaluator class
#author Cody
*/
import java.util.*;
import java.io.*;
import java.util.StringTokenizer;
public class PostfixEvaluator
{
private static final int STACK_SIZE = 100;
private Stack operand;
private String expression;
private ArrayList<Complex> answers;
public static Complex result;
public void run() throws IOException
{
ArrayList<Complex> a = new ArrayList<>();
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
//BufferedReader stdin = new BufferedReader(new FileReader("Prog3_1.in"));
operand = new Stack(STACK_SIZE);
boolean eof = false;
while (!eof) //while not done
{
expression = stdin.readLine(); //read a line of expression
//operand.clear(); //clear the stack
if (expression == null) //if no input, end program
{
eof = true;
}
else
{
result = evaluate(expression); //evaluate expression
}
if (result != null) //if the answer is valid
{
System.out.println("\nvalue: " + result.toString());
answers.add(result);//add answer to arrayList
}
else
{
System.out.println("\nInvalid Expression");
}
}
//read the ArrayList and print the results
/*
if (real)
/
for (int i = 0; i < answers.size(); i++)
{
System.out.println(answers.get(i));
}
*/
System.out.println("Normal termination of"
+ "program 3");
}
public Complex evaluate(String expression)
{
boolean valid = true;
StringTokenizer st = new StringTokenizer(expression); //tokenize the expression
String token; //get individual results of readLine
while (valid && st.hasMoreTokens()) //while valid and their are tokens remaining
{
token = st.nextToken(); //get next token
System.out.println("token is: " + token);
if (isOperator(token)) //if token is operator
{
if (isConjugate(token))
{// if token is conjugate
Complex result1 = evaluateConjugate(token);
operand.push(result1);
}
else //evaluate the operator and push the result
{
Complex result1 = evaluateTwoOperations(token);
operand.push(result1);
}
}
else
{
int value = Integer.parseInt(token);
operand.push(value);
}
}
Complex answer = (Complex) operand.pop();
return answer;
}
private Complex evaluateTwoOperations(String op)
{
Complex resultant = null;
if ( operand.isEmpty() )
System.out.println("Invalid Expression!");
else
{
Complex op2 = (Complex) operand.pop();
Complex op1 = (Complex) operand.pop();
switch (op.charAt(0)) //if op == '+'...
{
case '+':
resultant = op1.plus(op2);
break;
case '-':
resultant = op1.minus(op2);
case '*':
resultant = op1.times(op2);
}
return resultant;
}
return null;
}
private boolean isOperator(String token)
{
return token.equals("+") || token.equals("-")
|| token.equals("*") || token.equals("~");
}
private boolean isConjugate(String token)
{
return token.equals("~");
}
private Complex evaluateConjugate(String op)
{
Complex resultant = null;
if (operand.isEmpty())
System.out.println("Invalid Expression!");
else
{
Complex op1 = (Complex) operand.pop();
switch (op.charAt(0)) //if op == '~'
{
case '~':
resultant = op1.conjugate();
}
return resultant;
}
return null;
}
/*
private void outputExpression(String expression)
{
for (int i = 1; i < answers.size(); i++)
{
System.out.println("Expression " + i + ": " + expression);
}
}
*/
}
Start of my Complex class
#author Cody
*/
public class Complex
{
private int realNumber;
private int imagNumber;
private final int checker = 0;
/**
default constructor creates the default complex number a+bi where a=b=0.
*/
public Complex()
{
realNumber = checker;
imagNumber = checker;
}
/**
parameterized constructor creates the complex number a+bi, where b=0.
*/
public Complex(int real)
{
realNumber = real;
imagNumber = checker;
}
/**
parameterized constructor creates the complex number a+bi where a and b are
integers.
*/
public Complex(int real, int imag)
{
realNumber = real;
imagNumber = imag;
}
/**
method returns a new Complex number that represents the sum
of two Complex numbers.
#param cp
#return new summed complex number
*/
public Complex plus(Complex cp)
{
return new Complex(realNumber + cp.realNumber, imagNumber + cp.imagNumber);
}
/**
method returns a new Complex that represents the difference
between two Complex numbers
#param cp
#return difference of two Complex numbers
*/
public Complex minus(Complex cp)
{
return new Complex(realNumber - cp.realNumber, imagNumber - cp.imagNumber);
}
/**
method returns a new Complex that represents the product of
two Complex numbers
#param cp
#return product of two complex numbers
*/
public Complex times(Complex cp)
{
return new Complex(realNumber * cp.realNumber - imagNumber * cp.imagNumber,
realNumber * cp.realNumber + imagNumber * cp.realNumber);
}
/**
method should return a new Complex that is the conjugate of a
Complex number
#param none
#return conjugate of complex number
*/
public Complex conjugate()
{
return new Complex(realNumber, -imagNumber);
}
/**
method returns true if two Complex numbers have the same
real and imaginary; return false otherwise.
#param obj
#return true if two complex numbers are equal, false otherwise
*/
public boolean equals(Object obj)
{
if (obj instanceof Complex)
{
Complex n = (Complex) obj;
return n.realNumber == realNumber && n.imagNumber == imagNumber;
}
return false;
}
/**
method returns a complex number as a String.
uses multiple if statements to check validity
#param none
#return complex number as a string
*/
public String toString()
{
if (imagNumber == checker)
{
return String.valueOf(realNumber);
}
if (realNumber == checker && imagNumber == checker)
{
return String.valueOf(checker);
}
if (realNumber == checker)
{
return imagNumber + "i";
}
if (realNumber != checker && imagNumber < checker)
{
return realNumber + " - " + -imagNumber + "i";
}
if (realNumber != checker && imagNumber > checker)
{
return realNumber + " + " + imagNumber + "i";
}
return "invalid";
}
}
Start of my Stack class
/**
performs all practical Stack operations
#author Cody
*/
public class Stack
{
private Object[] elements;
private int top;
/**
parameterized constructor creates array of Elements with size of size
initializes top to 0
#param size
*/
public Stack(int size)
{
elements = new Object[size];
top = 0;
}
/**
checks to see if the array is empty
#param none
#return true if array is empty, false otherwise.
*/
public boolean isEmpty()
{
return top == 0;
}
/**
checks to see if the array is full
#param none
#return true if array is full, false otherwise.
*/
public boolean isFull()
{
return top == elements.length;
}
/**
returns the item most recently added to the stack. if the array is empty,
returns null
#param none
#return last item added to stack, null if empty array
*/
public Object peek()
{
if (top == 0)
return null;
return elements[top - 1];
}
/**
returns and deletes element most recently added to the stack
#param none
#return element most recently added to stack
*/
public Object pop()
{
return elements[--top];
}
/**
adds item to stack and increments top
#param obj
*/
public void push(Object obj)
{
elements[top++] = obj;
}
/**
returns number of items in stack
#param none
#return number of items in stack
*/
public int size()
{
return elements.length;
}
/**
clears the stack by popping everything in it
#param none
*/
public void clear()
{
for (int i = 0; i < size(); i++)
elements[i] = pop();
}
}
In your evaluate method, you have this piece of code:
int value = Integer.parseInt(token);
operand.push(value);
But when you pop such values , you are converting it to (Complex) in your evaluateTwoOperations method. Hence, you are getting the ClassCastException.
You already have a constructor to help you convert your Integer to Complex class
You could use that.
public Complex(int real)
{
realNumber = real;
imagNumber = checker;
}
My algorithm constructs a word and looks up a value associated with the word in a TST.
private Node get(Node x, String key, int index) {
if (key.isEmpty()) {
return root;
}
if (x == null) {
return null;
}
char c = key.charAt(index);
if (c < x.val) {
return get(x.left, key, index);
} else if (c > x.val) {
return get(x.right, key, index);
} else if (index < key.length() - 1) {
return get(x.mid, key, index + 1);
} else {
return x;
}
}
Each node is constructed as such:
private class Node {
private char val;
private Node left, mid, right;
private Double selfWeight;
private double maxWeight;
/**
* Node constructor.
*/
private Node(char c) {
val = c;
maxWeight = 0.0;
selfWeight = null;
}
}
A word's maxWeight is set during construction, which is a modified version of standard construction of a TST:
private Node put(Node x, String key, Double weight, int index) {
char c = key.charAt(index);
if (x == null) {
x = new Node();
x.val = c;
}
if (c < x.val) {
x.left = put(x.left, key, weight, index);
} else if (c > x.val) {
x.right = put(x.right, key, weight, index);
} else if (index < key.length() - 1) {
x.mid = put(x.mid, key, weight, index + 1);
} else {
x.selfWeight = weight;
}
if (weight > x.maxWeight) {
x.maxWeight = weight;
}
return x;
}
When running my algorithm, if I insert, for e.g. "hello" with weight 20, and I do search on get("hello" + '\u0000'); the method will return null where as if I call get("hello") the method will return 20. Why is this?
My logic is that adding the 'null' char will not change the string, and printing out "hello" + '\u0000' confirms this. What is happening?
They're not the same string because they don't contain the same characters. Just because you can't see a character doesn't mean it's not there.
If you converted hello to unicode then what you're claiming is
0068 0065 006C 006C 006F 0000 is the same as 0068 0065 006C 006C 006F
If you need further explanation, go examine the equals method for String
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#String.equals%28java.lang.Object%29
/**
* Compares this string to the specified object. The result is {#code
* true} if and only if the argument is not {#code null} and is a {#code
* String} object that represents the same sequence of characters as this
* object.
*
* #param anObject
* The object to compare this {#code String} against
*
* #return {#code true} if the given object represents a {#code String}
* equivalent to this string, {#code false} otherwise
*
* #see #compareTo(String)
* #see #equalsIgnoreCase(String)
*/
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
Why is String + '/u0000' different than String?
Because '/u0000' (or NUL) is a valid character, not a string terminator.
A String in Java is a sequence of characters, not a sequence of characters terminated by a NUL (or zero).
(Actually, it is a bit more technically complicated than that. /u0000 is a 16-bit UTF-16 code-unit that also happens to be a Unicode code-point. A String is a sequence of 16-bit char values that may or may not be valid UTF-16 code-units and may or may not be a well-formed Unicode code-point sequence. But either way, the zero char / code-point / code-unit is NOT a string terminator.)
Is there any such thing as a truly empty char?
No. Certainly, not in Java.
Now I'm not sure anybody can really help me with this, since it's a pretty sizable amount of code to go through, but any help would be greatly appreciated. Here is my relevant code:
public class BTree implements Iterable<String> {
/** Left child */
BTree left;
/** Right Child */
BTree right;
/** Comparator to use for sorting */
Comparator<String> comp;
/** Parent node */
BTree parent;
/** String stored in this leaf */
String s;
/** # of iterators currently working on it */
int active = 0;
/** Size of the BTree */
int size;
public void build(Iterable<String> iter, int numStrings) {
if (this.active > 0) {
throw new ConcurrentModificationException();
}
else {
Iterator<String> itr = iter.iterator();
while (numStrings != 0 && itr.hasNext()) {
String s = itr.next();
if (!this.contains(s)) {
this.insert(s);
this.size++;
numStrings--;
}
}
}
}
/**
* Inserts the string into the given BTree
* #param str - String to insert
*/
private void insert(String str) {
if (this.s.equals("")) {
this.s = str;
}
else if (this.comp.compare(str, this.s) > 0) {
if (this.right == null) {
BTree bt = BTree.binTree(this.comp);
bt.s = str;
this.right = bt;
bt.parent = this;
}
else {
this.right.insert(str);
}
}
else if (this.comp.compare(str, this.s) < 0) {
if (this.left == null) {
BTree bt = BTree.binTree(this.comp);
bt.s = str;
this.left = bt;
bt.parent = this;
}
else {
this.left.insert(str);
}
}
}
private class BTreeIterator implements Iterator<String> {
/** Current BTree being iterated over */
BTree current;
/** How many next() calls have there been */
int count;
/** Size of the BTree */
int max;
/** Constructor for BTreeIterator
* #param current
*/
BTreeIterator(BTree current) {
this.current = current;
this.count = 0;
this.max = current.size;
active++;
}
/** Returns true if there is another string to iterate over
* #return boolean
*/
public boolean hasNext() {
if (this.count != this.max) {
return true;
}
else {
active--;
return false;
}
}
/**
* Returns the next string in the iterator
* #return String
*/
public String next() {
if (this.count == 0) {
this.count++;
current = this.current.getLeftMost();
if (this.current.s.equals("")) {
throw new NoSuchElementException();
}
return this.current.s;
}
else if (this.current.right != null) {
this.current = this.current.right.getLeftMost();
this.count++;
return this.current.s;
}
else {
BTree tree = this.current;
while (tree.parent.right == tree) {
tree = tree.parent;
}
this.current = tree.parent;
this.count++;
return this.current.s;
}
}
/** Throws an exception since we aren't removing anything from the trees
*/
public void remove() {
throw new UnsupportedOperationException();
}
}
}
}
The Exception gets thrown at the while (tree.parent.right == tree) line in the next() method of the iterator. The funny thing is, my code has worked just fine with a comparator comparing lexicographically and reverse lexicographically sorting through a file of 24000 words. It only throws the exception when using the following comparator:
class StringWithOutPrefixByLex implements Comparator<String> {
/**
* compares o1 and o2
* #param o1 first String in comparison
* #param o2 second String in comparison
* #return a negative integer, zero, or a positive integer
* as the first argument is less than, equal to, or
* greater than the second.
*/
public int compare(String o1, String o2) {
String s1, s2;
if(o1.length() > 4){
s1 = o1.substring(3);
}
else {
s1 = o1;
}
if(o2.length() > 4){
s2 = o2.substring(3);
}
else {
s2 = o2;
}
return s1.compareTo(s2);
}
}
Even weirder, it works fine with that comparator for the same file up to 199 words, but as soon as I have it build up to 200 words it breaks.
EDIT: I have determined that the Exception is due to the code trying to reference tree.parent.right while tree.parent is null, but I can't figure out WHY it's trying to do that. As far as I can tell, my code should never try to call a null tree.parent, as explained by my comment below.
Well, you do not actually show enough of your code, but, what about the root node of your BTree? What is the value of BTree.parent in the root node? null?
If the root node has a null parent, then, in this while loop, it is likely that :
while (tree.parent.right == tree) {
tree = tree.parent;
}
... will get to the root node, the tree will be set to tree.parent, which is null, and then the while loop test will fail because tree.parent.right will attempt to dereference a null pointer.
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
I built a symbol table using an array list filled with an object "pairs" that are singly-linked chains and hold a word and the number of times it occurs in a text file. I need to use this for the FrequencyCounter program that counts the number of words in a file. For some reason, I'm getting this error when running the the FrequencyCounter with the HashST:
Processed 1215985 words (19 sec; 19710 msec
Exception in thread "main" java.lang.NullPointerException
at HashST.hashIndex(HashST.java:60)
at HashST.get(HashST.java:105)
at FrequencyCounter.main(FrequencyCounter.java:112)
I have an idea that there's something wrong with my HashST and its not putting the pairs in the ArrayList like I wanted it to. Any suggestions on what is wrong with the implementation would be greatly appreciated.
Here is my code and the code for the FrequencyCounter:
import java.util.LinkedList;
import java.util.ArrayList;
import java.util.Iterator;
public class HashST<Key extends Comparable<Key>, Value> implements Iterable<Key> {
private ArrayList<Pair> chains;
private int numKeys;
private int numChains;
public class Pair
{
Key key;
Value value;
Pair(Key k, Value v)
{
key = k;
value = v;
}
Pair()
{}
Pair next;
}
/**
* Initialize an empty HashSt with a default of 64 empty chains.
*/
public HashST()
{
this(64);
}
/**
* Initialize an empty HashST with numChains emptychains.
* 387911 is a prime number about twice the number of distinct
* words in the leipzig1M.txt file.
*/
public HashST(int numChains)
{
this.numChains = numChains;
chains = new ArrayList<Pair>();
for(int i = 0; i < numChains; i++)
{
Pair p = new Pair(null, null);
chains.add(p);
}
}
/**
* compute the hash index for a key k if the number of
* chains is N
*/
private int hashIndex(Key k, int N)
{
return (k.hashCode() & 0x7fffffff) % N;
}
/**
* insert the Pair (k,v) into the appropriate chain and increment
* the number of keys counter or
* update the value for k if k is already in the hash table.
*
*/
public void put(Key k, Value v) {
int i = hashIndex(k, numChains);
Pair tmp = chains.get(i);
if(contains(k))
{
while(tmp.next != null)
{
if(tmp.key == k)
{
tmp.value = v;
return;
}
tmp = tmp.next;
}
}
else
{
Pair p = new Pair(k, v);
tmp.next = p;
numKeys ++;
}
}
/**
* return the value for key k if it is in the hash table
* or else return null if it is not.
*/
public Value get(Key k) {
int i = hashIndex(k, numChains);
Pair tmp = chains.get(i);
while(tmp.next != null)
{
if(tmp.key == k)
{
return tmp.value;
}
tmp = tmp.next;
}
return null;
}
/**
* remove the pair with key k if it is in the hash table
* otherwise no change.
*/
public void delete(Key k) {
if(contains(k))
{
return;
}
}
/**
* return true if the hash table contains a pair with key
* equal to k else return false
*/
public boolean contains(Key k) {
return (get(k) != null) ? true : false;
}
/**
* return the number of keys in the hash table
*/
public int size() {
return numKeys;
}
/**
* return a LinkedList<Key> containing the keys in the
* hash table
*/
public Iterable<Key> keys() {
LinkedList<Key> l = new LinkedList<Key>();
for(Pair p : chains)
{
while(p.next != null)
{
l.add(p.key);
p = p.next;
}
}
return l;
}
/**
* return an Iterator<Key> for the keys in the hash table
*/
public Iterator<Key> iterator() {
return keys().iterator();
}
}
And here is the Frequency Counter: http://algs4.cs.princeton.edu/31elementary/FrequencyCounter.java.html
According to your stack trace this would seem to be the line that threw a null pointer:
return (k.hashCode() & 0x7fffffff) % N;
So we have one object reference k, an integer constant, and a primitive N. Neither the constant nor the primitive can be null, the only thing being dereferenced here is k. So it looks like someone tried to get a value for a null k!