I can't figure out why I'm getting StackOverFlowError - java

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.

Related

Time & Space Complexity of Merge K Sorted List

I wrote this solution to the problem mentioned, I am having trouble finding the complexities since I am less familiar with heaps, any suggestion/correction in my complexity analysis would help.
If n is the size of ArrayList
and m is the length of the longest linked list
According to me, the complexities should be as follows
Space Complexity: O(nm) (for heap)
Time Complexity: O(nm) (doubt this one)
public class Solution {
public ListNode mergeKLists(ArrayList<ListNode> a) {
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
for(ListNode node: a) {
while(node != null) {
minHeap.add(node.val);
node = node.next;
}
}
ListNode head = new ListNode(0);
ListNode temp = head;
while(minHeap.size() > 0) {
ListNode newNode = new ListNode(minHeap.poll());
temp.next = newNode;
temp = temp.next;
}
return head.next;
}
}
If you have k sorted lists, and n total elements, then the time complexity of merging the lists is O(n * log(k)). The heap space required is O(k). Here's how it works.
First, create the heap and the head node of each list into it. So rather than a PriorityQueue<Integer>, you'd have a PriorityQueue<ListNode>. You'll have to write a custom comparator, of course, to sort on the value of the ListNode.
Now, when you poll the heap, you get the ListNode at the head of that list. If that node's next is not null, then push next back onto the heap. If the node's next is null, then you're at the end of that list and you don't push anything back onto the heap.
It looks something like:
ListNode head = new ListNode(0);
ListNode temp = head;
for each ListNode in a
minHeap.add(a)
while minHeap is not empty
node = minHeap.pop()
if node.next is not null
minHeap.push(node.next)
temp.next = node;
temp = node;
return head.next;

LinkedList function from InterviewBit

I'm struggling with my solution for a question on InterviewBit.
I linked to the full description, but in short:
1) You are given the head node of a linkedlist
2) take the first half of the list and change the values so that:
"1st node’s new value = the last node’s value - first node’s current value
2nd node’s new value = the second last node’s value - 2nd node’s current value"
Here is my approach (it compiles but does not mutate the list at all)
I see that my method does not actually modify the original list -- it seems like what I'm doing is making a new list with the correctly altered values, but not changing the original.
/**
* Definition for singly-linked list.
* class ListNode {
* public int val;
* public ListNode next;
* ListNode(int x) { val = x; next = null; }
* }
*/
public class Solution {
public ListNode subtract(ListNode a) {
ListNode current = a;
int length = 0;
//get length
while(current.next != null){
length++;
current = current.next;
}
length += 1;
while(current.next != null){
double half = Math.floor(length/2);
for(int i=0; i<half; i++ ){
//
// if(i == 0){
// int aval = (nthToLast(a, length)).val - a.val;
// a.val = ((nthToLast(a, length-i)).val - a.val);
// a.next = current;
// }
current.val = ((nthToLast(a, length-i)).val - current.val);
current = current.next;
}
}
return a;
}
/* Helper function that given LinkedList head, and int n,
returns the nth to last ListNode in the LinkedList */
public ListNode nthToLast(ListNode head, int n){
ListNode nth = head;
ListNode ahead = head;
/* strategy: set nth to head, and 'ahead' to n places in front of 'nth'
increment at same speed and then when 'ahead' reaches the end, 'nth'
will be in the nth place from the end.
*/
while(ahead.next != null){
for(int i=0; i<n; i++){
ahead = ahead.next;
}
nth = nth.next;
ahead = ahead.next;
}
return nth;
}
}
Also -- I'm trying to get better at questions like these. Is this an ok approach for this question? I'd like to figure out how to make this work, but also if this is an all around bad approach please let me know.
break code into simple helper functions,
make a function to get value of nth element in the linked list(this function is very easy to write)
,and then traverse the list upto the half every time calling that function to get the value of listSize-i member of the list and edit the value of the the ith member of the list. and make changes to the 1st few elements manually to check weather your linkList implementation is working or not
/**
* Definition for singly-linked list.
**/
class ListNode {
public int val;
public ListNode next;
ListNode(int x) { val = x; next = null; }
}
public class Solution {
public ListNode subtract(ListNode a) {
ListNode current = a;
int length = 0;
//get length
while(current.next != null){
length++;
current = current.next;
}
length += 1;
int half = length/2;
//logic of this loop is
//go from 0 to half of the list
// j goes from the last element to half
//for example if size of list is 6 (indexing from 0)
//when i is 0 j is 5
//when i is 1 j is 4 and so on
//so you get what you wanted
for(int i=0,j=length-1; i<half; i++,j-- ){
current.val=nthElement(a,j).val-current.val;
current = current.next;
}
return a;
}
/* Helper function that given LinkedList head, and int n,
returns the nth node of LinkedList */
public ListNode nthElement(ListNode head, int n){ //e.g-if n is 5 it will return the 5th node
ListNode nth = head;
for(int i=0; i<n; i++){
nth = nth.next;
}
return nth;
}
}

