Yaroslavsky Dual-pivot Quicksort Java implementation - java

I'd like to ask you if you can show me how my code might look like so I might not get java.lang.StackOverflowError during the sort of 100000 ints (My implementation is good but only to 20000 numbers , bigger sizes of table to sort will produce that error). I've tryied to change the size of heap in InteliJ , but that way seems not to be working.Also I've spend like 2 hours trying to modyfy it and reading about it over the web , yet I can't overcome this problem. That's why I'm asking you guys , to show me where can I change my code in my implementation so I won't recive that error.
Here is the code:
import java.util.ArrayList;
import java.util.Random;
public class YaroslawskiSort {
Random gener;
public int temporary,genertype,NInts;
ArrayList<Integer> mylist;
public YaroslawskiSort(int type,int ilosc){
gener = new Random();
mylist= new ArrayList<>();
this.genertype=type;
this.NInts=ilosc;
}
void generate(){
if(genertype==0){
for(int i=0;i<NInts;i++){
mylist.add(gener.nextInt(100000));
}
}else {
for(int i=0;i<NInts;i++){
mylist.add(NInts-i);
}
}
}
void sortingI(int left,int right) {
for (int i=left+1;i<=right;i++)
{
int value = mylist.get(i);
int j =i-1;
while (j >= left && mylist.get(j)>value)
{
mylist.set(j+1,mylist.get(j));
j--;
}
mylist.set(j+1,value);
}
}
private void sorting( int left, int right) {
if((right-left)>=17) {
int[] index=new int[2];
index = partition(left, right);
if (left < index[0]) {
sorting(left, index[0]);
}
if(index[0]<index[1]){
sorting(index[0], index[1]);
}
if (index[1] < right) {
sorting(index[1], right);
}
}
if((right-left)<17 && (right-left)!=0){
sortingI(left,right); //INSERTION SORT!
}
}
private int[] partition( int left, int right) {
int pivot1 = mylist.get(left);
int pivot2 = mylist.get(right);
if(pivot1>pivot2){
mylist.set(left,pivot2);
mylist.set(right,pivot1);
temporary=pivot1;
pivot1=pivot2;
pivot2=temporary;
}
int L=left+1;
while(mylist.get(L)<pivot1 && L<right){
L++;
}
int K=L;
while( K<=right&& mylist.get(K)>=pivot1 && mylist.get(K)<=pivot2 ){
K++;
}
int G=right-1;
while(mylist.get(G)>pivot2 && G>left){
G--;
}
while (K <= G) {
if(mylist.get(K)<pivot1){
mylist.add(left+1,mylist.remove(K));
L++;
K++;
}
if(mylist.get(K)>=pivot1 && mylist.get(K)<=pivot2){
mylist.add(L,mylist.remove(K));
K++;
}
if(mylist.get(K)>pivot2){
mylist.add(right,mylist.remove(K));
G--;
}
}
mylist.set(left,mylist.get(L-1));
mylist.set(L-1,pivot1);
mylist.set(right,mylist.get(G+1));
mylist.set(G+1,pivot2);
int[] table=new int[2];
table[0]=L;
table[1]=G;
return table;
}
void printing(){
for(int k=0;k<NInts;k++){
System.out.print(" "+mylist.get(k));
}
}
public static void main(String[] args){
YaroslawskiSort instance = new YaroslawskiSort(1,100000);
instance.generate();
instance.sorting(0, instance.mylist.size() - 1);
instance.printing();
}
}
Thanks for helping :)

Your code is working good, to increase stack size open Edit configuration... of your project in intellij IDEA (top right corner) and in field VM options type -Xss16m. If you do so, you will not get StackOverflowError.
In my opinion you get StackOverflow cause you're recursively call sorting method and it in its turn call partition method where always a new int[2] is created and all of these arrays are on stack.
If you can rewrite partition method so it (for example) return int and call it for left and right bound separately, I think this will fix the problem.

Related

