Java doubly linked list looping - java

My goal is to loop backwards through a list I have created and if an element is smaller than my chosen number t a node with the value of t will be inserted in front of the element that is smaller. Also, if every element in the list is bigger than t a node with the value of t will be put at the start of the list. Example:
DoublyLinkedList<Integer> list = new DoublyLinkedList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
list.addAtFirstSmaller(4);
System.out.println("Nodelist: " + list.toString());
And I should expect the outcome:
[1, 2, 4, 3, 4, 5]
But instead I get:
[1, 2, 3, 4, 4, 5]
This is my code so far:
public void addAtFirstSmaller(T t)
{
ListNode<T> node = tail;
ListNode<T> newNode = new ListNode<T>(t);
while(node.previous != null)
{
int compared = node.previous.element.compareTo(t);
node = node.previous;
if(compared < 0)
{
ListNode<T> temp = node.next;
node.next = newNode;
newNode.next = temp;
newNode.next.previous = newNode;
node.previous = null;
size++;
}
else if(compared > 0 && node.previous == null)
{
addFirst(t);
size++;
}
}
}
To me it seems like everything is pushed to the right. Any idea on what to do?

As you already verified: the example output is correct as the idea is to maintain the list sorted. The misinterpretation was understandable, as "in front of" is somewhat ambiguous.
However, there are still a few issues with your code:
Although the assignment node.previous = null will make the loop end once you have inserted the new node, this breaks a previous link that really should remain untouched. Only the head node should have previous equal to null, while in general node could have a predecessor, which must remain its predecessor.
newNode.previous never receives a value. It should be set to node.
When the value to insert is greater than the value in the tail node, the node will be inserted at the wrong spot -- there is never a scenario in your code where the new node will become the new tail, yet this is a possibility that should be foreseen.
I would assume that addFirst would already increase size, so increasing it again after you call this function is wrong. This really should be the responsibility of addFirst.
Assuming that you have implemented addLast, the corrected code could be like this:
public void addAtFirstSmaller(T t) {
ListNode<T> node = tail;
ListNode<T> newNode = new ListNode<T>(t);
while (node != null && node.element.compareTo(t) >= 0) {
node = node.previous;
}
if (node == null) {
addFirst(t);
} else if (node == tail) {
addLast(t);
} else {
ListNode<T> temp = node.next;
node.next = newNode;
newNode.next = temp;
newNode.previous = node;
temp.previous = newNode;
size++;
}
}
In case you don't have it yet, addLast could look like this:
public void addLast(T t) {
ListNode<T> newNode = new ListNode<T>(t);
tail.next = t;
t.previous = tail;
tail = t;
size++;
}

I just received an answer from my instructor, and it seems like my output is correct ([1, 2, 3, 4, 4, 5] that is). I will mark this thread as closed as the code is working.

Related

How to insert into a Linked List at the end

