Stack_Overflow_error while calling mergeSort method - java

I’ve been doing this problem:
I created one file which takes random numbers and I stored those numbers in a SinglyLinkedList data structure and I'd like to perform a mergeSort to sort these random numbers.
Everything works fine for smaller no of input.
But when I insert 10000 numbers, it starts giving ‘stack_overflow’ error at around 9800 no(at displaying numbers only) and when I insert 0.1 million numbers- it works well till 99700 numbers but then it starts showing errors for the rest of the numbers.
So what exactly the reason would be behind this error (I know it’s because it gets lost in recursive function)
Please help me out here, I'm not able to track the problem which causes this error.
Here's my main method code:
FileReader fr = new FileReader("C://my_folder//file_List.txt");
BufferedReader br = new BufferedReader(fr);
LinkedListNode lln = new LinkedListNode();
String str;
while((str=br.readLine())!=null){
/* This insertAtEnd appends the number to the SinglyLinkedList*/
lln.insertAtEnd(Integer.parseInt(str));
System.out.println(" "+str);
}
/*This method displays the elements of a LinkedList*/
Node res = lln.traverse();
System.out.println("\n");
mergeSortLinkedList ms = new mergeSortLinkedList();
ms.sort(res);
here's my sort method code:
public void sort(Node n){
Node tmp = n;
MergeSort(tmp);
}
Node a;
Node b;
public void MergeSort(Node headRef){
Node head1 = headRef;
if(head1 == null || head1.next == null){
return;
}
System.out.print("hi..");
Node Euler = splitList(head1);
printList(Euler);
}
/* perform merge sort on the linked list */
public Node splitList(Node head1){
Node slow;
Node fast;
Node left, right;
if(head1 == null || head1.next == null){
left = head1;
right = null;
return head1;
}
else{
slow = head1;
fast = head1.next;
while(fast!=null){
fast = fast.next;
if(fast!=null){
slow = slow.next;
fast = fast.next;
}
}
left = head1;
right = slow.next;
slow.next = null;
}
return SortedMerge(splitList(left),splitList(right));
}
/* merge the lists.. */
public Node SortedMerge(Node a, Node b){
Node result = null;
if(a == null){
return b;
}
else if( b == null){
return a;
}
if(a.data < b.data){
result = a;
result.next = SortedMerge(a.next, b);//getting error at this line
}
else{
result = b;
result.next = SortedMerge(a,b.next);//getting error at this line
}
return result;
}
public void printList(Node Euler){
System.out.println("\nPrinting sorted elements");
Node Ref = Euler;
int count = 0;
while(Ref!=null){
count++;
System.out.println(count+"-"+Ref.data);
Ref = Ref.next;
}
}

have you considered using Collections.sort() from the JDK, which will do a merge-sort? Java 8 has also a parallelSort which does a parallel merge-sort.

I’d like to give you a update.
By changing the stack size, I did able to run my program properly.
The reason it was causing
Exception in thread "main" java.lang.StackOverflowError is because it was getting out of stack size.
So I searched around and got this solution.
Go to the project properties- Inside run, go to the VM option and put this in argument -Xss100m to make it run!
Now it is able to sort more than 1 million numbers :D
Other suggestions / solutions are welcome.

Related

Cycle detection in java

I'm working on a hackerrank problem and it seems like no matter the variation of the solution I try, I can't get the cycle detection to work.
Here's the code I'm using
static boolean hasCycle(SinglyLinkedListNode head) {
if (head == null) return false;
SinglyLinkedListNode slow, fast;
slow = head;
fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) return true;
}
return false;
}
I can tweak the solution to get the other test to pass, but not both. In this case true is never returned, even when it should be. How can I fix this, what am I doing wrong?
It has to do with Hackerrank itself. I tried my own solution that passed all the tests some time ago but it also failed for cases where there were cycles. So, I took a look at Hackerrank's insertNode method used for creating lists in test cases:
public void insertNode(int nodeData) {
// here a new node object is created each time a method is called
SinglyLinkedListNode node = new SinglyLinkedListNode(nodeData);
if (this.head == null) {
this.head = node;
} else {
this.tail.next = node;
}
this.tail = node;
}
And then how it's used in their main:
public static void main(String[] args) throws IOException {
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(System.getenv("OUTPUT_PATH")));
int tests = scanner.nextInt();
scanner.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
for (int testsItr = 0; testsItr < tests; testsItr++) {
int index = scanner.nextInt();
scanner.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
SinglyLinkedList llist = new SinglyLinkedList();
int llistCount = scanner.nextInt();
scanner.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
for (int i = 0; i < llistCount; i++) {
int llistItem = scanner.nextInt();
scanner.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
// a new node is inserted each time so no cycle can be created whatsoever.
llist.insertNode(llistItem);
}
boolean result = hasCycle(llist.head);
bufferedWriter.write(String.valueOf(result ? 1 : 0));
bufferedWriter.newLine();
}
bufferedWriter.close();
scanner.close();
}
As you can see for each llistItem value llist.insertNode(llistItem) is invoked to add an item to the list. This method, however, can't create cycles as it creates a new SinglyLinkedListNode each time. So, even though some llistItem values are the same the nodes containing them are always different.
UPDATE
As of January 5, 2020, Hackerrank tests are fixed and the solution provided by the OP passes all of them.
Tests of this challenge are incorrect, and there are no loops. Check it by printing out head.next....next. You can get NPE where tests waiting for return TRUE. See linked lists generations in other languages.