How to determine the space and time complexity of these two algorithms?

I was practicing one algorithm exercise today from HackerRank: https://www.hackerrank.com/challenges/find-the-merge-point-of-two-joined-linked-lists
I decided to solve this problem with two solutions.
First algorithm, based on Floyd's algorithm:
/*
Insert Node at the end of a linked list
head pointer input could be NULL as well for empty list
Node is defined as
class Node {
int data;
Node next;
}
*/
int FindMergeNode(Node headA, Node headB) {
// Complete this function
// Do not write the main method.
int length1 = countLength(headA);
int length2 = countLength(headB);
int d = Math.abs(length1 - length2);
return (length1 > length2) ?
findIntersection(d, headA, headB) : findIntersection(d, headB, headA);
}
int countLength(Node head) {
Node current = head;
int counter = 0;
while (current != null) {
current = current.next;
counter++;
}
return counter;
}
int findIntersection(int d, Node headA, Node headB) {
Node currentA = headA;
Node currentB = headB;
for (int i = 0; i < d; i++) {
currentA = currentA.next;
}
while (currentA != null && currentB != null) {
if (currentA == currentB) return currentA.data;
currentA = currentA.next;
currentB = currentB.next;
}
return -1;
}
Second algorithm, using one outer and inner loop:
/*
Insert Node at the end of a linked list
head pointer input could be NULL as well for empty list
Node is defined as
class Node {
int data;
Node next;
}
*/
int FindMergeNode(Node headA, Node headB) {
Node currentA = headA;
while (currentA != null) {
Node currentB = headB;
while (currentB != null) {
if (currentA == currentB) {
return currentA.data;
}
currentB = currentB.next;
}
currentA = currentA.next;
}
return -1;
}
Honestly, I'm sure that the first algorithm is better than the second because of its performance. I would like to demonstrate this performance using SPACE and TIME COMPLEXITY, I have not dominated those topics.
According to the material, this solution should be Time Complexity: O(N). But I'm not quite sure that the first algorithm will be O(N).
The first algorithm scans headA and headB once to find the lengths, then skips the extra elements of the longer chain, then scans in parallel the two chains. The time complexity is proportional to the length of the chains, so it is O(N). It doesn't matter if you scan the lists 2, 3, or 5 times, as long as that number is constant, the time complexity is still O(N).
The second algorithm is worse, for each element in headA before the merge point, it scans the entire headB. In the worst case, when the lists don't intersect at the last node, it will scan all elements of headB for each element of headA. So the time complexity of this is O(N^2).
The space complexity of both algorithms is O(1), because you use constant storage in both (a bunch of local variables), that don't change, regardless the size of the input lists.
The first one is O(N) where N is in abstract the greatest of the two list length. Since you have two for loops and each can cost at max N, in the worst case the first algorithm will take 2 N cycle to end. So since O hide constant factor the algorithm is O(N)

Quicksort Median of Three

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

How can I reverse a linked list?

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");
}
}

Categories