NullPointerException when deleting a trie word - java

Below is the code. The array index represents the small characters(a-z) and index is 26 (number of characters in english alphabets). It is a dictionary of words in which the children[character ascii value-97] points to the next node. The end of word is given bool terminal=true.
All functions are recursive. In delete function, we have to traverse to the end of the word character by character. While traversing, on the second call of recursive delete, I lose all my references and NullPointerException occurs.
The line of code which is making trouble has a comment in front of it. First there is a check if word exist in dictionary or not.
import java.io.File;
import java.util.Scanner;
public class xxx {
public static void main(String[] args) {
Trie trie = new Trie();
if (trie.delete(word)) {
System.out.println("Word deleted");
} else {
System.out.println("Word not present");
}
break;
}
case "S": { //Search for the word
String word = tokens[1];
if (trie.isPresent(word)) {
System.out.println("Word found");
} else {
System.out.println("Word not found");
}
}
This class just calls the recursive functions of the Node class. The trie class gets call from the main class and then shifts the data to recursive functions in Node class
class Trie {
Node root;
public Trie() {
root = new Node();
}
boolean isPresent(String s) { // returns true if s is present, false otherwise
current = root;
for (int i = 0; i < s.length(); i++) {
if (current.children[(int) s.charAt(i) - 97] == null) {
return false;
} else {
current = current.children[(int) s.charAt(i) - 97];
}
}
if (current.terminal == false) {
return false;
}
return true;
}
boolean delete(String s) { // returns false if s is not present, true otherwise
if (!isPresent(s)) {
return false;
}
root.delete(root,s);
return true;
}
int membership() { // returns the number of words in the data structure
return root.membership(root, 0);
}
void listAll() { // list all members of the Trie in alphabetical orber
root.listAll(root, "");
}
}
The children[ascii value-97] will reference a node and this link will represent alphabetic character. The outDegree will make sure that only the given string is deleted. This class has all recursive functions.
class Node {
boolean terminal;
int outDegree;
Node[] children;
public Node() {
terminal = false;
outDegree = 0;
children = new Node[26];
}
public void delete(Node x, String s) {
if (s.length() > 1){
if(i<s.length())
delete(children[s.charAt(0)-97],s.substring(1)); //this is where problem occurs
}
else if(children[((int)s.charAt(0))-97].outDegree>0)
terminal =false;
else if(children[((int)s.charAt(0))-97].outDegree==0){
children[((int)s.charAt(0))-97]=null;
return;
}
if(children[s.charAt(0)-97].outDegree==0)
children[s.charAt(0)-97]=null;
}
}

Your problem is not in the line of code you commented. Your problem is how you initialized the array:
children = new Node[26];
This line of code allocates memory of the array. However, the value of each individual element of the array is set to NULL for object references, unicode NULL character for char primitives, false for boolean primitives, and to 0 for number primitives. If you want this to work, you must initialize the array properly.

Related

How to implement Autocomplete using Trie with a HashMap?

Here below is the code with HashMap implementation of Trie. But I am not sure how to implement the autocomplete part. I see how people have used LinkedList to implement Trie, but I want to understand with HashMap. Any help appreciated. I have pasted the code below for my Trie.
Is there a way to look for a prefix, then go to the end of the prefix and look for its children and return them back as strings? And if so, how to achieve using HashMap implementation. Or shouldn't I even do this with HashMap and go for LinkedList. And I am not sure, why one is better than the other?
public class TrieNode {
Map<Character, TrieNode> children;
boolean isEndOfWord;
public TrieNode() {
isEndOfWord = false;
children = new HashMap<>();
}
}
public class TrieImpl {
private TrieNode root;
public TrieImpl() {
root = new TrieNode();
}
// iterative insertion into Trie Data Structure
public void insert(String word) {
if (searchTrie(word))
return;
TrieNode current = root;
for(int i=0; i<word.length(); i++) {
char ch = word.charAt(i);
TrieNode node = current.children.get(ch);
if(node == null) {
node = new TrieNode();
current.children.put(ch, node);
}
current = node;
}
current.isEndOfWord = true;
}
// search iteratively
public boolean searchTrie(String word) {
TrieNode current = root;
for(int i=0; i < word.length(); i++) {
char ch = word.charAt(i);
TrieNode node = current.children.get(ch);
if(node == null) {
return false;
}
current = node;
}
return current.isEndOfWord;
}
// delete a word recursively
private boolean deleteRecursive(TrieNode current, String word, int index) {
if(index == word.length()) {
if(!current.isEndOfWord) {
return false;
}
current.isEndOfWord = false;
return current.children.size() == 0;
}
char ch = word.charAt(index);
TrieNode node = current.children.get(ch);
if(node == null) {
return false;
}
boolean shouldDeleteCurrentNode = deleteRecursive(node, word, index+1);
if(shouldDeleteCurrentNode) {
current.children.remove(ch);
return current.children.size() == 0;
}
return false;
}
// calling the deleteRecursively function
public boolean deleteRecursive(String word) {
return deleteRecursive(root, word, 0);
}
public static void main(String[] args) {
TrieImpl obj = new TrieImpl();
obj.insert("amazon");
obj.insert("amazon prime");
obj.insert("amazing");
obj.insert("amazing spider man");
obj.insert("amazed");
obj.insert("alibaba");
obj.insert("ali express");
obj.insert("ebay");
obj.insert("walmart");
boolean isExists = obj.searchTrie("amazing spider man");
System.out.println(isExists);
}
}
I was in hurry finding some other solution here, but this is
interesting question.
Answering this-
Is there a way to look for a prefix, then go to the end of the prefix
and look for its children and return them back as strings?
Yes, why not, if you have prefix ama ,now go to your searchTrie method, and when you are done and out of the loop. then, you have current variable pointing to a(last character from ama)
you can then write a method as below -
public List<String> getPrefixStrings(TrieNode current){
// DO DFS here and put all character with isEndOfWord = true in the list
// keep on recursing to this same method and adding to the list
// then return the list
}

BST String Traversal

I'm trying to implement an inorder, preorder, and postorder traversal algorithm for my BST. It seems that the inorder algorithm is working so far, but it's only returning the first character of the word. I realize that I'm returning char c, but I'm confused on how I would make it return the entire word. Any help would be highly appreciated!
package main;
import java.io.*;
import java.util.*;
// Node class
class Node
{
char c;
boolean end;
Node left, right;
public Node(char c)
{
this.c = c;
this.end = false;
this.left = null;
this.right = null;
}
}
class BinarySearchTree
{
private Node root;
public BinarySearchTree()
{
root = null;
}
public void addValue(String s)
{
root = addValue(root, s, 0);
}
private Node addValue(Node x, String s, int d)
{
char c = s.charAt(d);
if (x == null)
x = new Node(c);
if (c < x.c)
x.left = addValue(x.left, s, d);
else if (c > x.c)
x.right = addValue(x.right, s, d);
else x.end = true;
return x;
}
public boolean search(String s)
{
return search(root, s, 0);
}
private boolean search(Node x, String s, int d)
{
if (x == null)
return false;
char c = s.charAt(d);
if (c < x.c)
return search(x.left, s, d);
else if (c > x.c)
return search(x.right, s, d);
else
return x.end;
}
public void inorder(){
inorder(root);
}
private void inorder(Node r){
if (r != null){
inorder(r.left);
System.out.print(r.c);
inorder(r.right);
}
}
}
public class Project2
{
public static void main(String[] args) throws Exception
{
BinarySearchTree tree = new BinarySearchTree(); // Make new BST object
// Variable for scanned word
String token = "";
// Use scanner for input file
Scanner scan = new Scanner(new File("10words.txt")).useDelimiter("\\s+");
//Check for next line in text file
while (scan.hasNext())
{
token = scan.next();
tree.addValue(token);
}
scan.close();
tree.inorder();
Scanner inputWord = new Scanner(System.in);
System.out.print("\nEnter a word to search: ");
String word = inputWord.next().toLowerCase();
if(tree.search(word) == false){
System.out.println("Word NOT Found!");
} else{
System.out.println("Word Found!");
}
inputWord.close();
}
}
I did not look at your inorder code but you said it works so I'll believe you.
However I did take a look at your addValue code and you only save the first character here. No wonder you can't get the entire word back, you just don't save it :P
Instead, you should change your Node class to accept a String instead of a character. You won't need the d parameter in your addValue method then either.
The Java String class provides the .compareTo () method in order to lexicographically compare Strings. You can use it with string.compareTo(otherString)
This method will return a value < 0, equal to 0 or > 0.
< 0 means string is lexicographically smaller than otherString (for example: "Apple" would be smaller than "Banana")
= 0 means it's the exact same word
> 0 means string is bigger than otherString (for example: "Banana" would be bigger than "Apple")
your addValue method looks like it is incorrect. it only modifies the root, then character will be equal, so it returns. In particular d is never modified.
On a more fondamental level, a BST would be appropriate to look for a character in a tree, not for looking for a String. If you want to look for a word, you can use a Trie instead (which is not a binary tree).

Tree printing extra characters

public class TreeWords {
public static void main (String[] args){
Tree tree = new Tree();
System.out.println("Enter your string.");
Scanner in = new Scanner(System.in);
String input = in.next();
for (char ch : input.toCharArray()) {
Tree tmp = new Tree(ch);
tree.insert(tree, tmp);
}
tree.printInOrder(tree);
}
}
class Tree {
//Tree variables
char letter;
Tree left, right;
//Constructors
public Tree(){
left = right = null;
}
public Tree(char input) {
left = right = null;
letter = input;
}
//Methods
public void printInOrder(Tree root) {
if (root == null) return;
printInOrder(root.left);
System.out.print(root.letter);
printInOrder(root.right);
}
public void insert(Tree root, Tree tmp) {
if (root == null) {
root = tmp;
return;
}
if (root.left == null) {
root.left = tmp;
return;
}
if (root.right == null) {
root.right = tmp;
return;
}
insert(root.left, tmp);
insert(root.right, tmp);
}
}
This is my sample code for a small program that I'm working on. Basically, it is supposed to add a character to each tree node. But somehow, there seems to be either printing extra characters, or adding extra characters.
For example:
Input : aaa
Output : aaaa
Input : hello
Output : oloholo�oloeolo
There's a couple of problems here. These two will hopefully get you started
The first is that parameters in Java are pass-by-value, so assigning a value to them will not be visible outside the method. So the first four lines of 'insert' do nothing.
The second is that once a node is 'full' (i.e. both left and right are non-null) you are inserting the next value into both the left and right sub-trees.
It's also possible that you're missing a '<' comparison in the insert method too, but I'm not sure if 'printInOrder' is referring to insert order or lexicographic order.

Linked List stack/ Generics implementation (homework)

I am trying to build a palindrome checker using stacks and a Linked List. I am using generics in order to reuse the nodes and structures to complete two parts of this assignment (to accomplish something different in the next part).
The program is not pushing the letters onto the stack- it is returning nulls. I believe the problem is with the construction of the push method, either in the LinkedStack construction, or the StackDriver implementation, or both. I am just not sure what I am doing wrong; I have tried a multitude of alternatives, and have looked up and tried other methods to construct the push methods but then I get errors and can’t get the program to run at all. (I realize the 2 push methods I have here are different- these are 2 versions I have tried). Should I be looking at some type of boxing for the char c to use the wrapper class?
The program has been set back to the last point at which it ran. The “reversed” popped element seems to be getting the correct amount of characters though- why?
I realize there are other problems with this program as well but I feel like I can’t address them until I get past this stumbling block. Any assistance would be appreciated- thank you!
Mike
The given interface:
public interface Stack<E> {
void push(E data);
E pop();
boolean isEmpty();
int size();
E stackTop();
void clear();
}
The Node and methods:
public class Node<E> {
// create the node structure
private E data;
private Node<E> next;
// getters and setters
public E getData() {
return data;
}
public void setData(E data) {
this.data = data;
}
public Node<E> getNext() {
return next;
}
public void setNext(Node<E> next) {
this.next = next;
}
}
The Stack:
import java.util.EmptyStackException;
public class LinkedStack<E> implements Stack<E>{
// Create the head and nodeCount variables
private Node<E> head;
private int nodeCount;
// also need to be able to convert letters to capitals.
// constructor for the LinkedStack
public LinkedStack()
{
clear();
}
// A method to push the data onto a stack and increment the node count
public void push(E data) {
head = new Node<E>();
nodeCount++;
}
// pop the head off of the stack and decrement the node count
public E pop() {
E item;
if (head == null)
throw new EmptyStackException();
item = head.getData();
head = head.getNext();
nodeCount--;
return item;
}
// Check if the stack is empty
public boolean isEmpty() {
if (head == null);
return true;
}
// check the size of the node
public int size() {
return nodeCount;
}
// this is the peek method
public E stackTop()
{
if (head == null)
throw new EmptyStackException();
return head.getData();
}
// clear the Linked Stack
public void clear() {
head = null;
nodeCount = 0;
}
// convert to text
public String toString() {
String rtn = "";
if (nodeCount == 0) {
rtn += "<empty>";
}
else {
Node<E> t = head;
while (t != null){
/* return the node data on a line with the head node data
at the beginning of the line and the arrow pointing to
each successive node*/
rtn += t.getData() + "->";
// go on to the next
t = t.getNext();
}
rtn += "null";
}
return rtn;
}
}
And the driver:
import java.util.Iterator;
import java.util.Scanner;
public class StackDriver<E> implements Iterator<E>{
/**
* #param args
*/
public static void main(String[] args) {
//Initialize the driver
StackDriver run = new StackDriver();
run.doIt();
}
public void doIt() {
// gather the input
Scanner keyboard = new Scanner(System.in);
System.out.println("Please enter a phrase. This program will verify" +
" if the phrase is a palindrome.");
// holder for the phrase
String phrase;
// holder for the reversed phrase
String reversed = "";
phrase = keyboard.nextLine().toUpperCase();
System.out.println("You entered: "+ phrase);
// create the two stacks for the characters
LinkedStack<E> alpha = new LinkedStack<E>();
LinkedStack<E> punctuation = new LinkedStack<E>();
//------------------------------------------
for(int i=0; i<phrase.length(); i++)
{
// if the character is a letter, push it onto the letters stack
char c = phrase.charAt(i);
if (true == Character.isLetter(c))
{
// (testing purposes only- remove next line)
System.out.println("LETTER");
String A = Character.toString(c);
// push the letter onto the stack
alpha.push((E) new Node<E>());
}
// else push it onto the characters stack
else
{
// (testing purposes only- remove next line)
System.out.println("NOT LETTER");
String B = Character.toString(c);
// push the character onto the stack
punctuation.push((E) new String(B));
}
// then pop the letters stack
while (!alpha.isEmpty());
{
reversed += alpha.pop();
}
}
//------------------------------------------
// if it equals the String phrase
if (reversed == phrase)
// it is a palindrome
System.out.println("The phrase you entered is a palindrome");
else
System.out.println("The phrase you entered is NOT a palindrome");
System.out.println("phrase: " + phrase);
System.out.println("alpha: " + alpha);
System.out.println("reversed: " + reversed);
}
#Override
public boolean hasNext() {
// TODO Auto-generated method stub
return true;
}
#Override
public E next() {
// TODO Auto-generated method stub
return null;
}
#Override
public void remove() {
// TODO Auto-generated method stub
}
}
And the result:
Please enter a phrase. This program will verify if the phrase is a palindrome.
mom
You entered: MOM
LETTER
LETTER
LETTER
The phrase you entered is NOT a palindrome
phrase: MOM
alpha: <empty>
reversed: nullnullnull
If I got your question properly, I think the issue is indeed your push method in the LinkedStack class. Take a look.
public void push(E data) {
head = new Node<E>();
nodeCount++;
}
You create a new Node, assign it to head and increment the number of nodes of your stack, but you never actually link the older head or populate the new current head, you just replace the head with a new node that has no previous or next element.
// A method to push the data onto a stack and increment the node count
public void push(E data) {
head = new Node<E>();
nodeCount++;
}
This method is wrong. When you push a new node, you need to set it's next to the current head. You also need to populate that node with your data.
This may or may not be your whole problem, but it's definitely part of it...
// A method to push the data onto a stack and increment the node count
public void push(E data) {
head = new Node<E>();
nodeCount++;
}
always replaces head with a new node that contains no data, even though an object of E type was passed. You need to call head.setData(data).
you need to also add to the list rather than replace the head.
if( head == null )
{
head = new Node();
head.setData(data);
}
else {
Node n = new Node();
n.setData(data);
Node last = ...; // leaving getting the last node in the list as an exercise for the reader
last.setNext(n);
}

Getting a list of words from a Trie

I'm looking to use the following code to not check whether there is a word matching in the Trie but to return a list all words beginning with the prefix inputted by the user. Can someone point me in the right direction? I can't get it working at all.....
public boolean search(String s)
{
Node current = root;
System.out.println("\nSearching for string: "+s);
while(current != null)
{
for(int i=0;i<s.length();i++)
{
if(current.child[(int)(s.charAt(i)-'a')] == null)
{
System.out.println("Cannot find string: "+s);
return false;
}
else
{
current = current.child[(int)(s.charAt(i)-'a')];
System.out.println("Found character: "+ current.content);
}
}
// If we are here, the string exists.
// But to ensure unwanted substrings are not found:
if (current.marker == true)
{
System.out.println("Found string: "+s);
return true;
}
else
{
System.out.println("Cannot find string: "+s +"(only present as a substring)");
return false;
}
}
return false;
}
}
I faced this problem while trying to make a text auto-complete module. I solved the problem by making a Trie in which each node contains it's parent node as well as children. First I searched for the node starting at the input prefix. Then I applied a Traversal on the Trie that explores all the nodes of the sub-tree with it's root as the prefix node. whenever a leaf node is encountered, it means that the end of a word starting from input prefix has been found. Starting from that leaf node I iterate through the parent nodes getting parent of parent, and reach the root of the subtree. While doing so I kept adding the keys of nodes in a stack. In the end I took the prefix and started appended it by popping the stack. I kept on saving the words in an ArrayList. At the end of the traversal I get all the words starting from the input prefix. Here is the code with usage example:
class TrieNode
{
char c;
TrieNode parent;
HashMap<Character, TrieNode> children = new HashMap<Character, TrieNode>();
boolean isLeaf;
public TrieNode() {}
public TrieNode(char c){this.c = c;}
}
-
public class Trie
{
private TrieNode root;
ArrayList<String> words;
TrieNode prefixRoot;
String curPrefix;
public Trie()
{
root = new TrieNode();
words = new ArrayList<String>();
}
// Inserts a word into the trie.
public void insert(String word)
{
HashMap<Character, TrieNode> children = root.children;
TrieNode crntparent;
crntparent = root;
//cur children parent = root
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);
t.parent = crntparent;
children.put(c, t);
}
children = t.children;
crntparent = t;
//set leaf node
if(i==word.length()-1)
t.isLeaf = true;
}
}
// Returns if the word is in the trie.
public boolean search(String word)
{
TrieNode t = searchNode(word);
if(t != null && t.isLeaf){return true;}
else{return false;}
}
// Returns if there is any word in the trie
// that starts with the given prefix.
public boolean startsWith(String prefix)
{
if(searchNode(prefix) == null) {return false;}
else{return true;}
}
public TrieNode searchNode(String str)
{
Map<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;}
}
prefixRoot = t;
curPrefix = str;
words.clear();
return t;
}
///////////////////////////
void wordsFinderTraversal(TrieNode node, int offset)
{
// print(node, offset);
if(node.isLeaf==true)
{
//println("leaf node found");
TrieNode altair;
altair = node;
Stack<String> hstack = new Stack<String>();
while(altair != prefixRoot)
{
//println(altair.c);
hstack.push( Character.toString(altair.c) );
altair = altair.parent;
}
String wrd = curPrefix;
while(hstack.empty()==false)
{
wrd = wrd + hstack.pop();
}
//println(wrd);
words.add(wrd);
}
Set<Character> kset = node.children.keySet();
//println(node.c); println(node.isLeaf);println(kset);
Iterator itr = kset.iterator();
ArrayList<Character> aloc = new ArrayList<Character>();
while(itr.hasNext())
{
Character ch = (Character)itr.next();
aloc.add(ch);
//println(ch);
}
// here you can play with the order of the children
for( int i=0;i<aloc.size();i++)
{
wordsFinderTraversal(node.children.get(aloc.get(i)), offset + 2);
}
}
void displayFoundWords()
{
println("_______________");
for(int i=0;i<words.size();i++)
{
println(words.get(i));
}
println("________________");
}
}//
Example
Trie prefixTree;
prefixTree = new Trie();
prefixTree.insert("GOING");
prefixTree.insert("GONG");
prefixTree.insert("PAKISTAN");
prefixTree.insert("SHANGHAI");
prefixTree.insert("GONDAL");
prefixTree.insert("GODAY");
prefixTree.insert("GODZILLA");
if( prefixTree.startsWith("GO")==true)
{
TrieNode tn = prefixTree.searchNode("GO");
prefixTree.wordsFinderTraversal(tn,0);
prefixTree.displayFoundWords();
}
if( prefixTree.startsWith("GOD")==true)
{
TrieNode tn = prefixTree.searchNode("GOD");
prefixTree.wordsFinderTraversal(tn,0);
prefixTree.displayFoundWords();
}
After building Trie, you could do DFS starting from node, where you found prefix:
Here Node is Trie node, word=till now found word, res = list of words
def dfs(self, node, word, res):
# Base condition: when at leaf node, add current word into our list
if EndofWord at node:
res.append(word)
return
# For each level, go deep down, but DFS fashion
# add current char into our current word.
for w in node:
self.dfs(node[w], word + w, res)
The simplest solution is to use a depth-first search.
You go down the trie, matching letter by letter from the input. Then, once you have no more letter to match, everything under that node are strings that you want. Recursively explore that whole subtrie, building the string as you go down to its nodes.
This is easier to solve recursively in my opinion. It would go something like this:
Write a recursive function Print that prints all the nodes in the trie rooted in the node you give as parameter. Wiki tells you how to do this (look at sorting).
Find the last character of your prefix, and the node that is labeled with the character, going down from the root in your trie. Call the Print function with this node as the parameter. Then just make sure you also output the prefix before each word, since this will give you all the words without their prefix.
If you don't really care about efficiency, you can just run Print with the main root node and only print those words that start with the prefix you're interested in. This is easier to implement but slower.
You need to traverse the sub-tree starting at the node you found for the prefix.
Start in the same way, i.e. finding the correct node. Then, instead of checking its marker, traverse that tree (i.e. go over all its descendants; a DFS is a good way to do it) , saving the substring used to reach the "current" node from the first node.
If the current node is marked as a word, output* the prefix + substring reached.
* or add it to a list or something.
I built a trie once for one of ITA puzzles
public class WordTree {
class Node {
private final char ch;
/**
* Flag indicates that this node is the end of the string.
*/
private boolean end;
private LinkedList<Node> children;
public Node(char ch) {
this.ch = ch;
}
public void addChild(Node node) {
if (children == null) {
children = new LinkedList<Node>();
}
children.add(node);
}
public Node getNode(char ch) {
if (children == null) {
return null;
}
for (Node child : children) {
if (child.getChar() == ch) {
return child;
}
}
return null;
}
public char getChar() {
return ch;
}
public List<Node> getChildren() {
if (this.children == null) {
return Collections.emptyList();
}
return children;
}
public boolean isEnd() {
return end;
}
public void setEnd(boolean end) {
this.end = end;
}
}
Node root = new Node(' ');
public WordTree() {
}
/**
* Searches for a strings that match the prefix.
*
* #param prefix - prefix
* #return - list of strings that match the prefix, or empty list of no matches are found.
*/
public List<String> getWordsForPrefix(String prefix) {
if (prefix.length() == 0) {
return Collections.emptyList();
}
Node node = getNodeForPrefix(root, prefix);
if (node == null) {
return Collections.emptyList();
}
List<LinkedList<Character>> chars = collectChars(node);
List<String> words = new ArrayList<String>(chars.size());
for (LinkedList<Character> charList : chars) {
words.add(combine(prefix.substring(0, prefix.length() - 1), charList));
}
return words;
}
private String combine(String prefix, List<Character> charList) {
StringBuilder sb = new StringBuilder(prefix);
for (Character character : charList) {
sb.append(character);
}
return sb.toString();
}
private Node getNodeForPrefix(Node node, String prefix) {
if (prefix.length() == 0) {
return node;
}
Node next = node.getNode(prefix.charAt(0));
if (next == null) {
return null;
}
return getNodeForPrefix(next, prefix.substring(1, prefix.length()));
}
private List<LinkedList<Character>> collectChars(Node node) {
List<LinkedList<Character>> chars = new ArrayList<LinkedList<Character>>();
if (node.getChildren().size() == 0) {
chars.add(new LinkedList<Character>(Collections.singletonList(node.getChar())));
} else {
if (node.isEnd()) {
chars.add(new LinkedList<Character>
Collections.singletonList(node.getChar())));
}
List<Node> children = node.getChildren();
for (Node child : children) {
List<LinkedList<Character>> childList = collectChars(child);
for (LinkedList<Character> characters : childList) {
characters.push(node.getChar());
chars.add(characters);
}
}
}
return chars;
}
public void addWord(String word) {
addWord(root, word);
}
private void addWord(Node parent, String word) {
if (word.trim().length() == 0) {
return;
}
Node child = parent.getNode(word.charAt(0));
if (child == null) {
child = new Node(word.charAt(0));
parent.addChild(child);
} if (word.length() == 1) {
child.setEnd(true);
} else {
addWord(child, word.substring(1, word.length()));
}
}
public static void main(String[] args) {
WordTree tree = new WordTree();
tree.addWord("world");
tree.addWord("work");
tree.addWord("wolf");
tree.addWord("life");
tree.addWord("love");
System.out.println(tree.getWordsForPrefix("wo"));
}
}
You would need to use a List
List<String> myList = new ArrayList<String>();
if(matchingStringFound)
myList.add(stringToAdd);
After your for loop, add a call to printAllStringsInTrie(current, s);
void printAllStringsInTrie(Node t, String prefix) {
if (t.current_marker) System.out.println(prefix);
for (int i = 0; i < t.child.length; i++) {
if (t.child[i] != null) {
printAllStringsInTrie(t.child[i], prefix + ('a' + i)); // does + work on (String, char)?
}
}
}
The below recursive code can be used where your TrieNode is like this:
This code works fine.
TrieNode(char c)
{
this.con=c;
this.isEnd=false;
list=new ArrayList<TrieNode>();
count=0;
}
//--------------------------------------------------
public void Print(TrieNode root1, ArrayList<Character> path)
{
if(root1==null)
return;
if(root1.isEnd==true)
{
//print the entire path
ListIterator<Character> itr1=path.listIterator();
while(itr1.hasNext())
{
System.out.print(itr1.next());
}
System.out.println();
return;
}
else{
ListIterator<TrieNode> itr=root1.list.listIterator();
while(itr.hasNext())
{
TrieNode child=itr.next();
path.add(child.con);
Print(child,path);
path.remove(path.size()-1);
}
}
Simple recursive DFS algorithm can be used to find all words for a given prefix.
Sample Trie Node:
static class TrieNode {
Map<Character, TrieNode> children = new HashMap<>();
boolean isWord = false;
}
Method to find all words for a given prefix:
static List<String> findAllWordsForPrefix(String prefix, TrieNode root) {
List<String> words = new ArrayList<>();
TrieNode current = root;
for(Character c: prefix.toCharArray()) {
TrieNode nextNode = current.children.get(c);
if(nextNode == null) return words;
current = nextNode;
}
if(!current.children.isEmpty()) {
findAllWordsForPrefixRecursively(prefix, current, words);
} else {
if(current.isWord) words.add(prefix);
}
return words;
}
static void findAllWordsForPrefixRecursively(String prefix, TrieNode node, List<String> words) {
if(node.isWord) words.add(prefix);
if(node.children.isEmpty()) {
return;
}
for(Character c: node.children.keySet()) {
findAllWordsForPrefixRecursively(prefix + c, node.children.get(c), words);
}
}
Complete code can be found at below:
TrieDataStructure Example

Categories