Segregate even and odd nodes in a Linked List

Given, a linked-list, I'm trying to partition it into so that the even nodes come before the odd nodes. My approach is to create two different linked-list (even and odd) to store even numbers and odd numbers. However, I'm running into a problem when I want to add to the even or odd linked list (I commented the part that I think is giving me problem in my code below). Thanks!
public class SeperateOddEven {
static Node head;
static int count;
public static class Node {
int data;
Node next;
private Node(int data) {
this.data = data;
next = null;
count++;
}
}
public void seperate() {
Node even = null;
Node odd = null;
Node temp;
// go through each linked-list and place node in new list depending on whether they are even or odd
while(head != null) {
// if even, place in even linked-list
if(head.data % 2 == 0) {
temp = new Node(head.data);
even = temp; // Problem here
even = even.next; // and here
} else { // if head.data % 2 != 0
temp = new Node(head.data);
odd = temp;
odd = odd.next;
}
head = head.next;
}
toString(even);
//toString(odd);
}
public void toString(Node node) {
while (node != null) {
System.out.print(node.data + " ");
node = node.next;
}
}
public static void main(String[] args) {
SeperateOddEven s = new SeperateOddEven();
head = new Node(8);
head.next = new Node(12);
head.next.next = new Node(10);
head.next.next.next = new Node(5);
head.next.next.next.next = new Node(4);
head.next.next.next.next.next = new Node(1);
head.next.next.next.next.next.next = new Node(6);
System.out.println("original list: ");
s.toString(head);
s.seperate();
}
}
I believe you identified exactly where the problem is. Let's go line by line:
temp = new Node(head.data);
The extra temp variable is unnecessary but fine.
even = temp;
A problem arises on the next line however. You assign even to temp (making temp unnecessary). If something was previously stored in even, it is now lost to the garbage collector because you now have no reference to it. even and temp are now both references to the same Node object.
What I think you might have wanted to do was to say even.next = temp. This would start to create a list, but with only a single reference you would have to use that reference to point to the head of the list. Each time you wanted to append to the list, you would need to loop through it until you found the end. If you instead tried to make this single reference point to the tail of the list, you would no longer have any way to get back to the head because your Nodes only have next references, and not prev references (a list with bidirectional references is called a doubly linked list).
even = even.next;
Because even (and temp) both point to the newly created Node object, the even.next property is null. So when this line executes, even now points to null. The work inside the loop has accomplished nothing because you immediately lose references to every Node you create.
Try something like this:
// Must keep track of head reference, because your Nodes can only go forward
Node evenHead = null;
Node evenTail = null;
Node oddHead = null;
Node oddTail = null;
while (head != null) {
if(head.data % 2 == 0) {
if (evenHead == null) {
// The even list is empty, set the head and tail
evenHead = new Node(head.data);
evenTail = evenHead;
} else {
// Append to the end of the even list
evenTail.next = new Node(head.data);
evenTail = evenTail.next;
}
} else {
// similar code for odd, consider creating a method to avoid repetition
}
}
You can also try this :
while (head != null) {
// if even, place in even linked-list
temp = new Node(head.data);
if (head.data % 2 == 0) {
if(even == null) {
even = temp;
} else{
Node insertionNode = even;
while(insertionNode.next != null)
insertionNode = insertionNode.next;
insertionNode.next = temp;
}
} else { // if head.data % 2 != 0
if(odd == null) {
odd = temp;
} else{
Node insertionNode = odd;
while(insertionNode.next != null)
insertionNode = insertionNode.next;
insertionNode.next = temp;
}
}
head = head.next;
}

Cycle in a linked list