I'm trying to implement merge sort but the output i get is the same array

I'm trying to implement merge sort but the output i get is the same array.this merge sort gives me the same output as input.plz help.i'm pretty sure the implementation is correct and i tried debugging it but couldnt figure out the mistake.
Solved: i was comparing helper[left] to helper[mid] instead of helper right. Thanks for the help people.
public class Sort {
public static void main(String[] args){
int arr[] = {3,5,6,9,0,2,4};
Sort sort = new Sort();
int i=0;
sort.MergeSort(arr);
for(i=0;i<arr.length;i++){
System.out.print(arr[i]);
}
}
private void MergeSort(int[] arr2) {
// TODO Auto-generated method stub
int helper[] = new int[arr2.length];
MergeSort(arr2,helper,0,arr2.length-1);
}
private void MergeSort(int[] arr2,int[] helper,int start, int end) {
if(start<end){
int mid = (start+end)/2;
MergeSort(arr2,helper,start,mid);
MergeSort(arr2,helper,mid+1,end);
Merge(arr2,helper,start,mid,end);
}else{
//do nothing
}
}
private void Merge(int[] arr2, int[] helper, int start, int mid, int end) {
// TODO Auto-generated method stub
int i;
for(i=start;i<=end;i++){
helper[i]=arr2[i];
}
i=start;
int left = start;
int right = mid+1;
while(left <= mid && right <= end){
if(helper[left] <= helper[mid]){
arr2[i] = helper[left];
left++;
}else{
arr2[i] = helper[right];
right++;
}
i++;
}
//move remaining of left to array
int remaining = mid-left;
int j;
for(j=0;j<=remaining;j++){
arr2[i+j]=helper[left+j];
}
}
}
Tricky one... :-)
you are always comparing the element at leftto the element at mid instead of the element at right:
while(left <= mid && right <= end){
if(helper[left] <= helper[mid]){
should be
while(left <= mid && right <= end){
if(helper[left] <= helper[right]){
Optional, but more clear:
Besides as Matt mentioned you are missing to catch up remaining values from the right arm
while (left <= mid)
arr2[i++] = helper[left++];
while (right <= end) {
arr2[i++] = helper[right++];
Edit: Mark right arm catchup as optional
I think it's that your merge() function is missing a certain case.
//move remaining of left to array
int remaining = mid-left;
int j;
for(j=0;j<=remaining;j++){
arr2[i+j]=helper[left+j];
}
takes care of if the right sub-array was exhausted first, but does not consider the case if the left sub array was exhausted first (which may lead to some unusual results). I know this wasn't quite what you were trying to ask and I will keep looking at your code to see if I can help.
Happy Coding! Leave a comment if you have any questions.

Java program crashes with StackOverflow when using bubble sort of a large array

I have written a small Java program implementing the bubble sort technique for int arrays. It works for arrays of 1000 units, but when I increase it to 10 000, it crashes with java.lang.StackOverflowError.
Here is the code:
import java.util.*;
import java.lang.*;
class BubbleSort
{
public static void main (String [] argv)
{
int Array [] = new int [10000];
for (int a = 0; a < 10001; a++)
{
Array[a] = (int) (Math.random()*100);
}
// generated an array of 10000 units and filled with random numbers
for (int end = Array.length-1; end >= 0; end--)
{
BubbleSort (Array, 0, end);
}
}
public static int BubbleSort (int A [], int count, int end)
{
if (count == end) //debugger says crash occurs here
{
return count;
}
else
{
if (A[count] > A[count+1])
{
int temp = A[count];
A[count] = A[count+1];
A[count+1] = temp;
return BubbleSort(A, count+1, end); //and here
}
else
{
return BubbleSort(A, count+1, end);
}
}
}
}
Any help very appreciated!
Keeping aside the logic, the technical reason as to why it fails at 10000 is because each thread in Java has a fixed stack size. And when you use 10000 it is unable to find enough memory.
Use -XX:ThreadStackSize=512 to increase the default memory that JVM allocates to threads and it may work. But generally you don't have to bother about it.
On a sidenote check whether you really require recursion over here.

Java comb sort caught in an infinite loop

I'm doing a combsort algorithim as a class assignment, and it loops whenever I run it. I'm not sure what I did wrong (I got it working in C++, but that was a while ago, and those skills don't translate as well as I'd like them to). I've been poring over it for an hour and a half now, and emailed some friends, but nobody has any ideas, unfortunately. I think I just need someone with some more experience to tell me what I screwed up. Thanks!
import java.util.ArrayList;
public class CombSort {
public CombSort()
{
super();
}
public ArrayList<Integer> combSort(ArrayList<Integer> sortMe)
{
int swap;
int size = sortMe.size();
int gap = size;
boolean swapped = false;
while ((gap > 1) || swapped)
{
if (gap > 1)
{
gap = (int) ((size)*((double)gap / 1.247330950103979));
}
swapped = false;
for (int i = 0; gap + i < size; ++i)
{
if (sortMe.get(i) - sortMe.get(i + gap) > 0)
{
swap = sortMe.get(i);
sortMe.set(i, sortMe.get(i + gap));
sortMe.set(i + gap, swap);
swapped = true;
}
}
}
return sortMe;
}
public static void main(String[] args)
{
ArrayList<Integer> randomArrayList = new ArrayList<Integer>(7);
randomArrayList.add(5);
randomArrayList.add(7);
randomArrayList.add(2);
randomArrayList.add(6);
randomArrayList.add(8);
randomArrayList.add(2);
randomArrayList.add(9);
CombSort combSorter = new CombSort();
System.out.println(combSorter.combSort(randomArrayList).toString());
}
}
Your gap value is getting bigger with each iteration inside the while loop, hence why it is infinitely looping.
You should only multiply the gap by the comb factor, not by the size.
(int) ((size)*((double)gap / 1.247330950103979)); should be
(int) ((double)gap / 1.247330950103979);

Java: QuickSort on LinkedList gives me exception

I'm studying for exam (Algorithms and data structures), and I'm trying to make quicksort work for LinkedList but it's giving me ListIndexOutOfBoundsException.
For homework a while ago, I used straightinsertion for sorting ArrayList and Vector, now I'd like to understand QuickSort (I do in theory) for LinkedList.
I'm not too familiar with linkedlist, but it shouldn't be too different from ArrayList?
public class Sort {
public static void quickSort(LinkedList<Oseba> a) {
sort(a, 0, a.size() - 1); // this is line 16
}
public static void sort(LinkedList<Oseba> a, int l, int r) {
int i = l;
int j = r;
Oseba x = a.get((l + r) / 2), w;
do {
while (a.get(i).mlajsi(x)) {
++i;
}
while (x.mlajsi(a.get(j))) { // this is line 31
--j;
}
if (i <= j) {
w = a.get(i);
a.set(i, a.get(j));
a.set(j, w);
++i;
--j;
}
} while (i <= j);
if (l < j) {
sort(a, l, j);
}
if (i < r) {
sort(a, i, r);
}
}
}
Oseba means 'a Person', it's a class I made for testing various methods (like sorting, comparing)
public class Oseba implements Comparable<Oseba> {
protected String priimekIme; //surnameName
protected int letoRojstva; //year of birth
protected Spol spol; //gender (enum)
public Oseba(String priimekIme, int letoRojstva, Spol spol) {
this.priimekIme = priimekIme;
this.letoRojstva = letoRojstva;
this.spol = spol;
}
#Override
public int compareTo(Oseba o) {
if (this.letoRojstva < o.letoRojstva) {
return -1;
} else if (this.letoRojstva > o.letoRojstva) {
return 1;
} else {
return this.priimekIme.compareTo(o.priimekIme);
}
}
public boolean mlajsi(Oseba o) { //younger
return (o.letoRojstva - this.letoRojstva <= 0);
}
#Override
public String toString() {
String s = priimekIme + ", " + spol.getKratko() + ", " + letoRojstva;
return s;
}
}
And this is an error I get:
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: -1, Size: 6
at java.util.LinkedList.checkElementIndex(LinkedList.java:553)
at java.util.LinkedList.get(LinkedList.java:474)
at javaapplication1.Sort.sort(Sort.java:31)
at javaapplication1.Sort.quickSort(Sort.java:16)
at javaapplication1.JavaApplication1.main(JavaApplication1.java:55)
Java Result: 1
This quicksort method is supposed to work with Vector or ArrayList, I don't know why it wouldn't with LinkedList?
Thanks!
Well you don't check for boundaries during your loops.
while (a.get(i).mlajsi(x)) {
++i;
}
while (x.mlajsi(a.get(j))) { // this is line 31
--j;
}
should be
while (i <= r && a.get(i).mlajsi(x)) {
++i;
}
while (j >= l && x.mlajsi(a.get(j))) { // this is line 31
--j;
}
and
} while (i <= j);
strictly speaking, should also take account that i and j are inside the boundaries (but i think it is not neccessary).
It will solve the exception issue, but I didn't verify the correctness of the algorithm.
One of the big rules in Java (and OO in general) is "code to interfaces, not to implementations." Right now, you're coding to the LinkedList implementation of the List interface. The only way to guarantee that this code will work with any List (Vector, ArrayList, etc.) is to change your declarations. For instance:
public static void quickSort(LinkedList<Oseba> a) {
Should become
public static void quickSort(List<Oseba> a) {
And similarly with sort:
public static void sort(List<Oseba> a, int l, int r) {
Now, whenever you declare a person, it should look like this:
List<Oseba> a = LinkedList<Oseba>();
But in the place of LinkedList, you can substitute any other type of list.
This doesn't answer the question of why your code is failing -- I think UmNyobe's advice is good, though I didn't test it -- but it answers your lesser question as to why this code isn't acting like other list types. It's because you're coding to the implementation, where you should be using the interface.

Finding the largest positive int in an array by recursion

I decided to implement a very simple program recursively, to see how well Java handles recursion*, and came up a bit short. This is what I ended up writing:
public class largestInIntArray {
public static void main(String[] args)
{
// These three lines just set up an array of ints:
int[] ints = new int[100];
java.util.Random r = new java.util.Random();
for(int i = 0; i < 100; i++) ints[i] = r.nextInt();
System.out.print("Normal:"+normal(ints,-1)+" Recursive:"+recursive(ints,-1));
}
private static int normal(int[] input, int largest) {
for(int i : input)
if(i > largest) largest = i;
return largest;
}
private static int recursive(int[] ints, int largest) {
if(ints.length == 1)
return ints[0] > largest ? ints[0] : largest;
int[] newints = new int[ints.length - 1];
System.arraycopy(ints, 1, newints, 0, ints.length - 1);
return recursive(newints, ints[0] > largest ? ints[0] : largest);
}
}
And that works fine, but as it's a bit ugly I wondered if there was a better way. If anyone has any thoughts/alternatives/syntactic sugar to share, that'd be much appreciated!
P.s. If you say "use Lisp" you win nothing (but respect). I want to know if this can be made to look nice in Java.
*and how well I handle recursion
Here's how I might make the recursive method look nicer:
private static int recursive(int[] ints, int largest, int start) {
if (start == ints.length) {
return largest;
}
return recursive(ints, Math.max(ints[start], largest), start + 1);
}
This avoids the expensive array copy, and works for an empty input array. You may implement an additional overloaded method with only two parameters for the same signature as the iterative function:
private static int recursive(int[] ints, int largest) {
return recursive(ints, largest, 0);
}
2 improvements:
no copy of the array (just using the offset)
no need to give the current max
private static int recursive(int[] ints, int offset) {
if (ints.length - 1 == offset) {
return ints[offset];
} else {
return Math.max(ints[offset], recursive(ints, offset + 1));
}
}
Start the recursion with recursive(ints, 0).
You could pass the current index as a parameter rather than copying almost the entire array each time or you could use a divide and conquer approach.
public static int max(int[] numbers) {
int size = numbers.length;
return max(numbers, size-1, numbers[size-1]);
}
public static int max(int[] numbers, int index, int largest) {
largest = Math.max(largest, numbers[index]);
return index > 0 ? max(numbers, index-1, largest) : largest;
}
... to see how well Java handles recursion
The simple answer is that Java doesn't handle recursion well. Specifically, Sun java compilers and Hotspot JVMs do not implement tail call recursion optimization, so recursion intensive algorithms can easily consume a lot of stack space.
However, I have seen articles that say that IBM's JVMs do support this optimization. And I saw an email from some non-Sun guy who said he was adding it as an experimental Hotspot extension as a thesis project.
Here's a slight variation showing how Linked Lists are often a little nicer for recursion, where "nicer" means "less parameters in method signature"
private static int recursive(LinkedList<Integer> list) {
if (list.size() == 1){
return list.removeFirst();
}
return Math.max(list.removeFirst(),recursive(list));
}
Your recursive code uses System.arrayCopy, but your iterative code doesn't do this, so your microbenchmark isn't going to be accurate. As others have mentioned, you can clean up that code by using Math.min and using an array index instead of the queue-like approach you had.
public class Maximum
{
/**
* Just adapted the iterative approach of finding maximum and formed a recursive function
*/
public static int max(int[] arr,int n,int m)
{
if(m < arr[n])
{
m = arr[n];
return max(arr,n - 1,m);
}
return m;
}
public static void main(String[] args)
{
int[] arr = {1,2,3,4,5,10,203,2,244,245,1000,55000,2223};
int max1 = max(arr,arr.length-1,arr[0]);
System.out.println("Max: "+ max1);
}
}
I actually have a pre made class that I setup for finding the largest integer of any set of values. You can put this class into your project and simply use it in any class like so:
System.out.println(figures.getLargest(8,6,12,9,120));
This would return the value "120" and place it in the output. Here is the methods source code if you are interested in using it:
public class figures {
public static int getLargest(int...f) {
int[] score = new int[f.length];
int largest=0;
for(int x=0;x<f.length;x++) {
for(int z=0;z<f.length;z++) {
if(f[x]>=f[z]) {
score[x]++;
}else if(f[x]<f[z]) {
}else {
continue;
}
if(z>=f.length) {
z=0;
break;
}
}
}
for(int fg=0;fg<f.length;fg++) {
if(score[fg]==f.length) {
largest = f[fg];
}
}
return largest;
}
}
The following is a sample code given by my Java instructor, Professor Penn Wu, in one of his lectures. Hope it helps.
import java.util.Random;
public class Recursion
{
static int s = 0;
public static Double max(Double[] d, int n, Double max)
{
if (n==0) { return max;}
else
{
if (d[n] > max)
{
max = d[n];
}
return max(d, n-1, max);
}
}
public static void main(String[] args)
{
Random rn = new Random();
Double[] d = new Double[15];
for (int i=0; i
{
d[i] = rn.nextDouble();
System.out.println(d[i]);
}
System.out.print("\nMax: " + max(d, d.length-1, d[0]));
}
}
Here is my alternative
public class recursion
{
public static int max( int[] n, int index )
{
if(index == n.length-1) // If it's simple, solve it immediately:
return n[index]; // when there's only one number, return it
if(max(n, index+1) > n [index]) // is one number bigger than n?
return max(n, index+1); // return the rest, which contains that bigger number
return n[index]; // if not, return n which must be the biggest number then
}
public static void main(String[] args)
{
int[] n = {100, 3, 5, 1, 2, 10, 2, 15, -1, 20, -1203}; // just some numbers for testing
System.out.println(max(n,0));
}
}

Categories

Resources