Array-based Trie Implementation. Non-null value in the child array - java

I'm trying to understand the array-based implementation of Trie from http://www.programcreek.com/2014/05/leetcode-implement-trie-prefix-tree-java/ (see Java Solution 2 - Improve Performance by Using an Array).
public void insert(String word) {
TrieNode p = root;
for(int i = 0; i < word.length(); i++) {
char c = word.charAt(i);
int index = c - 'a';
if(p.arr[index] == null) {
TrieNode temp = new TrieNode();
p.arr[index] = temp;
p = temp;
} else {
p = p.arr[index];
}
}
p.isEnd = true;
}
I'm not sure the else branch is ever executed. What am I missing?
Update 1
The given word only contains lower-case English letters

The first time you call this function, the else branch will indeed not execute. However, as the Trie gets populated, it is very possible that p.arr[index] is not null.
For example, calling insert("i") will cause add a new TrieNode at root.arr['i' - 'a']. Calling the function a second time, for example with insert("it"), will result in the check p.arr[index] == null returning false because the first insert already added the TrieNode for i at the root node.
You can test this out with the following main function (and putting a breakpoint or println statement in the else branch)
public static void main (String[] args)
{
Trie t = new Trie();
t.insert("i");
t.insert("it");
}

That looks to me pretty much like a bug. If c-'a'>26 then p.arr[index] won't be null but will raise an ArrayIndexOutOfBounds exception.

Related

Did I set up this BST correctly? If so, how can I use it in other methods?

