I have a method that finds a node in a linked list with a certain id and adds items to the arraylist of that node.
ArrayList <String> elems;
public Place addElemToLst(String id, String elem) {
// if no nodes create new node
if (head == null) {
Node node = new Node(id);
node.elems.add(item);
head = unit;
} else if (head != null) {
Node curr = head;
while (curr.next != null && !curr.next.id.equals(id)) {
curr = curr.next;
}
// if there is a id match
if (curr.id.equals(id)) {
curr.elems.add(item);
}
// add new Node
else { // the error is in this section
Node node = new Node(id);
node.elems.add(elem);
curr.next = node;
}
}
return this;
}
The problem is when I call addElemToLst() on an id of lets say "item1" multiple times and keep adding elements to the arraylist, the arraylist will only keep the last item entered into the arraylist. Essential, the arraylist is always a size of 1 because previous entries keep getting replaced. Why is this and what is the error? I have isolated the error to the comment in the code.
Thanks
You are not checking the first element/head for the correct ID
while (curr.next != null && !curr.next.id.equals(id))
You can try something like this for the second half:
else {
Node curr = head;
Node prev = null;
while(curr != null){
if(curr.id == id){
curr.elems.add(elem);
return this;
}
prev = curr;
curr = curr.next;
}
Node node = new Node(id);
node.elems.add(elem);
prev.next = node;
}
}
Your approach to finding a node with a matching ID will return a few different false negatives, which will in turn cause existing nodes to be overwritten. The issue is that you're using a sliding window to inspect nodes and determine a match, but your criteria for sliding doesn't line up with your criteria for determining whether to append to an existing node or create a new node.
Here are a few examples to illustrate:
_ = null
x = node
o = node with matching ID
[ ] = sliding window (left side is `curr`, right side is `curr.next`)
x -> o -> _
[ ]
Since the matching node is at the end of the list, you should append
`elem` to it. However, your code checks `curr.id` (instead of `curr.next.id`),
incorrectly concludes that no matching node is found, and overwrites `curr.next`.
o -> x -> _
[ ]
[ ]
Here, the matching node is at the head of the list, but your code
skips it and incorrectly creates a new node at the end of the list.
o -> x -> x -> _
[ ]
[ ]
[ ]
Same as above, a new node is incorrectly inserted at the end of
the list since you skipped the matching node at the head of the list.
x -> o -> x -> _
[ ]
Since you're checking `curr.id` (instead of `curr.next.id`), your code
incorrectly concludes that a new node needs to be created, overwriting
the existing (matching) node and truncating the tail of the list.
Linked lists are tough to reason about, and combining while conditions makes it even more difficult to grok. Here is a fixed implementation that (IMO) is easier to reason about:
public Place addElemToLst(String id, String elem) {
// if the list is empty, create a new node
if (head == null) {
Node node = new Node(id);
node.elems.add(elem);
head = node;
return this;
}
Node curr = head;
while (curr.next != null) {
// if the matching node appears inside the list,
// append the element and return
if (curr.id.equals(id)) {
curr.elems.add(elem);
return this;
}
curr = curr.next;
}
// if the last node in the list is a match, use it
if (curr.id.equals(id)) {
curr.elems.add(elem);
// now that you've exhausted all nodes, create a new one
} else {
Node node = new Node(id);
node.elems.add(elem);
curr.next = node;
}
return this;
}
Related
I`m trying to implement my own linkedlist and I tackled with this question.
This is add method implementation for linkedlist, supposed to add specified elements to the end of the list.
Below you see a code I found and that works, and you see my code which only shows last 2 elements added no matter how many you add to the list.
The only difference 2 codes have is that he stores rootNode (head) inside currentNode and does his traversing using currentNode. I directly used rootNode to do the same. Can someone explain my what is wrong with my code ?
This is his code that works:
public void add (E val) {
Node newNode = new Node(val, null);
Node currentNode = rootNode;
if (rootNode == null) {
rootNode = newNode;
} else {
while (currentNode.nextNode != null) {
currentNode = currentNode.nextNode;
}
currentNode.setNextNode(newNode);
}
}
And this is my code that only shows last 2 elements added :
public void add (E val) {
Node newNode = new Node(val, null);
if (rootNode == null) {
rootNode = newNode;
} else {
while (rootNode.nextNode != null) {
rootNode = rootNode.nextNode;
}
rootNode.setNextNode(newNode);
}
}
That happens because you're resigning the rootNode while iterating.
By making this, you are erasing all previous state of the list, which you can access only via root. That's way the only node that remain in the list are root and its next node.
In order to iterate over the list, you should introduce the local variable like in the first version. There's no other way around.
And I suggest to simplify the method a bit by returning after checking whether the root is null, there will be no in nesting the loop into the additional block of curly braces:
public void add (E val) {
Node newNode = new Node(val,null);
if(rootNode == null) {
rootNode = newNode;
return;
}
Node currentNode = rootNode;
while (rootNode.nextNode != null) {
rootNode = rootNode.nextNode;
}
rootNode.setNextNode(newNode);
}
Because you are changing root node, after add method ends, you have only the root node and the next node of it, do not change root node if it is not null.
For instance, you call add Method for nodes A, B, and C.
For the first time root is A, then when you call add(B), as the root node is not null already, loop will not work in the else statement and the next of A will be B, then when you call add(C), while loop will work one iteration and B will become root node(you lost A) and the next of B will be C node.
I am trying to sort my linked list with merge sort. The list is actually sorted but it is kind of missing first item(s).
Merge sort functions:
public Node mergeSort(Node head) {
if (head == null || head.next == null) {
return head;
}
Node middle = middleElement(head);
Node nextofMiddle = middle.next;
middle.next = null;
return merge(mergeSort(head), mergeSort(nextofMiddle));
}
public Node merge(Node left, Node right) {
Node temp = new Node();
Node newHead = temp;
while (left != null && right != null) {
if (left.info <= right.info) {
temp.next = left;
temp = left;
left = temp.next;
} else {
temp.next = right;
temp = right;
right = temp.next;
}
}
temp.next = (left == null) ? right : left;
return newHead;
}
public Node middleElement(Node head) {
if (head == null) {
return head;
}
Node slow = head;
Node fast = head;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
So I printed the list to the screen using traverse:
public static void main(String[] args) {
MyLinkedList mll = new MyLinkedList();
mll.insert(3);
mll.insert(5);
mll.insert(9);
mll.insert(1);
mll.insert(8);
mll.insert(7);
mll.insert(2);
mll.mergeSort(mll.head);
mll.traverse();
}
I have result like this:
1 and 2 missing!
After checking, i noticed that the "tail" of the linked list value is still 2. I don't know why can someone help?. I'm really new to programming so sorry for any inconvenience. Thank you for reading!
You're not far from a correct solution. I was able to get a working sort by adding 1 line and changing 3.
Your merge isn't doing what you think it is.
Allocating a false head node (what you call temp, not a good choice of name; try falseHead) is a fine idea. Then falseHead.next is the true head. That's what you'll finally return as the sorted list. Note that initially it's null, which is what you'd expect.
What you're missing is a variable tail to reference the current last node in the merged list. Since there is initially no last node at all, this should be initialized equal to falseHead. Consequently, when you append the first element to the tail of the current result by setting tail.next, you'll also be setting falseHead.next, i.e. creating the head element. It all works out.
Now, what is the logic for, say, removing the current head of the right list and appending it to the merge result? It's just 3 steps:
Do the append operation by making tail.next the current head of right.
Update tail to tail.next.
Remove the head of right by updating right to right.next.
Of course the left side is similar.
Good luck. You're close.
You have a couple problems that I can see. One, mentioned by #rcgldr, in the comments is that you merge method is returning the temp node newHead, but that node was no value and is not part of your graph. You need to return it's child newHead.next.
The other problem is that you never reset the head of your list. So after all the sorting, the head of mll still points to the original head, which in this case is 3. So when you traverse the list you skip 1 and 2. I'm not sure what your linked list class looks like but something like this should be close -- just assign the final node returned by mergeSort to the head of the list. Then when you traverse you should be starting in the right spot:
mll.head = mll.mergeSort(mll.head);
mll.traverse();
I am currently doing a Cracking the Coding Interview Problem (2.4) and I am supposed to partition a linked list around a value x, such that all nodes less than x come before all nodes greater than or equal to x. However, I am really confused as to why a temporary variable "next" is needed and why is node.next nulled below it. Why can't I just do node = node.next at the end of the while loop?
I am simply creating two linked lists, before and after, and merging them together once the correct values are put into each list.
public static Node partition(Node node, int x) {
Node beforeStart = null;
Node beforeEnd = null;
Node afterStart = null;
Node afterEnd = null;
/* Partition list */
while (node != null) {
Node next = node.next;
node.next = null;
if (node.data < x) {
if (beforeStart == null) {
beforeStart = node;
beforeEnd = beforeStart;
} else {
beforeEnd.next = node;
beforeEnd = beforeEnd.next;
}
} else {
if (afterStart == null) {
afterStart = node;
afterEnd = afterStart;
} else {
afterEnd.next = node;
afterEnd = afterEnd.next;
}
}
node = next;
}
/* Merge before list and after list */
if (beforeStart == null) {
return afterStart;
}
beforeEnd.next = afterStart;
return beforeStart;
}
Why can't I just do node = node.next at the end of the while loop?
It can be done this way. After doing the partition, for each list, you need to set the last node's next pointer to NULL. This will just take two lines of code.
The example code is using next = node.next and node.next = NULL to terminate each list during the partition process, but in this case that's not needed, since the lists don't need NULL terminators until after the partition process is done.
The loop in your question removes nodes from the head of the original list, and appends them to the before list or the after list, until the original list is empty. Then it concatenates the before and after lists.
That's easy to explain and easy to understand.
It can be done without the temporary next or nulling out node.next in every iteration, but then the above description would no longer apply -- nodes would not be removed from the original list in every iteration, the before list and after list would not contain only the appropriate nodes, the operation you perform on them is not 'appending', and nodes would even appear in multiple lists for a while.
Your algorithm would suddenly be a lot more difficult to describe and understand. That is a bad thing in software development, and a bad thing in a coding interview.
currently, I am working on implementing an AddAtIndex method and for the most part it seems to be working fine. However, my method is not passing my JUnit test and I can't seem to understand why. Thus, I have chosen to show the code I have done thus far:
**
* Add an element to the list at the specified index
* #param The index where the element should be added
* #param element The element to add
*/
public void add(int index, E element ) //Method should be O(1) time.
{
// TODO: Implement this method
if (index < 0) {
System.out.println("Can't add an element at a negative index.");
}
int i = 0;
LLNode<E> currentNode = head.next;
while ( i < size ) {
if ( i == index ) {
LLNode<E> newNode = new LLNode<E>(element);
LLNode<E> tempNode = new LLNode<E>(currentNode.data);
currentNode.next = tempNode;
currentNode.data = newNode.data;
newNode.prev = currentNode.prev;
newNode.next = tempNode;
tempNode.prev = newNode;
size++;
}
currentNode = currentNode.next;
i++;
}
}
My thought process behind the code is that the method creates a new Node, then it replaces the data at the specified index of the linked list. However, the data at the node it is replacing is stored in a temporary node which is incremented in position to the next node after the new node. I am about 80% confident in my implementation though the code looks a bit sloppy. I have created a driver to demonstrate the implementation. The drivers code is as follows:
public class LinkedListDriver {
public static void main(String[] args) {
// TODO Auto-generated method stub
MyLinkedList<String> nameList = new MyLinkedList<String>();
nameList.add("Hamadi");
nameList.add("Ballo");
nameList.add(1, "Salisu");
nameList.add(2, "Galo");
System.out.println(nameList.toString());
System.out.println(nameList.size());
nameList.set(2, "Abdullahi");
System.out.println(nameList.toString());
nameList.remove(1);
System.out.println(nameList.toString());
MyLinkedList<Integer> list1 = new MyLinkedList<Integer>();
list1.add(65);
list1.add(21);
list1.add(42);
System.out.println(list1.toString());
list1.remove(0);
System.out.println(list1.toString());
}
}
The Output from the driver is as follows:
List: Hamadi, Salisu, Galo, Ballo,
4
Replacing Galo with Abdullahi
List: Hamadi, Salisu, Abdullahi, Ballo,
Removing Salisu from the list
List: Hamadi, Abdullahi, Ballo,
List: 65, 21, 42,
Removing 65 from the list
List: 21, 42,
The unit test fails however with the following error:
It fails at the AssertEquals method:
shortList.add(2, "E");
shortList.add(3, "F");
**assertEquals("AddAtIndex: at position 2 ", "E", shortList.get(2)); //fails here**
assertEquals("AddAtIndex: at position 3 ", "F", shortList.get(3));
assertEquals("AddAtIndex: List size is ", 6, shortList.size());
I would like to know what I'm doing wrong. I have this literally completely figured out, though I know that there is something a bit off about my AddAtindex method. Thanks!
You don't need that tempNode. Just create the newNode and insert it properly between currentNode and its previous node.
You should also consider the possibility of adding an element at the beginning (no previous) or end (no next) of the list.
I used head and tail as sentinel nodes. Created a new node to be added in the list.
public boolean add(E element) {
// create new element
LLNode<E> variable = new LLNode(element);
variable.next = null;
variable.prev = null;
// if element is null, throw exception
if (element == null) {
// return false;
throw new NullPointerException("Element is null");
} else {
// get the value stored in tail.prev in variable temp.
variable.prev = tail.prev;
variable.next = tail;
// now modify the tail node prev and new node next
tail.prev = variable;
// get prev node next link changed
variable.prev.next = variable;
// update size
if (head.next.next != tail) {
size++;
}
return true;
}
}
I have my code as following:
Node current=head;
if(current==null)//check
else{
while(current.getNext()!=null)
current=current.getNext(); //loop through to find the last node in the list
}
//if I find it then connect it with my newNode(add)
Node add=new Node("A");
current.setLink(add);
add.setLink(null);
But it does not work, I drawn a diagram but still have no idea what`s wrong with it.
the line
if(current==null) //why do you check if you don't have any statements afterwards?
this solution is for singly linked list:
public static Node addLast(Node head, Object x) {
// save the reference to the header so we can return it.
Node ret = head;
// check base case, head is null.
if (header == null) {
return new Node(x, null);
}
// loop until we find the end of the list
while ((head.next != null)) {
head = head.next;
}
// set the new node to the Object x, next will be null.
head.next = new Node(x, null);
return ret;
}