My code needs to find a cycle in a linked list. If there is a cycle then the output is 1; the result is 0 otherwise. I've done research and learnt about Floyd's cycle algorithm and came across several other posts that contain the code for the algorithm. But I'm failing some test cases here on HackerRank. Could smb please tell me what is wrong with the code? Thanks!
int HasCycle(Node head) {
if(head == null){
return 0;
}
Node slow = head;
Node fast = head;
while(true)
{
slow = slow.next;
if(fast.next != null){
fast = fast.next.next;
}
else{
return 0;
}
if(slow == null || fast == null){
return 0;
}
if(slow.data == fast.data){
return 1;
}
}
}
Your issue is when a linked list has .data fields with all 10 for example. Then it always is a cycle according to your algo. You need if slow==fast return 1 as opposed to if slow.data==fast.data.

Using "temporary" variables in Double Linked Lists

I was supposed to make a Double Linked List in Java in a given exercise. Is it a good practice to use temporary variables to store values in order to sort the list ascending/descending? Is it possible to sort it ascending/descending without using these temporary/auxiliary variables? I've been trying to do it for the last couple hours but haven't succeeded.
This is how I declared my list:
private static class List {
public int num;
public List next;
public List previous;
}
In my main method, I declared the starting and ending points:
List start = null;
List end = null;
List current;
Then, the exercise demanded that it was allowed to add numbers both at the beginning and at the end of the list. This is how I add it at the beginning of the list:
List newElement = new List();
newElement.num = input.nextInt();
if (start == null) {
start = newElement;
end = newElement;
newElement.next = null;
newElement.previous = null;
} else {
newElement.next = start;
start = newElement;
start.next.previous = start;
}
And at the end of the list:
newElement.num = input.nextInt();
if (start == null) {
start = newElement;
end = newElement;
newElement.next = null;
newElement.previous = null;
} else {
end.next = newElement;
end.previous = end;
end = newElement;
newElement.next = null;
}
Finally, how I sort it ascending:
current = start;
int tmp = 0; //temporary variable that I do not know wether I'm supposed to use or not
while (current.next != null) {
if (current.num > current.next.num) {
tmp = current.next.num;
current.next.num = current.num;
current.num = tmp;
}
current = current.next;
}
current = end;
tmp = 0;
while (current.previous != null) {
if (current.num < current.previous.num) {
tmp = current.previous.num;
current.previous.num = current.num;
current.num = tmp;
}
current = current.previous;
}
Sometimes it scrambles some numbers, depending on the other, so I suppose it's not correct. To fix that, I tried checking the list both forward and reverse, as you can see in the code above, but apparently that's not the problem.
Is there a way to sort it ascending without using a temporary variable? I've already tried at least 20 times but it always lost reference to either next or previous addresses. I'm a beginner.
Do you know there is a well known problem to swap two numbers without using temporary variable.Look for that and the temporary variable will be gone.

Java - Iterative deepening search with nodes

