I'm working on my Quick Sort exercise that uses a LinkedList to sort, (I know it's not efficient and really pointless, it's for class). I understand how the Quick Sort method works, as well as the median of three strategy. My code is working properly for only certain lengths however, for example.
This works fine:
7 6 5 4 3 2 1, pivot = 4
7 6 5, pivot = 6 | 3 2 1, pivot = 2
Now, for anything that isn't like that, ie.
5 4 3 2 1, pivot = 3
5 4, throws an error | 2 1 throws an error.
Here is the code that I have:
Finds the middle node in the LinkedList.
public Node findMiddleNode() {
Node node1 = first;
Node node2 = first;
while(node2.getNext() != null && node2.getNext().getNext()!= null) {
node1 = node1.getNext();
node2 = node2.getNext().getNext();
}
return node1;
}
Finds the median of the first, middle and last nodes.
public Node medianOfThree() {
Node firstNode = first;
Node lastNode = last;
Node middleNode = findMiddleNode();
if((firstNode.getData() - middleNode.getData()) * (lastNode.getData() - firstNode.getData()) >= 0) {
return firstNode;
} else if((middleNode.getData() - firstNode.getData()) * (lastNode.getData() - middleNode.getData()) >= 0) {
return middleNode;
} else {
return lastNode;
}
}
Removes the pivots from the list, this is the method which breaks.
private Node chooseAndRemovePivot() {
Node pivot = medianOfThree();
Node previous = first;
// If the pivot is the first Node.
if(previous == pivot) {
first = previous.getNext();
}
// Gets the last Node before the pivot
while(previous.getNext() != pivot) {
previous = previous.getNext();
}
previous.setNext(pivot.getNext());
pivot.setNext(null);
size--;
if (size == 0)
last = null;
return pivot;
}
Can anyone point out what's going wrong here, I'm sure it's a simple mistake that I am making.
EDIT: Solution;
In the method chooseAndRemovePivot();
// If the pivot is the first Node.
if(previous == pivot) {
first = previous.getNext();
} else {
// Gets the last Node before the pivot
while(previous.getNext() != pivot) {
previous = previous.getNext();
}
}
This gets it working for all lengths.
The medianOfThree function will return pivot == first for lists of length 2. Thus this code:
// Gets the last Node before the pivot
while(previous.getNext() != pivot) {
previous = previous.getNext();
}
...will never find the terminal condition and instead assign previous = null when it reaches the end of the list. Then the next iteration will throw a NullPointerException.
I beleive the error is in your findMiddleNode() function. Specifically, node2.getNext.getNext() doesn't ever check that node2.getNext() is not null
in a list with an even number of items, node2.getNext().getNext() will run off the end. effectively reducing the statement to Null.getNext() which is an error.
For example using the list
first -> a -> b -> null
First node1 and node2 are set to "first.
Then node1 becomes a, and node2 becomes b.
Then node1 becomes b and node2 becomes b.getNext().getNext() or in other words Null.getNext.
The algorithm works for odd length lists, because node2.getNext().getNext() will always land on the null
Related
I was going through a sum on geeksforgeeks.com for adding two linked lists. And I am confused in the answer provided.
Node addTwoLists(Node first, Node second) {
Node res = null; // res is head node of the resultant list
Node prev = null;
Node temp = null;
int carry = 0, sum;
while (first != null || second != null) //while both lists exist
{
// Calculate value of next digit in resultant list.
// The next digit is sum of following things
// (i) Carry
// (ii) Next digit of first list (if there is a next digit)
// (ii) Next digit of second list (if there is a next digit)
sum = carry + (first != null ? first.data : 0)
+ (second != null ? second.data : 0);
// update carry for next calulation
carry = (sum >= 10) ? 1 : 0;
// update sum if it is greater than 10
sum = sum % 10;
// Create a new node with sum as data
temp = new Node(sum);
// if this is the first node then set it as head of
// the resultant list
if (res == null) {
res = temp;
} else // If this is not the first node then connect it to the rest.
{
prev.next = temp;
}
// Set prev for next insertion
prev = temp;
// Move first and second pointers to next nodes
if (first != null) {
first = first.next;
}
if (second != null) {
second = second.next;
}
}
if (carry > 0) {
temp.next = new Node(carry);
}
// return head of the resultant list
return res;
}
I understand that we have created three Nodes res, prev and temp and I don't understand how each one of them are getting updated simultaneously.
if (res == null) {
res = temp;
} else // If this is not the first node then connect it to the rest.
{
prev.next = temp;
}
Like here, how the 2nd element would be added in res when we are adding it in prev.next.
And below :
if (carry > 0) {
temp.next = new Node(carry);
}
If we are adding the last element in temp, how will it reflect in res?
The code seems to be working but I am having a hard time understanding this concept.
Please help. Thanks in advance.
res, prev and temp are references to a Node. When you write something like res = tmp; it means that now res and tmp refer to the same Node instance, and any changes made to this instance using, for example, res reference will remain when you use tmp reference.
here is the same code but with additional comments to try to help explain what is happening. This code appears to be taking two head nodes from link lists where each node contain a single digit, then adding the digits together to create a new list of single digits (e.g. 1->2->3 and 5->6->7->8 with = 1+5->2+6->3+7->0+8. Note that the third set results in a carry over so the final values in the returned list would be 6->8->0->9).
Thus, this code is not adding to two link lists together, it is adding the data contained
in each of the nodes of the two lists and putting the result into a third list.
My additional comments in the code are prefixed with WCK -
Node addTwoLists(Node first, Node second) {
Node res = null; // res is head node of the resultant list
Node prev = null;
Node temp = null;
int carry = 0, sum;
while (first != null || second != null) //while both lists exist WCK actually this is While at least one of the lists exists, I believe the comment is wrong and the code is right
{
// Calculate value of next digit in resultant list.
// The next digit is sum of following things
// (i) Carry
// (ii) Next digit of first list (if there is a next digit)
// (ii) Next digit of second list (if there is a next digit)
sum = carry + (first != null ? first.data : 0)
+ (second != null ? second.data : 0);
// update carry for next calulation
carry = (sum >= 10) ? 1 : 0; // WCK - assumes sum <20; is only carrying at most 1
// update sum if it is greater than 10
sum = sum % 10;
// Create a new node with sum as data
temp = new Node(sum);
// if this is the first node then set it as head of
// the resultant list
// WCK - the first time through the loop, res will be null
// WCK - each subsequent time through the loop, the else is invoked to link the new node to the one from the previous iteration thus linking them
if (res == null) {
res = temp; //WCK - as #ardenit says, both res and temp point to the same node at this point
} else // If this is not the first node then connect it to the rest.
{
prev.next = temp;
}
// Set prev for next insertion
// WCK - now they are starting to set up for the next iteration.
// WCK - the first time through, res, prev and temp all point to the same node after this statement is executed.
prev = temp;
// Move first and second pointers to next nodes
if (first != null) {
first = first.next;
}
if (second != null) {
second = second.next;
}
// WCK - the first time through the loop, both of the lists passed in
// have been advanced to the next node in their respective lists.
// res and prev will point to the temp. As the next iteration of the loop
// starts, temp will be pointed to a new node while res and prev will
// still point to the same node created in the first iteration. As the
// second iteration executes, prev is set to point to the new temp
// where you see (prev.next = temp) and then prev is advanced to the
// this new node as well. res will not be changed again (it is only set
// once in the first iteration)
}
// WCK - now that the loop is finished, there may be a final carry value
if (carry > 0) {
temp.next = new Node(carry);
}
// return head of the resultant list
return res;
}
I'm trying to delete a given Node from a Linked List. I don't know why my code is not working. Any hints?
So I have [11,21,31,41] and they are asking me to delete the node at index 2 in this case 31. So far I have this:
public void delete (int k) {
//[ 11 21 31 41 ].delete( 2 ): expected=[ 11 21 41 ]
if (k < 0 || k >= N) throw new IllegalArgumentException ();
for(Node x = first; x != null; x = x.next) {
//deletes node
if(x.item == k){
x = x.next;
}
if(x.item <= k){
x = x.next.next;
}
}
}
Can someone tell me please why is this not working? Thank you
You could move nodes using next k times. Store a temporary int and a previous node. Decrement the temporary int each time you call next(). Once you are at 0 (the desired element), remove by setting the previous node's next pointer to x's next pointer, and then set x to null.
I think in your code you are missing the part where pointers are set.
For example:
(1) -> (2) -> (3)
To remove (2), set (1).next = (3) and (2) = null. This will get:
(1) -> (3)
There are a couple of things going wrong here, and I encourage you to work on some println debugging to better understand the issues as you develop.
Assuming the item field is the value of the Node, you're comparing that value of a Node to the index of said Node (e.g. x.item == k).
The general logic that you're going to want to follow is, "if the Node the iterator is pointing to is the next Node in my list, set my next to its next."
In your code you are comparing the value of node with the index you passed. This comparison will always have index less than value in node. Also after that you are not updating the node when you assume the code is correct.
Below code should give you the result.
public void delete (int k)
{
//[ 11 21 31 41 ].delete( 2 ): expected=[ 11 21 41 ]
if (k < 0 || k >= N) throw new IllegalArgumentException ();
int count = 0;//Assuming index starts from 0
Node prev;
for(Node x = first; x != null; x = x.next)
{
//deletes node
count++;
if(count<k)
{
prev = x;
continue;
}
else
{
prev.next = x.next;
x.next = null;
break;
}
}
if(count>k || count<k)
{
System.out.println("No element with index k");
}
}
#vase is correct saying
Assuming the item field is the value of the Node, you're comparing
that value of a Node to the index of said Node (e.g. x.item == k).
some example code that could fix this
public void delete(int k){
Node n = first;
for(int i = 0; i < k-1; i++){ // this loop finds the node right before the
n=n.next; // index to use to delete the desired index.
}
n.next = n.next.next; // delete command
}
So I'm attempting to quicksort a singly linked list. Since I can't traverse backward like the traditional quicksort, I made it traverse forward to partition the list... But, if anyone could tell me where I'm getting this StackOverflowError it would really be appreciated.
public static <E extends Comparable<E>> void quickSort(MyNode<E> first, MyNode<E> last) {
if(first != last) {
MyNode<E> pivot = first;
MyNode<E> currentNode = first.next;
MyNode<E> previousNode = first;
while(currentNode.next != last && currentNode.next != null) {
if (currentNode.element.compareTo(pivot.element) < 0) {
MyNode<E> temp = new MyNode<E>(currentNode.element);
previousNode.next = currentNode.next;
temp.next = first;
first = currentNode;
}
previousNode = previousNode.next;
currentNode = currentNode.next;
}
quickSort(first, pivot);
quickSort(pivot, last);
}
}
EDIT:
So thanks to your guys help I am a little bit closer I think... But I am still stuck. I have changed my code based on suggestions. But now it is just not sorting correctly.. The issue is when I try to move current to the front of the list... It seems to disconnect it from the list. So, when I print out the list all I get back is the pivot and the values greater than the pivot.. All of the lesser than elements have disappeared..
public static <E extends Comparable<E>> void quickSort(MyNode<E> first, MyNode<E> last) {
if(first != last && first != null) {
E pivot = first.element;
MyNode<E> current = first.next;
MyNode<E> previous = first;
while(previous != last && current != null) {
if (current.element.compareTo(pivot) < 0) {
previous.next = current.next;
first = current;
first.next = previous;
current = previous.next;
}
else {
previous = previous.next;
current = current.next;
}
//recursive calls will go here... Just want to get the logic right first
}
}
}
The main problem (the StackOverflowError you're getting) is, that you don't change pivot and hence the recursive call to quickSort(pivot, last); will be the same as quickSort(first, last); and thus first != last will always be true for any list of size > 1.
You should first set pivot to the middle element, then sort elements according to being greater or smaller than the pivot and then call quicksort recursively for the sublists. Here though, you shouldn't pass pivot twice, otherwise you'd still get a stack overflow.
Assume you end up with a sublist of only two elements and you pick one as the pivot. One recursive call would do nothing since first = last but the other would essentially be quicksort(first, last), would select the same pivot and repeat with the very same sublist.
So either pass pivot +/- 1 to one of the recursive calls (since it's a linked list I'd suggest quicksort(pivot.next, last) ) or check whether the sublist has more than 2 elements before doing the recursion.
From a quick glance... you are looping quickSort too many times and therefor you get that error.
example
private void countUp(int x){
System.out.println(x);
countUp(++x);
}
this will count about 10541 times for me... before throwing that error.
With that in mind... you might have an infinite loop somewhere OR your array are too large.
Im trying to move the Index element to the end of the singly list while shifting all other elements so If I had a list of {1, 2, 3, 4, 5} and I pass the index 2 to it, it would return {1, 2, 4, 5, 3}.
public void moveToLast(int index) throws IllegalArgumentException {
if(index<0 || index > size())
throw new IllegalArgumentException("" + index);
Node ref= first;
Node otherRef=first;
for(int i=0;i<index;i++){
ref=ref.next;
for(int j=0;j<size()-1;j++){
if(otherRef.next!=null)
otherRef=otherRef.next;
}
}
E temp=ref.data;
ref.data=otherRef.data;
otherRef.data=temp;
}
This code that I have written only switches the element at index and the last element, returning {1, 2, 5, 4, 3}
Thanks for the help and keep in mind, I am very new to coding, all help is greatly appreciated.
You have to update the references while looping, not at the end.
This is a small algorithm that saves you the double loop. I implemented it swapping the references, not the data, but there's no actual difference in the result. I'm not sure what restrictions you have about one approach or the other, but if you have methods for removing nodes and so on you usually work with references and not values.
I didn't compile it, so please excuse any error, but I think something like this should work:
public void moveToLast(int index) throws IllegalArgumentException {
if(index<0 || index > size())
throw new IllegalArgumentException("" + index);
Node refToMove= first;
Node previousRef=null;
for(int i=0;i<index && refToMove!=null;i++){
previousRef=refToMove;
refToMove=refToMove.next;
}
if(refToMove!=null && previousRef!=null) {
Node nextRef=refToMove.next;
while(nextRef!=null) {
previousRef.next = nextRef;
Node tempRef = nextRef.next;
nextRef.next = refToMove;
refToMove.next = tempRef;
nextRef = tempRef;
}
}
}
Consider this also.
if(index<0 || index > size())
does not catch all bad indexes. If index == size shouldn't be allowed as will be out of bounds and also if the index is the last element then you should return as no need to do anything, Perhaps change to
if(index<0 || index >= size())
//throw exception
if( index == (size()-1))
return
Like you say your code only swaps as you find the indexed element end last element and assign them at the end.
What you need to do is find the first then for each set the link to the next element until the end then you set the last element to link the your original index like so
public void moveToLast(int index) throws IllegalArgumentException {
if(index<0 || index >= size())
throw new IllegalArgumentException("" + index);
if( index == (size()-1))
return
Node currentElement = first;
Node elementToMove;
Node nextElement;
// if first is the one to move
if(index == 0)
{
elementToMove = first;
currentElement = first.next;
first = currentElement
}
// Iterate over the list only once
for(int i = 0; i < size()-2; i++) // up to the 2nd to last element as the next element is referenced
{
nextElement = currentElement.next
if(i+1 == index) // next element is the one you want to move
{
// store reference to the element you want to move
elementToMove = nextElement;
// Skip this element and update to the next one
nextElement = nextElement.next;
}
// Update reference
currentElement.next = nextElement;
// Move to next element
currentElement = nextElement
}
// Put the one to move on the end
currentElement.next = elementToMove
}
This saves you having to loop twice over your list, I havent checked or complied this so you might need to add null checks in here also, you many also need special consideration if the index entered is 0 i.e. you will need to reset first
Consider:
Node reverse(Node head) {
Node previous = null;
Node current = head;
Node forward;
while (current != null) {
forward = current.next;
current.next = previous;
previous = current;
current = forward;
}
return previous;
}
How exactly is it reversing the list?
I get that it first sets the second node to forward. Then it says current.next is equal to a null node previous. Then it says previous is now current. Lastly current becomes forward?
I can't seem to grasp this and how it's reversing. Can someone please explain how this works?
You reverse the list iteratively and always have the list in the interval [head, previous] correctly reversed (so current is the first node that has its link not set correctly). On each step you do the following:
You remember the next node of current so that you can continue from it
You set the link of current to be pointing to previous, which is the correct direction if you think about it
You change previous to be current, because now current also has its link set correctly
You change the first node that does not have its link set correctly to be the one remembered in the first step
If you do that for all the nodes, you can prove (with induction for instance) that the list will be correctly reversed.
The code simply walks the list and inverts the links until it reaches the previous tail, which it returns as the new head.
Before:
Node 1 (Head) -> Node 2 -> Node 3 -> Node 4 (Tail) -> null
After:
null <- Node 1 (Tail) <- Node 2 <- Node 3 <- Node 4 (Head)
The easiest way to think about it is to think like this:
First add the head of the list to a new linked list.
Keep iterating through the original and keep adding the nodes before the head of the new linked list.
Diagram:
Initially:
Original List -> 1 2 3 4 5
New List -> null
1st Iteration
Original List -> 1 2 3 4 5
New List -> 1->null [head shifted to left, now newHead contains 1 and points to null]
2nd Iteration
Original List -> 1 2 3 4 5
New List -> 2-> 1->null [head shifted to left, now newHead contains 2 and points to next node which is 1]
3rd Iteration
Original List -> 1 2 3 4 5
New List ->3 -> 2-> 1->null [head shifted to left, now newHead contains 2 and points to next node which is 1]
Now it keeps looping through till the end. So finally the new list becomes:
New List-> 5 -> 4 -> 3 -> 2 -> 1 -> null
The code for the same should be like this (made it easy to understand):
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
public ListNode reverseList(ListNode head) {
if(head == null) {
return null;
}
if(head.next == null) {
return head;
}
ListNode current = head;
ListNode previous = new ListNode(head.val);
previous.next = null;
while(current.next != null) {
current = current.next;
previous = addBeforeHead(current, previous);
}
return previous;
}
private ListNode addBeforeHead(ListNode node, ListNode head) {
if (node == null) return null;
ListNode temp = new ListNode(node.val);
temp.next = head;
head = temp;
return head;
}
public Node getLastNode()
{
if(next != null)
return next.getLastNode();
else
return this;
}
public Node reverse(Node source)
{
Node reversed = source.getLastNode();
Node cursor = source;
while(cursor != reversed)
{
reversed.addNodeAfter(cursor.getInfo());
cursor = cursor.getNodeAfter();
}
source = reversed;
return source;
}
I call it "cherry picking". The idea is to minimize the number of swaps. Swapping happens between a near and far index. It's a twp-pass algorithm.
(Odd length) A -> B -> C -> D -> E
(Even length) A -> B -> C -> D
Pre-Condition: N >= 2
Pass 1: Count N, the number of elements
Pass 2:
for(j=0 -> j<= (N/2 -1))
{
swap(j, (N-1)-j)
}
Example 1:
For above Odd length list, N = 5 and there will be two swaps
when j=0, swap(0, 4) // Post swap state: E B C D A
when j=1, swap(1, 3) // Post swap state: E D C B A
The mid point for odd length lists remains intact.
Example 2:
For above Even length list, N = 4 and there will be two swaps
when j=0, swap(0, 3) // Post swap state: D B C A
when j=1, swap(1, 2) // Post swap state: D C B A
Swapping applies to data only, not to pointers, and there might be any sanity checks missed, but you got the idea.
list_t *reverse(list_t *a)
{
list_t *progress = NULL;
while(a)
{
list_t *b; //b is only a temporary variable (don't bother focusing on it)
b = a->next;
a->next = progress; // Because a->next is assigned to another value,
// we must first save a->next to a different
// variable (to be able to use it later)
progress = a; // progress is initially NULL (so a->next = NULL
// (because it is the new last element in the list))
a = b; // We set a to b (the value we saved earlier, what
// a->next was before it became NULL)
/*
Now, at the next iteration, progress will equal a, and a will equal b.
So, when I assign a->next = progress, I really say, b->next = a.
and so what we get is: b->a->NULL.
Maybe that gives you an idea of the picture?
What is important here is:
progress = a
and
a = b
Because that determines what a->next will equal:
c->b->a->0
a's next is set to 0
b's next is set to a
c's next is set to b
*/
}
return progress;
}
The basic idea is to detach the head node from the first list and attach it to the head of a second list. Keep repeating until the first list is empty.
Pseudocode:
function reverseList(List X) RETURNS List
Y = null
WHILE X <> null
t = X.next
X.next = Y
Y = X
X = t
ENDWHILE
RETURN Y
ENDfunction
If you wish to leave the original list undisturbed then you can code a copying version recursively with the use of a helper function.
function reverseList(List X) RETURNS List
RETURN reverseListAux(X, null)
ENDfunction
function reverseListAux(List X, List Y) RETURNS List
IF X = null THEN
RETURN Y
ELSE
RETURN reverseListAux(X.next, makeNode(X.data, Y))
ENDfunction
Note that the helper function is tail recursive. This means that you can create a copying reversal using iteration.
function reverseList(List X) RETURNS List
Y = null
WHILE X <> null
Y = makeNode(x.data, Y)
X = X.next
ENDWHILE
RETURN Y
ENDfunction
Reversing a singly-linked list using iteration:
current = head // Point the current pointer to the head of the linked list
while(current != NULL)
{
forward = current->link; // Point to the next node
fforward = forward->link; // Point the next node to next node
fforward->link = forward; // 1->2->3,,,,,,,,,this will point node 3 to node 2
forward->link = current; // This will point node 2 to node 1
if(current == head)
current->link = NULL; // If the current pointer is the head pointer it should point to NULL while reversing
current = current->link; // Traversing the list
}
head = current; // Make the current pointer the head pointer
Implementation of a singly-linked list reversal function:
struct Node
{
int data;
struct Node* link;
}
Node* head = NULL;
void reverseList()
{
Node* previous, *current, *next;
previous = NULL;
current = head;
while(current != NULL)
{
next = current-> link;
current->link = previous;
previous = current;
current = next;
}
head = previous;
}
Here is a simple function to reverse a singly linked list
// Defining Node structure
public class Node {
int value;
Node next;
public Node(int val) {
this.value=val;
}
}
public LinkedList reverse(LinkedList list) {
if(list==null) {
return list;
}
Node current=list.head;
Node previous=null;
Node next;
while(current!=null) {
next=current.next;
current.next=previous;
previous=current;
current=next;
}
list.head=previous;
return list;
}
For better understanding, you can watch this video https://youtu.be/6SYVz-pnVwg
If you want to use recursion:
class Solution {
ListNode root=null;
ListNode helper(ListNode head)
{
if (head.next==null)
{ root= head;
return head;}
helper (head.next).next=head;
head.next=null;
return head;
}
public ListNode reverseList(ListNode head) {
if (head==null)
{
return head;
}
helper(head);
return root;
}
}
public void reverseOrder() {
if(head == null) {
System.out.println("list is empty");
}
else {
Node cn = head;
int count = 0;
while (cn != null) {
count++;
cn = cn.next;
}
Node temp;
for(int i = 1; i<=count; i++) {
temp = head;
for(int j = i; j<count; j++) {
temp = temp.next;
}
System.out.print(temp.data+" ->");
}
System.out.print("null");
}
}