I'm hoping to find a bit of direction for this problem I was given. Been banging my head over it for two weeks now. Essentially, I'm to write a function, public static int FindWords(char[][] puzzle) , where given a 2D char array, I can find the amount of times a given set of strings occur. Given:
public static class PuzzleSolver
{
public static string[] DICTIONARY = {"OX","CAT","TOY","AT","DOG","CATAPULT","T"};
static bool IsWord(string testWord)
{
if (DICTIONARY.Contains(testWord))
return true;
return false;
}
}
A 2D Array for instance that is like this:
public static char[][] puzzle = {{'C','A','T'},
{'X','Z','T'},
{'Y','O','T'}};
Would return back 8 for the following instances: (AT, AT, CAT, OX, TOY, T, T, T) because we would be searching horizontally, vertically, diagonally and in reverse for all the same directions.
My approach was to visit each char in the array and then search for all possible directions with the SearchChar function...
public static int FindWords(char[][] puzzle){
int arrayRow = puzzle.length;
int arrayCol = puzzle[0].length;
int found = 0;
for(int i = 0; i < arrayRow; i++){
for(int j = 0; j < arrayCol; j++){
found += SearchChar(i,j);
}
}
return found;
}
Which looks like this:
public static int SearchChar(int row, int col){
if(row < 0 || col < 0 || row > puzzle.length || col > puzzle[0].length)//Is row or col out of bounds?
return 0;
if(IsWord(puzzle[row][col]))
return 1;
return 0;
}
Conceptually, I feel like I need some kind of recursive function to handle this but I can't seem to wrap my head around it. I don't even know if that's the right approach. I've been playing around with StringBuilder appending but I'm still struggling with that too. I think this recursive function would need to take for instance, puzzle[0][0] (or 'C') and see if it is in the dictionary. Followed by puzzle[0][0] + puzzle[0][1] (or 'CA') and then finally puzzle[0][0] + puzzle[0][1] + puzzle[0][2] (or 'CAT'). Then the same would have to be don vertically and diagonally. I'm having trouble trying to get back into the SearchChar function with a position change to append to the original char so that I can see if it is in the DICTIONARY.
Sorry if this is a bit wordy, but I just want to give the impression that I'm actually trying to solve this. Not just some lazy programmer that's copy & pasting some problem up here for someone else to solve. Thanks in advance for any help!
I will show you how to solve this problem step by step.
1. Generating All Possible Words from the given Puzzle
to do this we must start anywhere in the puzzle and move towards all directions (except the previous Point) to generate all possible words;
2. Choosing Suitable Data Structure for Dictionary
I think Trie is a good choice and is suitable for use in such situations.
The most important reason for choosing Trie is that during the search, we can easily test if a word exists in our dictionary or is there any word that starts with the word generated by searching through the puzzle or not.
As a result, we can decide whether or not to continue the search.
This will save us a lot of time and helps to generate words correctly.
otherwise, we'll be stuck in an endless loop...
3. Implementation
there are several implementations for Tire , but I wrote my own CharTrie :
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
/**
* #author FaNaJ
*/
public final class CharTrie {
/**
* Pointer to root Node
*/
private final Node root = new Node();
/**
* Puts the specified word in this CharTrie and increases its frequency.
*
* #param word word to put in this CharTrie
* #return the previous frequency of the specified word
*/
public int put(String word) {
if (word.isEmpty()) {
return 0;
}
Node current = root;
for (int i = 0; i < word.length(); i++) {
current = current.getChildren().computeIfAbsent(word.charAt(i), ch -> new Node());
}
return current.getAndIncreaseFrequency();
}
/**
* #param word the word whose frequency is to be returned
* #return the current frequency of the specified word or -1 if there isn't such a word in this CharTrie
*/
public int frequency(String word) {
if (word.isEmpty()) {
return 0;
}
Node current = root;
for (int i = 0; i < word.length() && current != null; i++) {
current = current.getChildren().get(word.charAt(i));
}
return current == null ? -1 : current.frequency;
}
/**
* #param word the word whose presence in this CharTrie is to be tested
* #return true if this CharTrie contains the specified word
*/
public boolean contains(String word) {
return frequency(word) > 0;
}
/**
* #return a CharTrie Iterator over the Nodes in this CharTrie, starting at the root Node.
*/
public Iterator iterator() {
return new Iterator(root);
}
/**
* Node in the CharTrie.
* frequency-children entry
*/
private static final class Node {
/**
* the number of occurrences of the character that is associated to this Node,
* at certain position in the CharTrie
*/
private volatile int frequency = 0;
private static final AtomicIntegerFieldUpdater<Node> frequencyUpdater
= AtomicIntegerFieldUpdater.newUpdater(Node.class, "frequency");
/**
* the children of this Node
*/
private Map<Character, Node> children;
public Map<Character, Node> getChildren() {
if (children == null) {
children = new ConcurrentHashMap<>();
}
return children;
}
/**
* Atomically increments by one the current value of the frequency.
*
* #return the previous frequency
*/
private int getAndIncreaseFrequency() {
return frequencyUpdater.getAndIncrement(this);
}
}
/**
* Iterator over the Nodes in the CharTrie
*/
public static final class Iterator implements Cloneable {
/**
* Pointer to current Node
*/
private Node current;
private Iterator(Node current) {
this.current = current;
}
/**
* Returns true if the current Node contains the specified character in its children,
* then moves to the child Node.
* Otherwise, the current Node will not change.
*
* #param ch the character whose presence in the current Node's children is to be tested
* #return true if the current Node's children contains the specified character
*/
public boolean next(char ch) {
Node next = current.getChildren().get(ch);
if (next == null) {
return false;
}
current = next;
return true;
}
/**
* #return the current frequency of the current Node
*/
public int frequency() {
return current.frequency;
}
/**
* #return the newly created CharTrie Iterator, starting at the current Node of this Iterator
*/
#Override
#SuppressWarnings("CloneDoesntCallSuperClone")
public Iterator clone() {
return new Iterator(current);
}
}
}
and the WordGenerator :
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
import java.util.function.BiConsumer;
/**
* #author FaNaJ
*/
public final class WordGenerator {
private WordGenerator() {
}
public static void generate(char[][] table, CharTrie.Iterator iterator, BiConsumer<String, Integer> action) {
final ForkJoinPool pool = ForkJoinPool.commonPool();
final VisitorContext ctx = new VisitorContext(table, action);
for (int y = 0; y < table.length; y++) {
for (int x = 0; x < table[y].length; x++) {
pool.invoke(new Visitor(new Point(x, y), null, "", iterator.clone(), ctx));
}
}
}
private static final class VisitorContext {
private final char[][] table;
private final BiConsumer<String, Integer> action;
private VisitorContext(char[][] table, BiConsumer<String, Integer> action) {
this.table = table;
this.action = action;
}
private boolean validate(Point point) {
Object c = null;
try {
c = table[point.getY()][point.getX()];
} catch (ArrayIndexOutOfBoundsException ignored) {
}
return c != null;
}
}
private static final class Visitor extends RecursiveAction {
private final Point current;
private final Point previous;
private final CharTrie.Iterator iterator;
private final VisitorContext ctx;
private String word;
private Visitor(Point current, Point previous, String word, CharTrie.Iterator iterator, VisitorContext ctx) {
this.current = current;
this.previous = previous;
this.word = word;
this.iterator = iterator;
this.ctx = ctx;
}
#Override
protected void compute() {
char nextChar = ctx.table[current.getY()][current.getX()];
if (iterator.next(nextChar)) {
word += nextChar;
int frequency = iterator.frequency();
if (frequency > 0) {
ctx.action.accept(word, frequency);
}
List<Visitor> tasks = new ArrayList<>();
for (Direction direction : Direction.values()) {
Point nextPoint = direction.move(current);
if (!nextPoint.equals(previous) && ctx.validate(nextPoint)) {
tasks.add(new Visitor(nextPoint, current, word, iterator.clone(), ctx));
}
}
invokeAll(tasks);
}
}
}
}
Note that I've used ForkJoinPool and RecursiveAction to speed up the search.
learn more :
https://docs.oracle.com/javase/tutorial/essential/concurrency/forkjoin.html
http://tutorials.jenkov.com/java-util-concurrent/java-fork-and-join-forkjoinpool.html
http://www.javaworld.com/article/2078440/enterprise-java/java-tip-when-to-use-forkjoinpool-vs-executorservice.html
the rest of classes :
PuzzleSolver
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.stream.Stream;
/**
* #author FaNaJ
*/
public final class PuzzleSolver {
private final CharTrie dictionary;
public enum OrderBy {FREQUENCY_IN_DICTIONARY, FREQUENCY_IN_PUZZLE}
public PuzzleSolver(CharTrie dictionary) {
this.dictionary = dictionary;
}
public CharTrie getDictionary() {
return dictionary;
}
public Stream<Word> solve(char[][] puzzle) {
return solve(puzzle, OrderBy.FREQUENCY_IN_DICTIONARY);
}
public Stream<Word> solve(char[][] puzzle, OrderBy orderBy) {
Stream<Word> stream = null;
switch (orderBy) {
case FREQUENCY_IN_DICTIONARY: {
final Map<String, Integer> words = new ConcurrentHashMap<>();
WordGenerator.generate(puzzle, dictionary.iterator(), words::put);
stream = words.entrySet().stream()
.map(e -> new Word(e.getKey(), e.getValue()));
break;
}
case FREQUENCY_IN_PUZZLE: {
final Map<String, AtomicInteger> words = new ConcurrentHashMap<>();
BiConsumer<String, Integer> action = (word, frequency) -> words.computeIfAbsent(word, s -> new AtomicInteger()).getAndIncrement();
WordGenerator.generate(puzzle, dictionary.iterator(), action);
stream = words.entrySet().stream()
.map(e -> new Word(e.getKey(), e.getValue().get()));
break;
}
}
return stream.sorted((a, b) -> b.compareTo(a));
}
}
http://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/
Point
import java.util.Objects;
/**
* #author FaNaJ
*/
public final class Point {
private final int x;
private final int y;
public Point() {
this(0, 0);
}
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
#Override
public int hashCode() {
return x * 31 + y;
}
#Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
Point that = (Point) obj;
return x == that.x && y == that.y;
}
#Override
public String toString() {
return "[" + x + ", " + y + ']';
}
}
Word
/**
* #author FaNaJ
*/
public final class Word implements Comparable<Word> {
private final String value;
private final int frequency;
public Word(String value, int frequency) {
this.value = value;
this.frequency = frequency;
}
public String getValue() {
return value;
}
public int getFrequency() {
return frequency;
}
#Override
public int hashCode() {
return value.hashCode() * 31 + frequency;
}
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Word that = (Word) o;
return frequency == that.frequency && value.equals(that.value);
}
#Override
public String toString() {
return "{" +
"value='" + value + '\'' +
", frequency=" + frequency +
'}';
}
#Override
public int compareTo(Word o) {
return Integer.compare(frequency, o.frequency);
}
}
Direction
/**
* #author FaNaJ
*/
public enum Direction {
UP(0, 1), UP_RIGHT(1, 1), UP_LEFT(-1, 1),
RIGHT(1, 0), LEFT(-1, 0),
DOWN(0, -1), DOWN_RIGHT(1, -1), DOWN_LEFT(-1, -1);
private final int x, y;
Direction(int x, int y) {
this.x = x;
this.y = y;
}
public Point move(Point point) {
return new Point(point.getX() + x, point.getY() + y);
}
}
4. Test it
/**
* #author FaNaJ
*/
public class Test {
public static String[] DICTIONARY = {"OX", "CAT", "TOY", "AT", "DOG", "CATAPULT", "T", "AZOYZACZOTACXY"};
public static void main(String[] args) {
CharTrie trie = new CharTrie();
for (String word : DICTIONARY) {
trie.put(word);
}
PuzzleSolver solver = new PuzzleSolver(trie);
char[][] puzzle = {
{'C', 'A', 'T'},
{'X', 'Z', 'T'},
{'Y', 'O', 'T'}
};
solver.solve(puzzle, PuzzleSolver.OrderBy.FREQUENCY_IN_PUZZLE).forEach(System.out::println);
}
}
output :
{value='T', frequency=3}
{value='AT', frequency=2}
{value='CAT', frequency=2}
{value='TOY', frequency=2}
{value='OX', frequency=1}
{value='AZOYZACZOTACXY', frequency=1}
Related
I have implemented a binary search tree. Most of my test in JUNIT test is going through, including these two. I have implementedleavesIsCorrectWhenTreeIsPerfect() and insertValuesInAscendingOrderIncrementsHeight().
Both of these test goes through, however i do not know if it is correctly written based on what their description is asking.
//EDIT: I have added a test that might be a help to one of the test a need help with.
//TODO: help me understand if I have written the correct code for the test in insertValuesInAscendingOrderIncrementsHeight() and leavesIsCorrectWhenTreeIsPerfect() based on what the description for the test is saying.
Have in mind, that I have not included all the tests in the test class, Because the goes through with my implementation of the tree.
Down here I have included my tree class and the test class with both the test I need help with.
/**
* An Binary Search tree implementation.
* #param <T>
*/
public class Tree <T extends Comparable <T>> implements BSTInterface <T>{
private int size;
private Node root;
public class Node{
private Node Left;
private Node Right;
private T data;
public Node(T data){
this.data = data;
}
public Node getRight(){
return Right;
}
public Node getLeft() {
return Left;
}
public T getData() {
return data;
}
}
public Tree (){
size = 0;
root = null;
}
/**
* Test for presence of a value.
* #param elem
* #return true/false
*/
#Override
public boolean search(T elem) {
if(root == null ||elem == null){
return false;
}
Node node = root;
while(true){
if(node.data.compareTo(elem) > 0){
if(node.Right == null){
return false;
} else{
node = node.Right;
}
} else if(node.data.compareTo(elem) == 0){
break;
} else{
if(node.Left== null){
return false;
}
else{
node = node.Left;
}
}
}
return true;
}
/**
* Add value to tree; duplicates are not allowed.
* Return true if the element is not already present (and is thus inserted),
* false otherwise.
*
* #param elem
* #return true/false
*/
#Override
public boolean insert(T elem) {
if (elem == null){
return false;
}
if (root == null){
root = new Node(elem);
size++;
return true;
}
Node node = root;
while (true){
if (node.data.compareTo(elem) > 0) {
if (node.Right == null){
node.Right = new Node(elem);
size++;
break;
} else {
node = node.Right;
}
} else if (node.data.compareTo(elem) == 0) {
return false;
} else {
if (node.Left == null){
node.Left = new Node(elem);
size++;
break;
} else {
node = node.Left;
}
}
}
return true;
}
/**
* the number of elements in the tree
* #return size.
*/
#Override
public int size() {
return size;
}
/**
* The height of the tree.
* The empty tree and the tree with only the root node both have height 0.
* #return the height of the tree.
*/
#Override
public int height() {
return countHeight(root);
}
/**
* Helper method for height
*/
private int countHeight(Node node){
if(node == null) {
return 0;
}
if (node.Left == null && node.Right == null) {
return 0;
}
return 1 + Math.max(countHeight(node.getLeft()), countHeight(node.getRight()));
}
/**
* The number of leaves in the tree.
* #return the amount of leaves the tree has.
*/
#Override
public int leaves() {
return countLeaves(root);
}
/**
* Helper method for leaves
*/
private int countLeaves(Node node) {
if (node == null) {
return 0;
}
if (node.Left == null && node.Right == null) {
return 1;
}
return countLeaves(node.Left) + countLeaves(node.Right);
}
/**
* A string describing the tree
* #return
*/
public String toString(){
String str = "[" + helpToString(root);
if (str.length() > 1) {
str = str.substring(0, str.length() - 2);
} return str + "]";
}
/**
* Helper method for toString
*/
private String helpToString(Node node) {
String str = "";
if (node != null) {
str += helpToString(node.Right);
str += node.data + ", ";
str += helpToString(node.Left);
}
return str;
}
}
import org.junit.Test;
import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.Timeout;
import static org.junit.Assert.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.CoreMatchers.*;
import java.util.Arrays;
import java.util.stream.IntStream;
/**
* Test class for a tree.
*/
public class TreeTest{
#Rule public Timeout globalTimeout = Timeout.seconds(5);
Tree<Integer> tree;
int[] elementsInTree;
int[] elementsNotInTree;
#Before
public void setUp() {
/**
* This tree should look like this:
*
* 8
* / \
* 3 10
* / \ \
* 1 6 14
* / \ /
* 4 7 13
*/
tree = new Tree<>();
elementsInTree = new int[] {8, 10, 14, 13, 3, 1, 6, 4, 7};
for (int elem : elementsInTree) {
tree.insert(elem);
}
elementsNotInTree = new int[] {34, -3, -10, 12, 74, 5};
}
#Test
public void heightIsLogOfNumLeavesTreeIsPerfect() {
// For a perfect tree, tree.height() == log2(tree.leaves()
// Arrange
Tree<Integer> tree = new Tree<>();
int[] elements = new int[] {8, 3, 10, 1, 6, 9, 14};
int numLeaves = 4;
int logNumLeaves = (int) Math.round(Math.log(numLeaves) / Math.log(2));
for (int elem : elements) {
tree.insert(elem);
}
// Act
int height = tree.height();
// Assert
assertThat(height, equalTo(logNumLeaves));
}
#Test
public void leavesIsCorrectWhenTreeIsPerfect() { //TEST
// A perfect tree has all leaves at the same depth, and all internal nodes
// (i.e. non-leaves) have two children
//
// This test should assert that a perfect tree with 2*n-1 nodes total,
// has exactly n leaves (i.e. that Tree.leaves() returns n).
//
// An example is the perfect three-node tree from the test above:
//
// (1338)
// / \
// (1337) (1396)
// You have to construct your own tree here, with n >= 4
Tree <Integer> tree = new Tree<>();
int n = 4;
for(int i = 0; i>=n; i++) {
tree.insert(i);
int numLeaves = 2*n-1;
int leaves = tree.leaves();
assertThat(leaves,equalTo(numLeaves));
}
}
// Tests for insert/height
#Test
public void insertValuesInAscendingOrderIncrementsHeight() { //TEST
// When inserting elements in ascending order, each element is inserted
// to the right of the deepest node, so the height should increment by
// 1 for each element inserted.
Tree <Integer> tree = new Tree<>();
int val = 100;
for(int i = 0; i < val; i++){
tree.insert(i);
}
int treeHeight = tree.height();
treeHeight++;
assertThat(tree.size(),equalTo(treeHeight));
}
}
for(int i = 0; i>=n; i++) {
tree.insert(i);
The condition of your for loop is always false.
It's awkward that "n" is used in the instructions to describe a tree with n leaves because "n" is traditionally used to describe your node count. But picture a tree with 4 nodes at the bottom, then half that for the prior layer, then half again for the first layer, and you have a tree with 1+2+4 nodes, or 7 nodes total, which coincides with the formula 2*n-1 (2*4-1=7).
#Test
public void leavesIsCorrectWhenTreeIsPerfect() {
int n=4;
int[] balanced=new int[] {4,2,6,1,3,5,7};
for (int i=0; i<balanced.length; i++) {
tree.insert(balanced[i]);
}
int leaves = tree.leaves();
assertThat(balanced.length,equalTo(2*n-1));
assertThat(leaves,equalTo(n));
}
I have an exercise, where I have to implement a priority queue, using a min-heap.
However I cannot use the PriorityClass library, I have to implement it, by myself.
I've managed to do it by far, but, my professor, told me that my insert methods is wrong. He told me, to create an Element class, which contains 2 attributes of type T.These two attributes are (T element and T priority). How can I edit my insert method?
package priorityQueue;
import java.util.ArrayList;
import java.util.Comparator;
import priorityQueueInterfaces.PriorityQueue;
public class BinaryHeap<T> implements PriorityQueue<T>
{
private int currentSize = 0;
private static final int DEFAULT_CAPACITY = 20;
private ArrayList<T> array = null;
private Comparator <? super T> comparator = null;
/**
* Constructor of binary-heap
*/
public BinaryHeap(Comparator <? super T> comparator)
{
currentSize = 0;
array = new ArrayList<>(DEFAULT_CAPACITY + 1);
this.comparator = comparator;
}
/**
* Construct the binary heap from an arrayList
*/
public BinaryHeap(ArrayList<T> array, Comparator <? super T> comparator)
{
this.currentSize = array.size();
this.array = new ArrayList<>(array.size() + 1);
this.comparator = comparator;
for(int i = 0; i < array.size(); i++)
this.array.set(i + 1, array.get(i));
}
/**
* Method which builds the min heap with the minHeapify method
* #throws PriorityQueueException
*/
public void buildMinHeap(ArrayList<T> array, int heapSize) throws PriorityQueueException
{
for(int i = this.currentSize / 2; i > 0;i--)
minHeapify(this.array,i,this.currentSize);
}
/**
* Method which builds the max heap with the maxHeapify method
* #throws PriorityQueueException
*/
public void buildMaxHeap() throws PriorityQueueException
{
for(int i = this.currentSize/2; i > 0; i--)
maxHeapify(this.array,i,this.currentSize);
}
public void buildMaxHeap(ArrayList<T> array, int heapSize)throws PriorityQueueException
{
if(this.array == null)
throw new NullPointerException("ArrayList is null");
if(this.array.size() <= 0 || heapSize <= 0 )
throw new IllegalArgumentException("Illegal Parameters: either the arraylist or the heap size are not valid");
if(heapSize > this.array.size())
heapSize = this.array.size();
for(int i = heapSize/2; i > 0; i--)
maxHeapify(this.array,i,heapSize);
}
/**
* Insert into the priority queue.
* Duplicates are allowed.
* #param element is the item to insert.
*/
public void insert(T element) throws PriorityQueueException
{
if(element == null)
throw new IllegalArgumentException("Element to be inserted, cannot be null!");
if(this.size() + 1 == this.array.size())
extendArray();
this.currentSize = this.size() + 1;
if(this.isEmpty())
this.array.add(0,element);
else
{
this.array.add(element);
int index = this.size() - 1;//indice index = all'elemento appena aggiunto
while( index > 1 && this.comparator.compare(this.array.get(index/2), this.array.get(index)) < 0)
{
swapElements(index, index/2);
index = index / 2;
}
}
}
/**
* #param firstIndex of the element that has to be swapped
* #param secondIndex of the element that has to be swapped
* #throws PriorityQueueException
*/
private void swapElements(int firstIndex,int secondIndex)throws PriorityQueueException
{
T temp = this.array.get(firstIndex);
this.array.set(firstIndex, this.array.get(secondIndex));
this.array.set(secondIndex,temp);
}
}
THAT'S MY ELEMENT CLASS Which I have to use for adding an element with min-priority
package priorityQueue;
public class Element<T>
{
private T element;
private T priority;
public Element(T element,T priority)
{
this.element = element;
this.priority = priority;
}
public void setElement(T element)
{
this.element = element;
}
public void setPriority(T priority)
{
this.priority = priority;
}
public T getElement()
{
return this.element;
}
public T getPriority()
{
return this.priority;
}
}
My method of insert works just fine, but i have to insert also the priority contained in the class element. How to do it?
I am working on this assignment which implements Autocomplete and dictionary. I have sucessfully implemented spellcheck and the addWord() and isWord() functions.
But I am just not able to implement the function which predicts words for AutoCompletions.
package spelling;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
/**
* An trie data structure that implements the Dictionary and the AutoComplete ADT
* #author You
*
*/
public class AutoCompleteDictionaryTrie implements Dictionary, AutoComplete {
private TrieNode root;
private int size;
public AutoCompleteDictionaryTrie()
{
root = new TrieNode();
size=0;
}
/** Insert a word into the trie.
* For the basic part of the assignment (part 2), you should ignore the word's case.
* That is, you should convert the string to all lower case as you insert it. */
public boolean addWord(String word)
{
//TODO: Implement this method.
String Word=word.toLowerCase();
if(isWord(Word))
return false;
HashMap<Character, TrieNode> children=root.children;
for(int i=0; i<Word.length(); i++){
char c = Word.charAt(i);
TrieNode t;
if(children.containsKey(c)){
t = children.get(c);
}else{
t = new TrieNode(""+(c));
children.put(c, t);
}
children = t.children;
if(i==Word.length()-1)
{
t.isWord = true;
size++;
}
}
return true;
}
/**
* Return the number of words in the dictionary. This is NOT necessarily the same
* as the number of TrieNodes in the trie.
*/
public int size()
{
//TODO: Implement this method
return size;
}
/** Returns whether the string is a word in the trie */
#Override
public boolean isWord(String s)
{
// TODO: Implement this method
TrieNode t = searchNode(s.toLowerCase());
if(t != null && t.isWord)
return true;
else
return false;
}
public TrieNode searchNode(String str){
HashMap<Character, TrieNode> children = root.children;
TrieNode t = null;
for(int i=0; i<str.length(); i++){
char c = str.charAt(i);
if(children.containsKey(c)){
t = children.get(c);
children = t.children;
}else{
return null;
}
}
return t;
}
/**
* * Returns up to the n "best" predictions, including the word itself,
* in terms of length
* If this string is not in the trie, it returns null.
* #param text The text to use at the word stem
* #param n The maximum number of predictions desired.
* #return A list containing the up to n best predictions
*/#Override
public List<String> predictCompletions(String prefix, int numCompletions)
{
// TODO: Implement this method
// This method should implement the following algorithm:
// 1. Find the stem in the trie. If the stem does not appear in the trie, return an
// empty list
// 2. Once the stem is found, perform a breadth first search to generate completions
// using the following algorithm:
// Create a queue (LinkedList) and add the node that completes the stem to the back
// of the list.
// Create a list of completions to return (initially empty)
// While the queue is not empty and you don't have enough completions:
// remove the first Node from the queue
// If it is a word, add it to the completions list
// Add all of its child nodes to the back of the queue
// Return the list of completions
List<String> completions=null;
int counter=0;
if (prefix==null){
return Collections.emptyList();
}
prefix=prefix.toLowerCase();
if(isWord(prefix))
completions.add(prefix);
LinkedList nodes = new LinkedList();
TrieNode curr=searchNode(prefix);
nodes.addLast(curr);
while(!nodes.isEmpty() && counter!=numCompletions)
{
if((nodes.removeFirst()).isWord)
completions.add(curr.getText());
TrieNode next = null;
for (Character c : curr.getValidNextCharacters()) {
next = curr.getChild(c);
}
}
return Collections.emptyList();
}
public void checkNull(String word){
if (word==null)
throw new NullPointerException("Null word passed");
}
// For debugging
public void printTree()
{
printNode(root);
}
/** Do a pre-order traversal from this node down */
public void printNode(TrieNode curr)
{
if (curr == null)
return;
System.out.println(curr.getText());
TrieNode next = null;
for (Character c : curr.getValidNextCharacters()) {
next = curr.getChild(c);
printNode(next);
}
}
}
And this is the code of the TrieNode class:
package spelling;
import java.util.HashMap;
import java.util.Set;
/**
* Represents a node in a Trie
* #author UC San Diego Intermediate Programming MOOC Team
*
*/
class TrieNode {
HashMap<Character, TrieNode> children;
private String text; // Maybe omit for space
boolean isWord;
/** Create a new TrieNode */
public TrieNode()
{
children = new HashMap<Character, TrieNode>();
text = "";
isWord = false;
}
/** Create a new TrieNode given a text String to store in it */
public TrieNode(String text)
{
this();
this.text = text;
}
/** Return the TrieNode that is the child when you follow the
* link from the given Character
* #param c The next character in the key
* #return The TrieNode that character links to, or null if that link
* is not in the trie.
*/
public TrieNode getChild(Character c)
{
return children.get(c);
}
/** Inserts this character at this node.
* Returns the newly created node, if c wasn't already
* in the trie. If it was, it does not modify the trie
* and returns null.
* #param c The character that will link to the new node
* #return The newly created TrieNode, or null if the node is already
* in the trie.
*/
public TrieNode insert(Character c)
{
if (children.containsKey(c)) {
return null;
}
TrieNode next = new TrieNode(text + c.toString());
children.put(c, next);
return next;
}
/** Return the text string at this node */
public String getText()
{
return text;
}
/** Set whether or not this node ends a word in the trie. */
public void setEndsWord(boolean b)
{
isWord = b;
}
/** Return whether or not this node ends a word in the trie. */
public boolean endsWord()
{
return isWord;
}
/** Return the set of characters that have links from this node */
public Set<Character> getValidNextCharacters()
{
return children.keySet();
}
}
Even though the algorithm is there I am not able to implement it. Any kind of help would be greatly appreciated.
are you trying to solve this as part of the Coursera's university of San Diego course?
If so then all what you have to do is to follow the algorithm that was written as a comment inside the class.
Any way, I added here a copy of my implementation to this method. Just don't copy and paste it as part of your solution please. Use it as guidance. I added comments in the code to help you understanding my algorithm:
//Trying to find the stem in Trie
String prefixToCheckLowerCase = prefix.toLowerCase();
int completionsCount = 0;
List<String> completions = new LinkedList<String>();
TrieNode traversal = root;
for (int i = 0; i < prefixToCheckLowerCase.length(); i++)
{
if (traversal.getValidNextCharacters().contains(prefixToCheckLowerCase.charAt(i)))
{
traversal = traversal.getChild(prefixToCheckLowerCase.charAt(i));
}
//Means stem not found, returns an empty list
else
return completions;
}
//If current word is an end word, increment the counter and add it to compeltions list
if (traversal.endsWord())
{
completionsCount=1;
completions.add(traversal.getText());
}
List<TrieNode> nodesToBeSearched = new LinkedList<TrieNode>();
List<Character> ChildCharaterList = new LinkedList<Character>(traversal.getValidNextCharacters());
//Filling the list with children of the current node, first level of of the breadth first search
for (int i=0; i<ChildCharaterList.size(); i++)
{
nodesToBeSearched.add(traversal.getChild(ChildCharaterList.get(i)));
}
//while loop for the linked list elements and see if any compeltions exists , inside it we will also check each node children and add them to the list!!!
while (nodesToBeSearched!=null && nodesToBeSearched.size()>0 && completionsCount < numCompletions)
{
TrieNode trieNode = nodesToBeSearched.remove(0);
if (trieNode.endsWord())
{
completionsCount++;
completions.add(trieNode.getText());
}
List<Character> subTrieNodeCholdren = new LinkedList<Character>(trieNode.getValidNextCharacters());
//Adding all next level tries to the linked list , kinda recursive!!!
for (int i=0; i<subTrieNodeCholdren.size();i++)
{
nodesToBeSearched.add(trieNode.getChild(subTrieNodeCholdren.get(i)));
}
}
return completions;
import java.util.ArrayList;
class TrieNode{
char data;
boolean isTerminating;
TrieNode children[];
int childCount;
public TrieNode(char data) {
this.data = data;
isTerminating = false;
children = new TrieNode[26];
childCount = 0;
}
}
public class Trie {
private TrieNode root;
//ArrayList<String> ans=new ArrayList<>();
public Trie() {
root = new TrieNode('\0');
}
private void add(TrieNode root, String word){
if(word.length() == 0){
root.isTerminating = true;
return;
}
int childIndex = word.charAt(0) - 'a';
TrieNode child = root.children[childIndex];
if(child == null){
child = new TrieNode(word.charAt(0));
root.children[childIndex] = child;
root.childCount++;
}
add(child, word.substring(1));
}
public void add(String word){
add(root, word);
}
private void searchHelper(TrieNode root,String word,String ans)
{
try
{
if(word.length()==0)
{
if(root.isTerminating == true)
{
System.out.println(ans);
}
for(int i=0;i<26;i++)
{
TrieNode temp=root.children[i];
if(temp !=null)
{
//ans=ans+temp.data;
//System.out.println("test check "+ans );
searchHelper(temp,word,ans+temp.data);
}
}
}
int childIndex=word.charAt(0)-'a';
TrieNode child=root.children[childIndex];
if(child == null)
{
//System.out.print();
return ;
}
ans=ans+word.charAt(0);
searchHelper(child,word.substring(1),ans);
}
catch(Exception e)
{
//System.out.println("error");
}
}
public void search(String word)
{
String s="";
searchHelper(root,word,s);
}
public void autoComplete(ArrayList<String> input, String word) {
// Complete this function
// Print the output as specified in question
Trie ansTrie = new Trie();
for(int i=0;i<input.size();i++)
{
ansTrie.add(input.get(i));
}
ansTrie.search(word);
}
}
i hope it helps in solving you doubt.
i am already sorry for any indentation errors .
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.stream.Collectors;
public class TrieImpl {
static class Element {
private Trie trie;
private String word;
Element(Trie trie, String word) {
this.trie = trie;
this.word = word;
}
}
static class Trie {
private boolean isLeaf;
private Map<Character, Trie> children;
private Map<Character, Integer> character;
Trie() {
isLeaf = false;
children = new HashMap<>();
character = new HashMap<>();
}
public void insert(String word) {
Trie curr = this;
for (Character ch : word.toCharArray()) {
curr.children.putIfAbsent(ch, new Trie());
int count = (curr.character.get(ch) == null) ? 1 : curr.character.get(ch) + 1;
curr.character.put(ch, count);
curr = curr.children.get(ch);
}
curr.isLeaf = true;
}
public boolean search(String word) {
Trie curr = this;
for (Character ch : word.toCharArray()) {
if (curr.children.get(ch) == null)
return false;
curr = curr.children.get(ch);
}
return curr.isLeaf;
}
public void delete(String word) {
if (search(word)) {
Trie lastSecond = this;
Character charToRemove = word.charAt(0);
Trie curr = this;
int i = -1;
while (i < word.length() && curr != null) {
if (curr.isLeaf && i != word.length() - 1) {
charToRemove = word.charAt(i + 1);
lastSecond = curr;
}
i = i + 1;
if (i < word.length())
curr = curr.children.get(word.charAt(i));
}
lastSecond.children.remove(charToRemove);
}
}
public int findPrefixCount(String word) {
Trie curr = this;
Character lastChar = null;
int count = 0;
for (Character ch : word.toCharArray()) {
if (curr.children.get(ch) == null)
return 0;
if (count < word.length() - 1) {
curr = curr.children.get(ch);
count++;
}
lastChar = ch;
}
if (lastChar != null && curr.character.get(lastChar) != null)
return curr.character.get(lastChar);
else
return 0;
}
public Set<String> autoComplete(String word) {
Trie curr = this;
int count = 0;
String wo = "";
Queue<Element> queue = new LinkedList<>();
Set<String> set = new HashSet<>();
for (Character ch : word.toCharArray()) {
if (count < word.length()) {
curr = curr.children.get(ch);
count++;
wo += ch;
}
}
if (curr != null)
queue.add(new Element(curr, wo));
while (!queue.isEmpty()) {
Element elem = queue.poll();
Trie current = elem.trie;
String temp = elem.word;
if (current != null && current.isLeaf)
set.add(temp);
List<Character> keys = current.character.keySet().stream().collect(Collectors.toList());
for (int i = 0; i < current.children.size(); i++) {
queue.add(new Element(current.children.get(keys.get(i)), temp + keys.get(i)));
}
}
return set;
}
}
public static void main(String[] args) {
Trie head = new Trie();
head.insert("techie");
head.insert("techi");
head.insert("tech");
head.insert("tecabc");
head.insert("tecabk");
head.insert("tecabd");
head.insert("tecalmz");
Set<String> words = head.autoComplete("t");
words.stream().forEach(x -> System.out.println(x));
}
}
I want to initialize an Item Array but can't figure it out.
Here is my code.
public class HashTable<Item> {
private int m; // hash table size
private Item[] T; // hash table
HashTable(int M)
{
m = M;
T = new Item[M];
for(int i=0;i<M;i++){
Item T[i] = null;
}
}
...
...
SOLUTION
T = (Item[])new Object[M];
I think what you need is something like:
for(int i=0;i<M;i++){
T[i] = new Item(); // call some constructor here
}
You have
Item T[i] = ...
in your loop, while it should be just
T[i] = ...
So try these hints.
Also do this:
T = (Item[])new Object[M];
as Kumar suggested in his reply.
The thing is that Item is not really a type here. You need
to read how generics are actually compiled into bytecode,
and you will see what happens under the hood.
You are trying to create the array of Generic type,Please look at this post.
How to create a generic array in Java?
Assuming you created the class item you could call it like this:
public class HashTable
{
private int tableSize; // hash table size
private Item[] table; // hash table
public static void main(String[] args)
{
// where 10 is the number of nodes
Item[] myTable = createHashTable(10);
}
private static Item[] createHashTable(int size)
{
Item[] table = new Item[size];
for(int i = 0; i < table.length; i++)
{
table[i] = new Item(i);
}
}
}
However if you want to see an example of a full HashTable implementation:
/*
* HashTable.java
*
*
*/
/**
* A class that implements a hash table that employs open addressing
* using either linear probing, quadratic probing, or double hashing.
*/
public class HashTable {
/* Private inner class for an entry in the hash table */
private class Entry {
private String key;
private LLList valueList; // all of the values with this key
private boolean hasBeenRemoved; // has this entry been removed?
private Entry(String key, int value) {
this.key = key;
valueList = new LLList();
valueList.addItem(value, 0);
hasBeenRemoved = false;
}
}
// parameters for the second hash function -- see h2() below
private static final int H2_MIN = 5;
private static final int H2_DIVISOR = 11;
// possible types of probing
public static final int LINEAR = 0;
public static final int QUADRATIC = 1;
public static final int DOUBLE_HASHING = 2;
public static final int NUM_PROBE_TYPES = 3;
private Entry[] table; // the hash table itself
private int probeType = LINEAR; // the type of probing
// keeps track of how many times we perform a probe of a given length
private int[] probeLengthCount;
public HashTable(int size, int probeType) {
if (probeType >= 0 && probeType < NUM_PROBE_TYPES)
this.probeType = probeType;
else
throw new IllegalArgumentException("invalid probeType: " +
probeType);
table = new Entry[size];
probeLengthCount = new int[size + 1];
for (int i = 0; i <= size; i++)
probeLengthCount[i] = 0;
}
public HashTable(int size) {
// Call the other constructor to do the work.
this(size, LINEAR);
}
/* first hash function */
private int h1(String key) {
int h1 = key.hashCode() % table.length;
if (h1 < 0)
h1 += table.length;
return h1;
}
/* second hash function */
private int h2(String key) {
int h2 = key.hashCode() % H2_DIVISOR;
if (h2 < 0)
h2 += H2_DIVISOR;
h2 += H2_MIN;
return h2;
}
/*
* probeIncrement - returns the amount by which the current index
* should be incremented to obtain the nth element in the probe
* sequence
*/
private int probeIncrement(int n, int h2) {
if (n <= 0)
return 0;
switch (probeType) {
case LINEAR:
return 1;
case QUADRATIC:
return (2*n - 1);
case DOUBLE_HASHING:
default:
return h2;
}
}
/*
* probe - attempt to find a slot in the hash table for the specified key.
*
* If key is currently in the table, it returns the index of the entry.
* If key isn't in the table, it returns the index of the first empty cell
* in the table.
* If overflow occurs, it returns -1.
*/
private int probe(String key) {
int i = h1(key); // first hash function
int h2 = h2(key); // second hash function
int positionsChecked = 1;
// keep probing until we get an empty position or a match
while (table[i] != null && !key.equals(table[i].key)) {
if (positionsChecked == table.length) {
probeLengthCount[positionsChecked]++;
return -1;
}
i = (i + probeIncrement(positionsChecked, h2)) % table.length;
positionsChecked++;
}
probeLengthCount[positionsChecked]++;
return i;
}
/**
* insert - insert the specified (key, value) pair in the hash table
*/
public void insert(String key, int value) {
if (key == null)
throw new IllegalArgumentException("key must be non-null");
int i = h1(key);
int h2 = h2(key);
int positionsChecked = 1;
int firstRemoved = -1;
while (table[i] != null && !key.equals(table[i].key)) {
if (table[i].hasBeenRemoved && firstRemoved == -1)
firstRemoved = i;
if (positionsChecked == table.length)
break;
i = (i + probeIncrement(positionsChecked, h2)) % table.length;
positionsChecked++;
}
probeLengthCount[positionsChecked]++;
if (table[i] != null && key.equals(table[i].key))
table[i].valueList.addItem(value, 0);
else if (firstRemoved != -1)
table[firstRemoved] = new Entry(key, value);
else if (table[i] == null)
table[i] = new Entry(key, value);
else
throw new RuntimeException("overflow occurred");
}
/**
* search - search for the specified key, and return the
* associated list of values, or null if the key is not in the
* table
*/
public LLList search(String key) {
if (key == null)
throw new IllegalArgumentException("key must be non-null");
int i = probe(key);
if (i == -1 || table[i] == null)
return null;
else
return table[i].valueList;
}
/**
* remove - remove from the table the entry for the specified key
*/
public void remove(String key) {
if (key == null)
throw new IllegalArgumentException("key must be non-null");
int i = probe(key);
if (i == -1 || table[i] == null)
return;
table[i].key = null;
table[i].valueList = null;
table[i].hasBeenRemoved = true;
}
/**
* printStats - print the statistics for the table -- i.e., the
* number of keys and items, and stats for the number of times
* that probes of different lengths were performed
*/
public void printStats() {
int numProbes = 0;
int probeLengthSum = 0;
int numKeys = 0;
for (int i = 0; i < table.length; i++) {
if (table[i] != null && !table[i].hasBeenRemoved)
numKeys++;
}
System.out.println("\n" + numKeys + " keys");
System.out.println("probe-length stats:");
System.out.println("length\tcount");
for (int i = 1; i <= table.length; i++) {
if (probeLengthCount[i] != 0)
System.out.println(i + "\t" + probeLengthCount[i]);
numProbes += probeLengthCount[i];
probeLengthSum += (probeLengthCount[i] * i);
}
System.out.println("average probe length = " +
(double)probeLengthSum / numProbes);
}
}
Here is the second file for a Linked-Linked-List
/*
* LLList.java
*
*
*/
import java.util.*;
/**
* A class that implements our simple List interface using a linked list.
* The linked list includes a dummy head node that allows us to avoid
* special cases for insertion and deletion at the front of the list.
*/
public class LLList implements List {
// Inner class for a node. We use an inner class so that the LLList
// methods can access the instance variables of the nodes.
private class Node {
private Object item;
private Node next;
private Node(Object i, Node n) {
item = i;
next = n;
}
}
private Node head; // dummy head node
private int length; // # of items in the list
/**
* Constructs a LLList object for a list that is initially empty.
*/
public LLList() {
head = new Node(null, null);
length = 0;
}
/*
* getNode - private helper method that returns a reference to the
* ith node in the linked list. It assumes that the value of the
* parameter is valid.
*
* If i == -1, it returns a reference to the dummy head node.
*/
private Node getNode(int i) {
Node trav = head;
int travIndex = -1;
while (travIndex < i) {
travIndex++;
trav = trav.next;
}
return trav;
}
/** getItem - returns the item at position i in the list */
public Object getItem(int i) {
if (i < 0 || i >= length)
throw new IndexOutOfBoundsException();
Node n = getNode(i);
return n.item;
}
/**
* addItem - adds the specified item at position i in the list,
* shifting the items that are currently in positions i, i+1, i+2,
* etc. to the right by one. Always returns true, because the list
* is never full.
*
* We don't need a special case for insertion at the front of the
* list (i == 0), because getNode(0 - 1) will return the dummy
* head node, and the rest of insertion can proceed as usual.
*/
public boolean addItem(Object item, int i) {
if (i < 0 || i > length)
throw new IndexOutOfBoundsException();
Node newNode = new Node(item, null);
Node prevNode = getNode(i - 1);
newNode.next = prevNode.next;
prevNode.next = newNode;
length++;
return true;
}
/**
* removeItem - removes the item at position i in the list,
* shifting the items that are currently in positions i+1, i+2,
* etc. to the left by one. Returns a reference to the removed
* object.
*
* Here again, we don't need a special case for i == 0 (see the
* note accompanying addItem above).
*/
public Object removeItem(int i) {
if (i < 0 || i >= length)
throw new IndexOutOfBoundsException();
Node prevNode = getNode(i - 1);
Object removed = prevNode.next.item;
prevNode.next = prevNode.next.next;
length--;
return removed;
}
/** length - returns the number of items in the list */
public int length() {
return length;
}
/**
* isFull - always returns false, because the linked list can
* grow indefinitely and thus the list is never full.
*/
public boolean isFull() {
return false;
}
/**
* toString - converts the list into a String of the form
* [ item0 item1 ... ]
*/
public String toString() {
String str = "[ ";
Node trav = head.next; // skip over the dummy head node
while (trav != null) {
str += (trav.item + " ");
trav = trav.next;
}
str += "]";
return str;
}
/**
* iterator - returns an iterator for this list
*/
public ListIterator iterator() {
return new LLListIterator();
}
/*
*** private inner class for an iterator over an LLList ***
*/
private class LLListIterator implements ListIterator {
private Node nextNode; // the next node to visit
private Node lastVisitedNode; // the most recently visited node
public LLListIterator() {
nextNode = head.next;
lastVisitedNode = null;
}
/**
* hasNext - does the iterator have additional items to visit?
*/
public boolean hasNext() {
return (nextNode != null);
}
/**
* next - returns a reference to the next Object in the iteration
*/
public Object next() {
if (nextNode == null)
throw new NoSuchElementException();
Object item = nextNode.item;
lastVisitedNode = nextNode;
nextNode = nextNode.next;
return item;
}
}
}
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.