I'm in the process of designing a program that is meant to search through a two-dimensional array of numbers that represents a map for a path to a specified end point. I've been using nodes that have several parameters, most prominently adjacent north, south, east, and west nodes each representing a square within the map. The search method I'm currently trying to finish is with iterative deepening but every time I try running the program, I wind up with a stack overflow error. This is the iterative deepening class.
import java.util.*;
import java.io.*;
public class IDeepeningSearch {
private Node start;
private Node end;
private int[][] map;
private ArrayList<Node> solution;
//Build using file handler
public IDeepeningSearch(String file){
FileHandler handle = new FileHandler(file);
//Create map
map = handle.getMap();
//Start node coordinates and value
start = new Node();
start.setRow(handle.getSRow());
start.setCol(handle.getSCol());
start.setValue(map[start.getRow()][start.getCol()]);
//End node coordinates
end = new Node();
end.setRow(handle.getERow());
end.setCol(handle.getECol());
end.setValue(map[start.getRow()][start.getCol()]);
}
//Runs search
public void run(){
int i = 0;
solution = new ArrayList<Node>();
//Value of i indicates depth to be explored; will increment with each failure
while(solution.isEmpty()){
search(start, i);
i++;
}
if(!solution.isEmpty()){
System.out.println("It worked.");
}
System.out.println("If you're not seeing the other message then it failed.");
}
//Building tree
public void build(Node head){
setNLeaf(head);
setSLeaf(head);
setELeaf(head);
setWLeaf(head);
// if(head.getNorth() != null){
// build(head.getNorth());
// }
// if(head.getSouth() != null){
// build(head.getSouth());
// }
// if(head.getEast() != null){
// build(head.getEast());
// }
// if(head.getWest() != null){
// build(head.getWest());
// }
}
//Performs search
public void search(Node head, int depth){
if(head.getRow() == end.getRow() && head.getCol() == end.getCol()){
solution.add(head);
return;
}
else{
if(depth == 0){
return;
}
build(head);
if(head.getNorth() != null){
search(head.getNorth(), depth--);
}
if(head.getSouth() != null){
search(head.getSouth(), depth--);
}
if(head.getEast() != null){
search(head.getEast(), depth--);
}
if(head.getWest() != null){
search(head.getWest(), depth--);
}
}
}
//Sets north leaf
public void setNLeaf(Node node){
//Determines if parent is on edge of map and if desired space has 0 value
if(node.getRow() != 0 && map[node.getRow() - 1][node.getCol()] != 0){
Node n = new Node();
n.setRow(node.getRow() - 1);
n.setCol(node.getCol());
n.setValue(map[n.getRow()][n.getCol()]);
n.setParent(node);
node.setNorth(n);
}
}
//Sets south leaf
public void setSLeaf(Node node){
//Determines if parent is on edge of map and if desired space has 0 value
if(node.getRow() != (map.length - 1) && map[node.getRow() + 1][node.getCol()] != 0){
Node n = new Node();
n.setRow(node.getRow() + 1);
n.setCol(node.getCol());
n.setValue(map[n.getRow()][n.getCol()]);
n.setParent(node);
node.setSouth(n);
}
}
//Sets east leaf
public void setELeaf(Node node){
//Determines if parent is on edge of map and if desired space has 0 value
if(node.getRow() != (map[0].length - 1) && map[node.getRow()][node.getCol() + 1] != 0){
Node n = new Node();
n.setRow(node.getRow());
n.setCol(node.getCol() + 1);
n.setValue(map[n.getRow()][n.getCol()]);
n.setParent(node);
node.setEast(n);
}
}
//Sets west leaf
public void setWLeaf(Node node){
//Determines if parent is on edge of map and if desired space has 0 value
if(node.getCol() != 0 && map[node.getRow()][node.getCol() - 1] != 0){
Node n = new Node();
n.setRow(node.getRow());
n.setCol(node.getCol() - 1);
n.setValue(map[n.getRow()][n.getCol()]);
n.setParent(node);
node.setWest(n);
}
}
}
I thought I was doing this correctly but the errors I've been getting have been pretty constant. This is what I wind up with.
Exception in thread "main" java.lang.StackOverflowError
at Node.setSouth(Node.java:88)
at IDeepeningSearch.setSLeaf(IDeepeningSearch.java:113)
at IDeepeningSearch.build(IDeepeningSearch.java:48)
at IDeepeningSearch.search(IDeepeningSearch.java:75)
at IDeepeningSearch.search(IDeepeningSearch.java:77)
at IDeepeningSearch.search(IDeepeningSearch.java:80)
at IDeepeningSearch.search(IDeepeningSearch.java:77)
The second-to-last and last lines repeat. I've tried building a full tree as well but that either gives me another stack overflow error or a null pointer exception. I'm not really sure what the issue is here but if I can fix this, I'm sure I can finish my breadth-first search method as well.
depth-- evaluates to the original value of depth. This means that the unmodified version of depth is being passed to the recursive call to search(), so your code is never approaching the base case. Try depth-1 instead. Or, if you need the value of the local variable depth to change, --depth.
For example, this will continually print 10 until it reaches stack overflow
public void foo(int x) {
if (x == 0) {
return;
}
System.out.println(x);
foo(x--);
}
foo(10);
The StackOverflowError is because of the flawed recursive calls of search(node, depth--) as Chris Rise has mentioned in his answer. Try --depth to fix this.
There is also poor memory management in this code, which is wasting heap memory that could either slow the program due to several calls to GC (Garbage-Collector) or lead to an OutOfMemeoryError! This problem is visible in the setXLeaf(Node n) methods (e.g. setNLeaf(Node north) etc.) where every time you are creating a new Node, while this can be done only when it's necessary with a simple check:
if (node.getSouth() == null) {
Node n = new Node();
n.setParent(node);
node.setSouth(n);
}
node.getSouth().setRow(node.getRow() + 1);
node.getSouth().setCol(node.getCol());
node.getSouth().setValue(map[node.getRow() + 1][node.getCol()]);
This way you will avoid creating new objects that are unnecessary. This should be fixed in all the setXLeaf(...) methods.

Categories