I am learning linked list here https://practice.geeksforgeeks.org/problems/linked-list-insertion/1#
https://www.geeksforgeeks.org/linked-list-set-2-inserting-a-node/?ref=lbp
Here I have to write 2 functions to add a node at the beginning/the end of a linked list.
LinkedList: 9->0->5->1->6->1->2->0->5->0
The output should be: 5 2 9 5 6
But my output is: 5 2 9
I think I am wrong in the function add a node at the end, but I could not find my mistake. Could you please let me know where I am wrong?
Create a link list of size N according to the given input literals.
Each integer input is accompanied by an indicator which can either be
0 or 1. If it is 0, insert the integer in the beginning of the link
list. If it is 1, insert the integer at the end of the link list.
Hint: When inserting at the end, make sure that you handle NULL
explicitly.
Example 1:
Input:
LinkedList: 9->0->5->1->6->1->2->0->5->0
Output: 5 2 9 5 6
Explanation:
Length of Link List = N = 5
9 0 indicated that 9 should be
inserted in the beginning. Modified
Link List = 9.
5 1 indicated that 5 should be
inserted in the end. Modified Link
List = 9,5.
6 1 indicated that 6 should be
inserted in the end. Modified Link
List = 9,5,6.
2 0 indicated that 2 should be
inserted in the beginning. Modified
Link List = 2,9,5,6.
5 0 indicated that 5 should be
inserted in the beginning. Modified
Link List = 5,2,9,5,6.
Final linked list = 5, 2, 9, 5, 6.
Here is my solution:
class Solution
{
//Function to insert a node at the beginning of the linked list.
Node insertAtBeginning(Node head, int x)
{
// code here
Node current = new Node(x);
current.next = head;
head = current;
return head;
}
//Function to insert a node at the end of the linked list.
Node insertAtEnd(Node head, int x)
{
// code here
Node current = head;
while(current.next != null){
current = current.next;
}
Node addthis = new Node(x);
current = addthis;
return head;
}
}
Indeed there is an issue in your insertAtEnd() method. You correctly iterate through to the tail of your linked list, but your problem is here:
current = addthis;
This will simply assign your new node to current, which is not what you want.
What you want is, to attach your new node to the next field of your last node like this:
current.next = addthis;
This way, you actually added your node to the previously last element of the list.
Full code:
Node insertAtEnd(Node head, int x) {
Node current = head;
while(current.next != null){
current = current.next;
}
Node addthis = new Node(x);
current.next = addthis;
return head;
}
class Solution {
//Function to insert a node at the beginning of the linked list.
Node insertAtBeginning(Node head, int x) {
Node node = new Node(x);
if (head == null) {
head = node;
return head;
}
node.next = head;
head = node;
return head;
}
//Function to insert a node at the end of the linked list.
Node insertAtEnd(Node head, int x) {
Node node = new Node(x);
if (head == null) {
head = node;
return head;
}
Node temp = head;
while (temp.next != null) {
temp = temp.next;
}
temp.next = node;
return head;
}
}

Trouble sorting linked list

outputI'm doing a project for class where I have to sort a linked list using insertion sort. I am supposed to take user input, convert it into an int array and insert it into a linked list. My problem is for some reason when I go to print the linked list post sort, it only prints the first node. The code worked jsut fine when I was initially testing it(I was manually entering what integers to insert), but now that I'm using arrays it doesn't seem to work. Can anyone help?
(this is only one class from my project but let me know if more information is needed).
Edit: I added a picture of what my output lokos like
import java.util.Arrays;
public class SortLL {
static LL top;
static Node head;
static Node sorted;
//function to insert node at head
public void toHead(int newData){
Node newNode = new Node(newData);
newNode.link = head;
head = newNode;
}
public static void insertion(Node ref){ //problem right now is that i'm only passing in one node
sorted = null;
Node current = ref;
while(current != null){
Node next = current.link;
sortInsert(current);
current = next;
}
head = sorted;
}
static void sortInsert(Node newNode){ //item in this case is val
if(sorted == null || sorted.item >= newNode.item){
newNode.link = sorted;
sorted = newNode;
} else {
Node current = sorted;
while(current.link != null && current.link.item < current.item){
current = current.link;
}
newNode.link = current.link;
current.link = newNode;
}
}
void printList(Node head)
{
while (head != null)
{
System.out.print(head.item + " ");
head = head.link;
}
}
public static void sortList(int[] arrA, int[] arrB){
int[] arr = new int[arrA.length + arrB.length];
System.arraycopy(arrA, 0, arr, 0, arrA.length);
System.arraycopy(arrB, 0, arr, arrA.length, arrB.length);
System.out.println("checking array " + Arrays.toString(arr));
SortLL sort = new SortLL();
for(int i=0;i<arr.length;i++){
sort.toHead(arr[i]);
}
System.out.println("sortLL.java\n\n");
sort.printList(sort.head);
sort.sortInsert(sort.head);
System.out.println("\nLinkedList After sorting");
sort.printList(sort.head);
}
}
Inside your printList() method, you shift the head variable while iterating over the list. When you move the head variable to the end, you essentially destroy the linked list since you lose your reference to the beginning of it. Java will then automatically treat the unreferenced nodes as garbage.
From what I see, after you first call sort.printList(sort.head), you destroyed your original linked list, so it didn't work when sorting.
When calling printList(), it might help to use a temporary node (Node temp = head) so that you don't lose your original head variable.

How to make duplicates of my nodes in current linked list?