My goal is to create a Binary Search Tree (BST) from a given string, using a preorder traversal. Eventually, I will use the BST to decode a binary message using Huffman encoding/decoding. My question/issue pertains to setting up the tree itself. (I already figured out how to decode the message after the set up.)
Here is an example of what I'm trying to accomplish. (NOTE: This was provided in the assignment we were given.
String: ^a^^!^dc^rb
Here is what the tree should look like:
My issue comes with setting up the tree and using it in the other methods I have. I want to be able to use the root of the tree in the other methods, but every time I would use it, it would give me a null value.
Here is my code:
public class MsgTree {
public char payloadChar;
public MsgTree left;
public MsgTree right;
public MsgTree root;
public String encodingString;
private static int staticCharIdx = 0; //Need static char idx in the tree string for recursive solution
public MsgTree(String encodingString) { //Constructor building the tree from a string
this.encodingString = encodingString;
for(staticCharIdx = 0; staticCharIdx < encodingString.length(); staticCharIdx++) { //The for loop loops through every character in the string one char at a time
char charToTest = encodingString.charAt(staticCharIdx); //The program creates a charToTest variable to use for creating the new MsgTree node.
MsgTree newNode = new MsgTree(charToTest); //A new MsgTree node is created for every new char in the encodingString. It does this by calling the second MsgTree constructor
if(staticCharIdx == 0) {
root = newNode;
}
preOrderTraversal(newNode); //The program then calls a private function to perform a preOrder traversal of the tree
}
}
public MsgTree(char payloadChar) { //Constructor for a single node with null children
left = null; //This method assigns two children (left and right) to the char node and sets them both to null
right = null;
this.payloadChar = payloadChar; //A payloadChar value is utilized to avoid naming conflicts and for use in other methods
}
private void preOrderTraversal(MsgTree newNode) { //This method performs a preOrder traversal of the string and creates it into a BST
if(newNode == null) { //If the newNode taken from the constructor is null, then nothing happens. This happens when it is past the last char of the string.
return;
}
System.out.printf("%s", newNode.payloadChar); //Prints the char value of the NewNode
preOrderTraversal(newNode.left); //Calls the same method, but focuses instead on the left child of the newNode
preOrderTraversal(newNode.right); //Calls the same method, but focuses instead on the right child of the newNode
}
public static void printCodes(MsgTree root, String code) { //method to print characters and their binary codes
//DOES THE PRINTING HERE
}
public void decode(MsgTree codes, String msg) { //Prints the decoded message to the console
//DOES THE DECODING HERE
}
public static void main(String args[]) throws FileNotFoundException { //Main method putting the tree and message into two separate strings and implementing the above methods
String treeString = "^a^^!^dc^rb";
String messageString = "10100101010110110111100";
MsgTree newTree = new MsgTree(treeString); //A new tree is created using the new tree string derived from the arch file
String code = "";
System.out.println();
System.out.println("character code");
System.out.println("-------------------------");
newTree.printCodes(root, code); //WHY CANT I CALL IT HERE? IT GIVES ME A NULL VALUE
newTree.decode(root, messageString); //I ALSO CAN'T USE IT HERE
}
Attempting to use the root value or the BST in any method besides where it was created will give me a null value. I've tried using "newTree.root" or "MsgTree.root" but that doesn't work.
I would appreciate any help with this. Thank you.
You never assign anything other than null to left and right, so you aren't actually building a tree.
It looks like the input string has a recursive definition:
If the character is '^' then the node payload is empty (or '^'), left is the node that we get from parsing the string starting at the next character, and right is the node we get by parsing the string starting at the next character after whatever we read for left.
Otherwise, the node payload is the character, and left and right are null.
You have the right idea with staticCharIdx. This is how you keep track of the "next character." But you don't want to loop through the whole string in the MsgTree constructor. And if staticCharIdx is going to be static, might as well make encodingString static too, and make a static tree-building method something like this:
public static MsgTree build(String encodingString) {
MsgTree.encodingString = encodingString;
staticCharIdx = 0;
return buildNextMsgTree();
}
The function buildNextMsgTree implements the two cases above, in the first case recursively calling itself to create the left and right nodes.
private static MsgTree buildNextMessageTree() {
char c = encodingString.charAt(staticCharIdx++);
MsgTree tree = new MsgTree(c);
if (c == '^') {
tree.left = buildNextMessageTree();
tree.right = buildNextMessageTree();
}
return tree;
}
You'll have to adjust the MsgTree constructor to accept the payload.

Not able to run my java program to construct BST

I am trying to construct BST From PreOrder And inorder
// Construct Binary Tree From Inorder And Preorder
public class Solution {
public TreeNode buildTree(ArrayList<Integer> A, ArrayList<Integer> B) {
return buildTreeUtil(A,0,A.size()-1,B,0,B.size()-1);
}
public TreeNode buildTreeUtil(ArrayList<Integer> inOrder,int inOrderStart,int inOrderStop,
ArrayList<Integer> preOrder,int preOrderStart,int preOrderStop){
if(inOrderStart > inOrderStop || preOrderStart>preOrderStop){
return null;
}
TreeNode root = new TreeNode(preOrder.get(preOrderStart));
int index = 0;
for(int i=0;i<inOrder.size()-1;i++){
if(inOrder.get(i)==preOrder.get(preOrderStart)){
index = i;
break;
}
}
root.left = buildTreeUtil(inOrder,inOrderStart,index-1,
preOrder,preOrderStart+1,preOrderStart+(index-inOrderStart));
root.right = buildTreeUtil(inOrder,index+1,inOrderStop,
preOrder,preOrderStart+index-inOrderStart+1,preOrderStop);
return root;
}
}
It's giving exception
Index out of bound
Unrelated to the IndexOutOfBoundsException, but the following line of code is improperly using the equality operator == to compare two Integer instances, instead it should use the .equals() method:
Bad code:
if(inOrder.get(i)==preOrder.get(preOrderStart)){
Correct code:
if(inOrder.get(i).equals(preOrder.get(preOrderStart))) {
The IndexOutOfBoundsException is likely occurring because the following lines of code are not protected against preOrderStart and preOrderStop parameter values that are negative or greater than the ArrayList's size()-1:
root.left = buildTreeUtil(inOrder,inOrderStart,index-1,
preOrder,preOrderStart+1,preOrderStart+(index-inOrderStart));
root.right = buildTreeUtil(inOrder,index+1,inOrderStop,
preOrder,preOrderStart+index-inOrderStart+1,preOrderStop);
Think about what happens in the code above if the variable index has a value of 0. The parameter index-1 will get a value of -1.

Investigate a queue with linked lists in java

.. I have to use a piece of code in java but I don't understand some parts of it.
The code uses methods (.isEmpty() etc. ) from a simple Queue i made in another document.
It is suppposed to investigate an array (which has linked lists in each address) and do some sort of processing with its values.
The problem is that i dont know what marked[s] = true; ,marked[t.v] = true; and parent[t.v] = k; are and how do they work as variables (?)
void BFS(int s)
{
Queue<Integer> Q = new Queue<Integer>();
marked[s] = true;
Q.put(s);
while (!Q.isEmpty())
{
k = Q.get();
for (Node t = adj[k]; t != null; t = t.next)
if (!marked[t.v]) {
marked[t.v] = true;
parent[t.v] = k;
Q.put(t.v);
}
}
}
}
edit: I wrote matrix instead of array, sorry.
marked[] parent and adj are all arrays.
t as you can see from the code, is a Node object. That node object will have a member variable called v. t.v therefore fetches the value of the variable v in the Node object t.
marked[t.v] finds the element in the array with index equal to t.v. e.g. if t.v is equal to 0, then you are fetching marked[0] which is the first element in the marked array.

Deleting the last element from an array

I am trying to delete an element from an array depending on the method's argument. If the argument is the last element's position, I can't use the for loop and end up specifying an if statement just to satisfy that. Also trying to return the current name in that position after the deletion. I have tested and the following code works.
I am trying to see if there is a better way of producing the same result without the extra if statement. I tried looking up the Arrays Class and no static method there that seems to help either. Please advice if there is a better way of doing this method. Thanks.
public class ArrayTester {
public static String[] array1 = new String[100];
public static void main(String[] args) {
remove(50);
System.out.println(remove(50));
}
public static String remove(int name) {
if(name == 99){
array1[name] = null;
return array1[name];
}
else if (name >= 0 && name < 99){
for (int i=name; i < array1.length-1; i++){
array1[i] = array1[i+1];
}
return array1[name];
}
return null;
}
}
And with ArrayList??
import java.util.ArrayList;
public class RemoveArrayListElement {
public static void main(String[] args) {
ArrayList<String> arlist=new ArrayList<String>();
//<E> it is return type of ArrayList
arlist.add("First Element"); // adding element in ArrayList
arlist.add("Second Element");
arlist.add("Third Element");
arlist.add("forth Element");
arlist.add("fifth Element");
// remove array list element by index number
arlist.remove(3);
// remove ArrayList element by Object value
arlist.remove("fifth Element");
// get elements of ArrayList
for(int i=0;i<arlist.size();i++)
{
System.out.println("ArrayList Element "+i+" :"+arlist.get(i));
}
}
}
Output:
Remove ArrayList Element 0 :First Element
Remove ArrayList Element 1 :Second Element
Remove ArrayList Element 2 :Third Element
With ArrayList is easier, isn't it?
You can simplify your code a little by excluding the if. Unfortunately, the loop has to stay - arrays provide contiguous storage, so you need to move the data if you are to delete an item in the middle of the array.
public static String remove(int index) {
// Note the use of "index" instead of "name"
if (index < 0 || index >= array1.length) {
// A more common approach is to throw an exception,
// but your code returns null for out-of-range index
return null;
}
for (int i = index; i < array1.length-1 ; i++) {
array1[i] = array1[i+1];
}
// Unconditionally set null in the last element of the array
array1[array1.length-1] = null;
return array1[index];
}
Looking at your code, you seem to want something like this -
if (name == 99) {
try {
return array1[name];
} finally {
array1[name] = null;
}
}
array1 = Arrays.copyOf(array1, 99);
Sounds to me like you would be better off using an ArrayList. Arrays aren't really made for what you're doing. But you could also just null the value at the desired location and run the java.util.Arrays.sort method on the array. Something like this (I'm winging it, but this would be close):
public static String remove(int name) {
String returnValue = array1[name];
array1[name] = null;
java.util.Arrays.sort(array1);
return returnValue;
}
This is going to leave you with a sorted array, but you're already shifting them out of their original indices anyway so that may or may not matter to you.
Another option would be to simply add a if (array1[index] != null) conditional to all of your code handling that array. That way you wouldn't have to shift your values around in the array and your code would just skip over any null values it runs into.

stackoverflowerror on recursive method with arraylist

I am see an Exception in thread "main" java.lang.StackOverflowError. I hope to know what is wrong with the code below.
public void addWord(String word){
addWord(word,root,0);
}
private void addWord(String word,Node root,int pos)
{
for(Node c:root.children)
{
if(word.charAt(pos)==c.letter)
{
addWord(word,c,pos++);
}
}
Node temp = new Node();
temp.letter=word.charAt(pos);
temp.children=new ArrayList<Node>();
root.children.add(temp);
if(pos==word.length()-1)
{
temp.terminus=true;
return;
}
if(pos<word.length()-1)
{
addWord(word,temp,pos++);
}
}
In essence, stack overflow comes from the fact that your method keeps being called recursively and the recursion never ends.
One possible problem is this call:
addWord(word,temp,pos++);
It is equivalent to
addWord(word,temp,pos);
pos = pos + 1;
You probably mean:
addWord(word,temp,++pos);
which would be equivalent to
pos = pos + 1;
addWord(word,temp,pos);
I wrote a simpler version of addWord():
private void addWord(String word, Node aRoot, int pos) {
if (pos == word.length())
return;
for (Node c : aRoot.children) {
if (word.charAt(pos) == c.letter) {
addWord(word, c, pos+1);
return;
}
}
Node temp = new Node();
temp.letter = word.charAt(pos);
temp.children = new ArrayList<Node>();
temp.terminus = pos == word.length() - 1;
aRoot.children.add(temp);
addWord(word, temp, pos+1);
}
The original version in your code had a couple of problems with base cases, and with the recursive calls. As a general rule, you should avoid changing the values of a method's parameters (the pos++ part).
I'm guessing you're building a Trie data structure, and I anticipate that you're gonna have problems with that terminus attribute. Think about it, if you add several words with common prefixes, which would be the terminus node? do you intend to add several nodes with the same letter at the same level, or do you want to share nodes at the same level with the same letter? in the latter case, what would be the value of the terminus attribute?
To make my point clear, draw a diagram showing how would you like your Trie to look like after executing the following code (paying close attention to the value of terminus in each node), and see if the above implementation gives the result you expect.
Test t = new Test();
t.addWord("a");
t.addWord("abc");
t.addWord("ab");

Categories