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");
Related
For homework, I am working on writing a LinkedList class, that replaces the LinkedList methods. I'm working on the "set" method.
Here's what I have so far for the set() method. It takes in int index and X item as parameters. The head of the node is in a variable called first. (The whole class is genericized.)
Node<X> p = new Node<X>();
if(index < 0 || index > size()-1){
throw new Bonfire();
}
int count = 0;
while(count != index){
p = p.next;
count++;
}
if(count == index){
p.item = item;
}
Node class:
public class Node<T>
{
T item;
Node<T> next;
}
When I go to run my code against some test code that I have, it fails the test.
Test Code:
LList<String> b = new LList<String>();
b.add("Hello");
b.add("Bye");
b.set(0, "Bonjour");
assertEquals("Bonjour", b.get(0));
Failed test Reason: org.junit.ComparisonFailure: expected:<[Bonjour]> but was:<[Hello]>
(add(), size(), and get() methods are working correctly.)
So my question is, how do I get this to set the element correctly? From this code, and from why it's failing the test, it looks like it's not setting anything at all. If you need any extra information from me, do not hesitate to ask me. Appreciate the help. Thanks!
All I needed to do was change Node<X> p to make it Node<X> p = first;.
Beginner here using Java (first year student), and am unable to get the below function to work. The goal is to use recursion and a helper function to compute the size of a singly linked list. When running the code against test lists, it keeps returning List changed to [].
I'm struggling in general with Java, so any help is appreciated. Thank you
public class MyLinked {
static class Node {
public Node(double item, Node next) {
this.item = item;
this.next = next;
}
public double item;
public Node next;
}
int N;
Node first;
public int sizeForward() {
return sizeForwardHelper(first);
}
public int sizeForwardHelper(Node n) {
Node current = first;
if (current == null) {
return 0;
} else {
first = first.next;
return sizeForward() + 1;
}
}
I believe I have the first portion set up to return 0 if there are no elements in the List. I believe it's the second part that isn't setting up correctly?
Thanks
Because it’s important for your learning to not spoonfeed you, I’ll describe an approach rather than provide code.
Use this fact:
The length of the list from any given node to the end is 1 plus the length measured from the next node (if there is one).
Usually (as would work here), recursive functions take this form:
If the terminating condition is true, return some value
Otherwise, return some value plus the recursively calculated value
When writing a recursive function, first decide on the terminating condition. In this case, n == null is the obvious choice, and you’d return 0, because you’ve run off the end of the list and the length of nothing (ie no node) is nothing. This also handles the empty list (when first is null) without any special code.
Otherwise, return 1 (the length of one node) plus the length of next.
Put that all together and you’ll have your answer.
——
Hint: The body of the recursive helper method can be coded using one short line if you use a ternary expression.
Instead of calling your wrapper function call your helper function recursively. Try the following:
public int sizeForward () {
return sizeForwardHelper (first);
}
public int sizeForwardHelper(Node n) {
if (n == null) // base case
return 0;
return sizeForwardHelper(n.next) + 1; // count this node + rest of list
}
Your method that computes the size of the list actually modifies the list in the process (with first = first.next; you set the first element to the next, and since there is a recursion, the first element always end up being null which is equivalent to an empty list with your design). Your method will work once, but your list will be empty afterwards.
To illustrate this, I added a print next to the instruction first = first.next; and wrote the following main:
public static void main(String[] args) {
Node n2 = new Node(2d, null);
Node n1 = new Node(1d, n2);
Node n = new Node(0, n1);
MyLinked l = new MyLinked(n);
System.out.println("The first element is: "+l.first.item);
System.out.println("The size is: "+l.sizeForward());
System.out.println("The first element is: "+l.first);
}
It yields:
The first element is: 0.0
first is set to 1.0
first is set to 2.0
first is set to null
The size is: 3
The first element is: null
Clearly, you should not modify the list while computing its size. The helper method should return 0 if the node is null (empty list), and 1 plus the size of the rest of the list otherwise. Here is the code.
public int sizeForwardHelper(Node n) {
if (n == null)
return 0;
else
return sizeForwardHelper(n.next) +1;
}
The goal of the arg free method sizeForward() is just to call the helper. The helper should not use it though.
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.
I have an interview question that still kills my mind, please help.
You have to write a method in Java with a String parameter.
That String should be a tree of ternary operators (a?b:c). So basically it can be something like:a? g?h:j ? u?v:w : p : r?s:t
a
/ \
g?h:j r?s:t
/ \
u?v:w p
Something like that, I hope I even wrote it right, because I am really confused.
Then we have a class Node that has 2 fields: left and right:
class Node {
char variableName;
Node left, right;
}
So you have to return a Node with all the Nodes(left, right) from that String.
I hope this is understandable. If you need more information I will provide, but the basic idea here is to get all the nodes right. I was trying to do this using recursion and I still believe that this is right. But I cannot figure out how to do it right.
This question can be solved with a very simple recursive descent parser. The intention behind asking this question is to see if you can implement a recursive algorithm where recursion makes sense, as opposed to asking you to code up a boring recursive factorial to see if you have heard of recursion before.
Here is one possible implementation:
static class Parser {
private int pos = 0;
private String s;
public Parser(String s) {
this.s = s;
}
private void skipSpace() {
while (pos != s.length() && Character.isWhitespace(s.charAt(pos))) {
pos++;
}
}
public Node parse() {
skipSpace();
Node res = new Node();
res.variableName = s.charAt(pos++);
skipSpace();
if (pos == s.length()) return res;
if (s.charAt(pos) == '?') {
pos++;
res.left = parse();
skipSpace();
if (pos == s.length() || s.charAt(pos) != ':') {
System.err.println("Syntax error");
return null;
}
pos++;
res.right = parse();
}
return res;
}
}
public static Node parse(String s) {
Parser p = new Parser(s);
return p.parse();
}
Demo.
The idea is to use parse() method as if it's already written: first we parse the variable name, then we check if it is followed by a question mark. If it is, we consume the question mark, parse from the current position what becomes our left node, skip the colon (or error out if the colon is missing), and finally parse the right node. Skip whitespace as you go.
This is for homework but please know that I have looked online for help (such as http://www.sethi.org/classes/class_stuff/cis435/others/notes-java/data/collections/lists/simple-linked-list.html) and my textbook but I am still having some issues.
Any help would be appreciated...
Right now I'm trying to just insert values in but nothing is working. Whether it's the first item, whether it's being added as the last one, or somewhere in between.
Node header = null; // First element of list.
Node back = null; // Last element of list.
public void insert(int i, double value){ //insert value before i-th element
Node e = new Node();
e.num = value;
Node curr = header;
for(int x=0;x<i;x++) {
if (i == 1) { //we want to insert as first thing
if (size == 0) { //its the FIRST time we add something
header.next = e;
e.next = back;
break;
} else if (size == 1){
e.next = header.next; //i.e. the second thing in the list
header.next = e;
break;
} else {
e.next = header.next.next; //i.e. the second thing in the list
header.next = e;
break;
}
}
else if (x == (i-1)) {
e.next = curr.next;
curr.next = e;
break;
}
curr = curr.next;
}
size = size+1;
}
Not really sure why it isn't working.
Thanks!
For some reason, people who are still learning to program make things far more complicated then they need to be. I did it when I was learning java, I still do it when I am just getting into a new language, and students that I have marked find new and amazing ways to do it. You have more going on in your insert then there needs to be, for example, a method that inserts a value at a specific index should not check if it's the first item to be inserted (not saying it shouldn't check bounds). Here is the pseudo code of what I would do.
insert(index, value)
if index>size
throw null pointer
traverse to index -1 //lets call this nodeI
create newnode and set value
set newnode.next to nodeI.next
set nodeI.next to newnode
increase size.
Couple of handy hints for you, you should have a function to get an element from the link list, something that returns a node? public node elementAt(int index) for example? use that to traverse the linked list. If you want to append to the Linked list, try this
append(value)
insert(size-1,value)
and if you want to insert at the beginning? same idea
insert(value)
insert(0,value)
In the line e.next = header.next.next what would happen if header.next points to a 'null'? Is it possible to get there?
What are the corner cases you have to deal with and have you taken them all into account?
Can you start with the simplest case first, adding either an element to the front or an element to the back? Then use those functions to implement the insert?
A few suggestions:
implement java.util.List
Think about generics
Read this.
Start with "insert at the end" before you think about "insert at i".
I have tried a simple program, which will be useful for you guys, I am also learning Java, please bear with me for any mistakes, but this program works fine.
I am posting a very simple singly linked list program in Java, which I tried out today.
I hope it will help all.
LinkList.java
class LinkList
{
public static void main(String args[])
{
Node node = new Node(1);
node.addAtLast(2);
node.addAtLast(3);
node.addAtLast(4);
node.addAtLast(5);
node.printList();
}
}
Node.java
class Node
{
private int data;
private Node link;
public Node(int mydata)
{
data = mydata;
link = null;
}
public void printList()
{
System.out.print("|"+data+"|"+"->");
if(link != null)
{
//recursive call
link.printList();
}
else
{
//marking end of list as NULL
System.out.print("|NULL|");
}
}
public void addAtLast(int mydata)
{
if(link == null)
{
link = new Node(mydata);
}
else
{
link.addAtLast(mydata);
}
}
}
OUTPUT :
The below is our output
|1|->|2|->|3|->|4|->|5|->|NULL|