I am having difficulty coming up with a solution to my homework assignment. My professor gave me a bunch of test linked lists and wants me to duplicate each node present in the linked list.
Example:
int[] array = {1, 2, 3, 4, 10};
LinkedIntList list = new LinkedIntList(array);
list.stutter();
The outcome when I print out my new list should be: {1, 1, 2, 2, 3, 3, 4, 4, 10, 10}
Here is what I have so far... (I can't think of a reasonable while loop)
public void stutter(){
if (front == null) {
return;
}
ListNode current = front;
while (current.next != null) {
if (current != null) {
ListNode duplicate = new ListNode(current.data, current.next);
current.next = duplicate;
}
current = current.next;
}
}
I also have a lot of constructors, but since I summon one in my method, here is the relevant constructor:
public ListNode(int data, ListNode next){
this.data = data;
this.next = next;
}
Any help is appreciated!!!
You just have to make sure to point to the next of the duplicate rather than current.next:
public void stutter() {
for (ListNode current = front; current != null; ) {
ListNode duplicate = new ListNode(current.data, current.next);
current.next = duplicate;
current = duplicate.next
}
}
try this one
public Node reverse(){
Node p= this;
Node firstDuplicate = new Node(p.getItem()); //save reference for first node to return
Node currentDuplicate=firstDuplicate;
while(Node.NIL!=p.getNext()){
Node nextNode = p.getNext();
Node nextCopy = new Node(nextNode.getItem());
currentDuplicate.n = nextCopy;
currentDuplicate = nextCopy;
p = nextNode;
}
/* If the list is empty */
if(firstDuplicate == NIL)
return Node.NIL;
/* If the list has only one node */
if(firstDuplicate.n == Node.NIL)
return firstDuplicate;
// Node reverseRest = new Node(p.getItem(),Node.NIL);
Node rest = new Node();
rest = firstDuplicate.getNext();
firstDuplicate.setNext(Node.NIL);
// Node reverseRest=new Node(p.getItem(),reverseRest);
Node reverseRest=new Node();
reverseRest = rest.reverse();
/* Join the two lists */
rest.setNext(firstDuplicate);
//p=this;
// p=p.nthNext(0);
return reverseRest;
}

Java Merge Sort on Linked List sorting only when smallest number is added first

When I insert numbers in my linked list it only sorts everything when the first number added to it is the smallest. This is the unexpected behavior that I am getting:
I insert the numbers in this order - 200, 25, 473, 23, 390
If I sort the list like that above and display it, I get this - 200, 390, 473
If I change 200 to 900 then sort the list, it only displays 900
It only works when I change 200 to the smallest number in the list like 1 (or anything less than 23), then it gives me the right output 1, 23, 25, 390, 473
For the linked list I insert the elements at the back of the the list, this is the code:
public void insertAtBack(IntegerElement elem) {
if (isFull()) {
System.out.println("Unable to insert node into full list");
} else {
Node temp = new Node(elem);
if (isEmpty()) {
head = temp;
} else {
Node current = head;
while (current.getLink() != null) {
current = current.getLink();
}
current.setLink(temp);
}
}
}
And this is the code I use to merge sort:
public Node getMiddle(Node node) {
if (node == null)
return node;
Node fastptr = node.getLink();
Node slowptr = node;
// Move fastptr by two and slow ptr by one
// Finally slowptr will point to middle node
while (fastptr != null) {
fastptr = fastptr.getLink();
if(fastptr != null) {
slowptr = slowptr.getLink();
fastptr = fastptr.getLink();
}
}
return slowptr;
}
public Node merge(Node left, Node right) {
Node tempHead = new Node(), curr;
curr = tempHead;
while(left != null && right != null) {
if(left.getData().getValue() <= right.getData().getValue()) {
curr.setLink(left);
left = left.getLink();
}else {
curr.setLink(right);
right = right.getLink();
}
curr = curr.getLink();
}
curr.setLink((left == null) ? right : left);
return tempHead.getLink();
}
/**
* This method utilizes merge sort algorithm
*
* #param node - Pass in head first
*
*/
public Node sort(Node node) {
// Base case : if head is null
if (node == null || node.getLink() == null)
return node;
// get the middle of the list
Node middle = getMiddle(node);
Node nextofmiddle = middle.getLink();
// set the next of middle node to null
middle.setLink(null);
// Merge the left and right lists
return merge(sort(node), sort(nextofmiddle));
}
Any help is appreciated
Your sort routine looks great. The bug appears to be the way you are returning from your sort routine. If you call your sort as if it were an in-place sort, i.e.
sort(head);
System.out.println(head);
the old head is not updated to the new head returned by sort(). Notice how the nodes that are being displayed in your test cases always begin with whatever the old head was. This appears to work if the old head in the unsorted list happens to be the new head in the sorted list, as in your last example. If, on the other hand, the old head node is moved during the sort, you'll only see the rest of the list from wherever the old head moved to onward. Nodes from the front of the list up to the old head will be garbage collected when they go out of scope.
The fix is to set the head of your list in the caller to the returned head from sort(), which is the new head of the list:
head = sort(head);
System.out.println(head);
Here's your code re-written which reproduces your errors to illustrate the problem:
class Main {
public static void main(String[] args) {
Node head = new Node(200, new Node(25, new Node(473, new Node(23, new Node(390, null)))));
System.out.println("Example 1 (correct):");
System.out.println(head);
head = sort(head);
System.out.println(head);
head = new Node(200, new Node(25, new Node(473, new Node(23, new Node(390, null)))));
System.out.println("\nExample 1 (incorrect):");
System.out.println(head);
sort(head);
System.out.println(head);
head = new Node(900, new Node(25, new Node(473, new Node(23, new Node(390, null)))));
System.out.println("\n\nExample 2 (correct):");
System.out.println(head);
head = sort(head);
System.out.println(head);
head = new Node(900, new Node(25, new Node(473, new Node(23, new Node(390, null)))));
System.out.println("\nExample 2 (incorrect):");
System.out.println(head);
sort(head);
System.out.println(head);
head = new Node(1, new Node(25, new Node(473, new Node(23, new Node(390, null)))));
System.out.println("\n\nExample 3 (accidentally works, because the old head is still the new head):");
System.out.println(head);
sort(head);
System.out.println(head);
}
static Node getMiddle(Node node) {
Node fastptr = node.link;
Node slowptr = node;
while (fastptr != null) {
fastptr = fastptr.link;
if (fastptr != null) {
slowptr = slowptr.link;
fastptr = fastptr.link;
}
}
return slowptr;
}
static Node merge(Node left, Node right) {
Node temp = new Node(-1, null);
Node curr = temp;
while (left != null && right != null) {
if (left.data < right.data) {
curr.link = left;
left = left.link;
}
else {
curr.link = right;
right = right.link;
}
curr = curr.link;
}
curr.link = left == null ? right : left;
return temp.link;
}
static Node sort(Node node) {
if (node == null || node.link == null) {
return node;
}
Node middle = getMiddle(node);
Node next = middle.link;
middle.link = null;
return merge(sort(node), sort(next));
}
}
class Node {
public int data;
public Node link;
public Node(int data, Node link) {
this.data = data;
this.link = link;
}
public String toString() {
return this.data + (this.link != null ? "->" + this.link : "");
}
}
Output:
Example 1 (correct):
200->25->473->23->390
23->25->200->390->473
Example 1 (incorrect):
200->25->473->23->390
200->390->473
Example 2 (correct):
900->25->473->23->390
23->25->390->473->900
Example 2 (incorrect):
900->25->473->23->390
900
Example 3 (accidentally works, because the old head is still the new head):
1->25->473->23->390
1->23->25->390->473
Try it!

Why is head.data = 0 when head.next == null?

Working on a HW assignment. The assignment is to reverse a linked list recursively. I just don't understand why at my System.out.println(head.data) line head.data always prints as 0. Assuming I enter 4,5,6 (the fill and read methods for this work, if I put a print in my final else it will show that head is still 4, 5, 6) and head.next is null, doesn't that mean that head.data is equal to 6? I know I've got a lot of other problems going on with trying to reverse this, but I just don't understand why when head.next is null the head.data is 0. I thought head.next was the next item in the list, not the current one.
public static Node reverse(Node head)
{
Node n = new Node();
if (head == null)
{
return n;
} else if (head.next == null)
{
System.out.println(head.data);
n.data = head.data;
head.next = null;
n.next = reverse(head.next);
return n;
} else
{
reverse(head.next);
return n;
}
}
The following:
Node n = new Node();
if(head == null) {
return n;
}
results in the reverse of an empty list being a single-element list with the default value of data (presumably zero?)
Also, the final else is clearly not right, as it never does anything to n before returning it.

Categories