having problems with inversion-counting Algorithm - java

I wrote an implementation of inversion-counting. This is an assignment being carried out in an online course. But the input i get isn't correct and according to what I have the program has a correct syntax. I dont just know were I went wrong
The program below is my implementation
import java.io.*;
class CountInversions {
//Create an array of length 1 and keep expanding as data comes in
private int elements[];
private int checker = 0;
public CountInversions() {
elements = new int[1];
checker = 0;
}
private boolean isFull() {
return checker == elements.length;
}
public int[] getElements() {
return elements;
}
public void push(int value) {
if (isFull()) {
int newElements[] = new int[elements.length * 2];
System.arraycopy(elements, 0, newElements, 0, elements.length);
elements = newElements;
}
elements[checker++] = value;
}
public void readInputElements() throws IOException {
//Read input from file and until the very last input
try {
File f = new File("IntegerArray.txt");
FileReader fReader = new FileReader(f);
BufferedReader br = new BufferedReader(fReader);
String stringln;
while ((stringln = br.readLine()) != null) {
push(Integer.parseInt(stringln));
}
System.out.println(elements.length);
fReader.close();
} catch (Exception e) {//Catch exception if any
System.err.println("Error: " + e.getMessage());
} finally {
// in.close
}
}
//Perform the count inversion algorithm
public int countInversion(int array[],int length){
int x,y,z;
int mid = array.length/2 ;
int k;
if (length == 1){
return 0;
}else{
//count Leftinversion and count Rightinversion respectively
int left[] = new int[mid];
int right[] = new int[array.length - mid];
for(k = 0; k < left.length;k++){
left[k] = array[k];
}
for(k = 0 ;k < right.length;k++){
right[k] = array[mid + k];
}
x = countInversion(left, left.length);
y = countInversion(right, right.length);
int result[] = new int[array.length];
z = mergeAndCount(left,right,result);
//count splitInversion
return x + y + z;
}
}
private int mergeAndCount(int[] left, int[] right, int[] result) {
int count = 0;
int i = 0, j = 0, k = 0;
int m = left.length, n = right.length;
while(i < m && j < n){
if(left[i] < right[j]){
result[k++] = left[i++];
}else{
result[k++] = right[j++];
count += left.length - i;
}
}
if(i < m){
for (int p = i ;p < m ;p++){
result[k++] = left[p];
}
}
if(j < n){
for (int p = j ;p < n ;p++){
result[k++] = right[p];
}
}
return count;
}
}
class MainApp{
public static void main(String args[]){
int count = 0;
CountInversions cIn = new CountInversions();
try {
cIn.readInputElements();
count = cIn.countInversion(cIn.getElements(),cIn.getElements().length);
System.out.println("Number of Inversios: " + count);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}

Your code works if the array length is a power of 2 (actually, I'm not sure whether if does, see second point below).
When reading the input, you double the array size when it's full, but you never resize it to the number of actually read items, which is stored in checker. So your array length is a power of 2, and if the number of ints read from the file is not a power of 2, you have a too long array with some trailing 0 elements corresponding to the places allocated but not filled from the file. Since you call countInversions with the length of the array and not with the number of read items, these 0s are sorted too, yielding some spurious inversions.
After reading the input, allocate a new array
int[] copy = new int[checker];
for(int i = 0; i < checker; ++i) {
copy[i] = elements[i];
}
elements = copy;
copy the elements, and discard the old array with the wrong capacity.
Another problem in your algorithm is that you never change the original array because you allocate a new array for the merge result,
int result[] = new int[array.length];
z = mergeAndCount(left,right,result);
so you are merging unsorted arrays, which may also skew the inversion count. Since you copied the halves of the input array to new arrays for the recursive calls, you can without problem put the merge result in the passed-in array, so replace the above two lines with
z = mergeAndCount(left,right,array);
to get a method that actually sorts the array and counts the inversions.

This post is tackling the problem of count inversion with Java (except for file reading, which you have done OK) - Counting inversions in an array

Related

Faster Merge Sort with Multithreading

My task is instead of giving a huge array to Arrays.sort() which only uses one thread, rather slice a big array into smaller arrays, and each thread sorts an array, then merge all the little arrays into a big one.
I mesured the time each section takes and the join() takes the longest time but i have to wait for every thread to finish.
I also tried merging after a join() since it finished sorting that array but it takes even longer.
Is there any way to make it more faster?
Merging:
/* Create new sorted array by merging 2 smaller sorted arrays */
private static int[] merge(int[] arr1, int[] arr2) {
// TODO: merge sorted arrays 'arr1' and 'arr2'
int[] mergedArray = new int[arr1.length + arr2.length];
int i = 0, j = 0, k = 0;
while (i < arr1.length && j < arr2.length) {
if (arr1[i] < arr2[j]) {
mergedArray[k] = arr1[i];
i++;
} else {
mergedArray[k] = arr2[j];
j++;
}
k++;
}
while (i < arr1.length) {
mergedArray[k] = arr1[i];
i++;
k++;
}
while (j < arr2.length) {
mergedArray[k] = arr2[j];
j++;
k++;
}
return mergedArray;
}
Slicing:
/* Creates an array of arrays by slicing a bigger array into smaller chunks */
private static int[][] slice(int[] arr, int k) {
//TODO: cut 'arr' into 'k' smaller arrays
int temp = 0;
final int[][] copyArray = new int[k][];
int x = (int) Math.ceil((double)arr.length / (double)k); // chunk size
int len = arr.length;
for (int i = 0; i < len - x + 1; i += x)
copyArray[temp++] = Arrays.copyOfRange(arr, i, i + x);
if (len % x != 0)
copyArray[temp++] = Arrays.copyOfRange(arr, len - len % x, len);
return copyArray;
}
Main:
public static int[] sort(int[] array) {
/* Initialize variables */
// TODO: check available processors and create necessary variables
int dbProcessor = Runtime.getRuntime().availableProcessors();
int[][] slicedArray;
Thread[] threads = new Thread[dbProcessor];
/* Turn initial array into array of smaller arrays */
// TODO: use 'slice()' method to cut 'array' into smaller bits
slicedArray = slice(array, dbProcessor);
/* parralelized sort on the smaller arrays */
// TODO: use multiple threads to sort smaller arrays (Arrays.sort())
int[][] finalSlicedArray = slicedArray;
int size = finalSlicedArray.length;
for (int i = 0; i < size ; ++i) {
int finalI = i;
if (finalSlicedArray[finalI] == null) {
break;
}
threads[i] = new Thread(() -> {
// counter++;
Arrays.sort(finalSlicedArray[finalI]);
});
threads[i].start();
}
for (Thread thread : threads) {
try {
if (thread == null) {
break;
}
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/* Merge sorted smaller arrays into a singular larger one */
// TODO: merge into one big array using 'merge()' multiple times
// create an empty array called 'sorted' and in a for cycle use
// 'merge(sorted, arr2d[i])' where arr2d is an array of sorted arrays
int[] sorted = new int[0];
for (int i = 0; i < size; ++i) {
if (finalSlicedArray[i] == null) {
break;
}
sorted = merge(sorted, finalSlicedArray[i]);
}
return sorted;
}

How could I improve the speed/performance for this problem, Java

I saw this challenge on https://www.topcoder.com/ for Beginners. And I really wanted to complete it. I've got so close after so many failures. But I got stuck and don't know what to do no more. Here is what I mean
Question:
Read the input one line at a time and output the current line if and only if you have already read at least 1000 lines greater than the current line and at least 1000 lines less than the current line. (Again, greater than and less than are with respect to the ordering defined by String.compareTo().)
Link to the Challenge
My Solution:
public static void doIt(BufferedReader r, PrintWriter w) throws IOException {
SortedSet<String> linesThatHaveBeenRead = new TreeSet<>();
int lessThan =0;
int greaterThan =0;
Iterator<String> itr;
for (String currentLine = r.readLine(); currentLine != null; currentLine = r.readLine()){
itr = linesThatHaveBeenRead.iterator();
while(itr.hasNext()){
String theCurrentLineInTheSet = itr.next();
if(theCurrentLineInTheSet.compareTo(currentLine) == -1)++lessThan;
else if(theCurrentLineInTheSet.compareTo(currentLine) == 1)++greaterThan;
}
if(lessThan >= 1000 && greaterThan >= 1000){
w.println(currentLine);
lessThan = 0;
greaterThan =0;
}
linesThatHaveBeenRead.add(currentLine);
}
}
PROBLEM
I think the problem with my solution, is because I'm using nested loops which is making it a lot slower, but I've tried other ways and none worked. At this point I'm stuck. The whole point of this challenge is to make use of the most correct data-structure for this problem.
GOAL:
The goal is to use the most efficient data-structure for this problem.
Let me try to present just an accessible refinement of what to do.
public static void
doIt(java.io.BufferedReader r, java.io.PrintWriter w)
throws java.io.IOException {
feedNonExtremes(r, (line) -> { w.println(line);}, 1000, 1000);
}
/** Read <code>r</code> one line at a time and
* output the current line if and only there already were<br/>
* at least <code>nHigh</code> lines greater than the current line <br/>
* and at least <code>nLow</code> lines less than the current line.<br/>
* #param r to read lines from
* #param sink to feed lines to
* #param nLow number of lines comparing too small to process
* #param nHigh number of lines comparing too great to process
*/
static void feedNonExtremes(java.io.BufferedReader r,
Consumer<String> sink, int nLow, int nHigh) {
// collect nLow+nHigh lines into firstLowHigh; instantiate
// - a PriorityQueue(firstLowHigh) highest
// - a PriorityQueue(nLow, (a, b) -> String.compareTo(b, a)) lowest
// remove() nLow elements from highest and insert each into lowest
// for each remaining line
// if greater than the head of highest
// add to highest and remove head
// else if smaller than the head of lowest
// add to lowest and remove head
// else feed to sink
}
Made you a little example with Binary search, now in Java code. It will only use Binary search when newLine is within limits of the sorting.
public static void main(String[] args) {
// Create random lines
ArrayList<String> lines = new ArrayList<String>();
Random rn = new Random();
for (int i = 0; i < 50000; i++) {
int lenght = rn.nextInt(100);
char[] newString = new char[lenght];
for (int j = 0; j < lenght; j++) {
newString[j] = (char) rn.nextInt(255);
}
lines.add(new String(newString));
}
// Here starts logic
ArrayList<String> lowerCompared = new ArrayList<String>();
ArrayList<String> higherCompared = new ArrayList<String>();
int lowBoundry = 1000, highBoundry = 1000;
int k = 0;
int firstLimit = Math.min(lowBoundry, highBoundry);
// first x lines sorter equal
for (; k < firstLimit; k++) {
int index = Collections.binarySearch(lowerCompared, lines.get(k));
if (index < 0)
index = ~index;
lowerCompared.add(index, lines.get(k));
higherCompared.add(index, lines.get(k));
}
for (; k < lines.size(); k++) {
String newLine = lines.get(k);
boolean lowBS = newLine.compareTo(lowerCompared.get(lowBoundry - 1)) < 0;
boolean highBS = newLine.compareTo(higherCompared.get(0)) > 0;
if (lowerCompared.size() == lowBoundry && higherCompared.size() == highBoundry && !lowBS && !highBS) {
System.out.println("Time to print: " + newLine);
continue;
}
if (lowBS) {
int lowerIndex = Collections.binarySearch(lowerCompared, newLine);
if (lowerIndex < 0)
lowerIndex = ~lowerIndex;
lowerCompared.add(lowerIndex, newLine);
if (lowerCompared.size() > lowBoundry)
lowerCompared.remove(lowBoundry);
}
if (highBS) {
int higherIndex = Collections.binarySearch(higherCompared, newLine);
if (higherIndex < 0)
higherIndex = ~higherIndex;
higherCompared.add(higherIndex, newLine);
if (higherCompared.size() > highBoundry)
higherCompared.remove(0);
}
}
}
You need to implement binary search and also need to handle duplicates.
I've done some code sample here which does what you want ( may contains bugs).
public class CheckRead1000 {
public static void main(String[] args) {
// generate strings in revert order to get the worse case
List<String> aaa = new ArrayList<String>();
for (int i = 50000; i > 0; i--) {
aaa.add("some string 123456789" + i);
}
// fast solution
ArrayList<String> sortedLines = new ArrayList<>();
long st1 = System.currentTimeMillis();
for (String a : aaa) {
checkIfRead1000MoreAndLess(sortedLines, a);
}
System.out.println(System.currentTimeMillis() - st1);
// doIt solution
TreeSet<String> linesThatHaveBeenRead = new TreeSet<>();
long st2 = System.currentTimeMillis();
for (String a : aaa) {
doIt(linesThatHaveBeenRead, a);
}
System.out.println(System.currentTimeMillis() - st2);
}
// solution doIt
public static void doIt(SortedSet<String> linesThatHaveBeenRead, String currentLine) {
int lessThan = 0;
int greaterThan = 0;
Iterator<String> itr = linesThatHaveBeenRead.iterator();
while (itr.hasNext()) {
String theCurrentLineInTheSet = itr.next();
if (theCurrentLineInTheSet.compareTo(currentLine) == -1) ++lessThan;
else if (theCurrentLineInTheSet.compareTo(currentLine) == 1) ++greaterThan;
}
if (lessThan >= 1000 && greaterThan >= 1000) {
// System.out.println(currentLine);
lessThan = 0;
greaterThan = 0;
}
linesThatHaveBeenRead.add(currentLine);
}
// will return if we have read more at least 1000 string more and less then our string
private static boolean checkIfRead1000MoreAndLess(List<String> sortedLines, String newLine) {
//adding string to list and calculating its index and the last search range
int indexes[] = addNewString(sortedLines, newLine);
int index = indexes[0]; // index of element
int low = indexes[1];
int high = indexes[2];
//we need to check if this string already was in list for instance
// 1,2,3,4,5,5,5,5,5,6,7 for 5 we need to count 'less' as 4 and 'more' is 2
int highIndex = index;
for (int i = highIndex + 1; i < high; i++) {
if (sortedLines.get(i).equals(newLine)) {
highIndex++;
} else {
//no more duplicates
break;
}
}
int lowIndex = index;
for (int i = lowIndex - 1; i > low; i--) {
if (sortedLines.get(i).equals(newLine)) {
lowIndex--;
} else {
//no more duplicates
break;
}
}
// just calculating how many we did read more and less
if (sortedLines.size() - highIndex - 1 > 1000 && lowIndex > 1000) {
return true;
}
return false;
}
// simple binary search will insert string and return its index and ranges in sorted list
// first int is index,
// second int is start of range - will be used to find duplicates,
// third int is end of range - will be used to find duplicates,
private static int[] addNewString(List<String> sortedLines, String newLine) {
if (sortedLines.isEmpty()) {
sortedLines.add(newLine);
return new int[]{0, 0, 0};
}
// int index = Integer.MAX_VALUE;
int low = 0;
int high = sortedLines.size() - 1;
int mid = 0;
while (low <= high) {
mid = (low + high) / 2;
if (sortedLines.get(mid).compareTo(newLine) < 0) {
low = mid + 1;
} else if (sortedLines.get(mid).compareTo(newLine) > 0) {
high = mid - 1;
} else if (sortedLines.get(mid).compareTo(newLine) == 0) {
// index = mid;
break;
}
if (low > high) {
mid = low;
}
}
if (mid == sortedLines.size()) {
sortedLines.add(newLine);
} else {
sortedLines.add(mid, newLine);
}
return new int[]{mid, low, high};
}
}

Determining if a program is fast, memory-efficient and does not have large time-complexity

Could someone please help me how I could determine whether my program is memory-efficient, fast and has low time-complexity? For one of my programs, I implemented merge sort and then called some methods here and there but since it has around 100 lines of code, I am skeptical whether it is memory efficient. Thanks guys
import java.util.*;
public class Question6 {
static void mergeSort(Integer arr1[], int o, int k, int x) {
int num1 = k - o + 1;
int num2 = x - k;
int temp1[] = new int[num1]; //creation of two temporary arrays to store in
int temp2[] = new int[num2];
for (int i = 0; i < num1; ++i) //for loops to copy the data to the temporary arrays
temp1[i] = arr1[o + i];
for (int j = 0; j < num2; ++j)
temp2[j] = arr1[k + 1 + j];
int i = 0, j = 0; //starting position of temporary arrays
int s = o; //starting position of the merged two temporary arrays
while (i < num1 && j < num2) {
if (temp1[i] <= temp2[j]) {
arr1[s] = temp1[i];
i++;
} else {
arr1[s] = temp2[j];
j++;
}
s++;
}
//code to copy elements from temp1
while (i < num1) {
arr1[s] = temp1[i];
i++;
s++;
}
//code to copy elements from temp2
while (j < num2) {
arr1[s] = temp2[j];
j++;
s++;
}
}
void forSorting(Integer arr2[], Integer t, Integer x) //main method that carries out merge sort
{
if (t < x) {
// Find the middle point
Integer a = (t + x) / 2;
// Sort first and second halves
forSorting(arr2, t, a);
forSorting(arr2, a + 1, x);
// Merge the sorted halves
mergeSort(arr2, t, a, x);
}
}
public static void main(String[] args) {
Question6 qs = new Question6();
Scanner sc = new Scanner(System.in);
Integer[] duplicate = new Integer[10];
System.out.println("Please input the numbers to be checked for repetition.");
for (int x = 0; x < 10; x++) {
duplicate[x] = sc.nextInt(); //filling array
}
int length = duplicate.length;
qs.forSorting(duplicate, 0, length - 1); //calling method forSorting
System.out.println(Arrays.toString(duplicate)); //displays the array which user fills
List<Integer> list = Arrays.asList(duplicate); //makes the array duplicate available as a list
Set<Integer> set = new LinkedHashSet<Integer>(list);
for ( Integer element : set) {
if(Collections.frequency(list, element) > 1) {
System.out.println(" Duplicate: " + element);
}
}
}
}
You can use Profiler. For Java - JProfiler, VisualVM, etc. You can check there all you looking for - how much memory yours algorithms need, the time complexity, and some more stuff.

Parallel sort not finding the top numbers

I'm writing a program which is supposed to find the 25 top numbers in a large array using threads. My algorithm seems to work fine, however when comparing the result to an Arrays.sort-ed version of the original array, it seems like my top 25-list misses some of the numbers. I really hate posting this much code in a question, but I'm completely stuck on this, and has been for a couple of hours now. I'd love some help figuring out what's wrong. Here are my classes:
Main.java
import java.util.Arrays;
import java.util.Random;
public class Main {
public static void main(String[] args) {
final int NUM_THRS = 4;
int[] numbers = new int[500];
Random generator = new Random(500);
for(int i = 0; i < numbers.length; i++) {
numbers[i] = Math.abs(generator.nextInt());
}
Thread[] thrs = new Thread[NUM_THRS];
NumberThread[] nthrs = new NumberThread[NUM_THRS];
long startTime = System.currentTimeMillis();
for(int i = 0; i < thrs.length; i++) {
int start = getStart(i, thrs.length, numbers.length);
int stop = getStop(i, thrs.length, numbers.length);
nthrs[i] = new NumberThread(numbers, start, stop);
thrs[i] = new Thread(nthrs[i]);
thrs[i].start();
}
for (int i = 0; i < thrs.length; i++) {
try {
thrs[i].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int[] top = new int[25];
int[] indices = new int[NUM_THRS];
for (int i = 0; i < indices.length; i++) {
indices[i] = 24;
}
for(int i = 0; i < top.length; i++) {
top[i] = getMax(nthrs, indices);
}
for (int i = 0; i < top.length; i++) {
System.out.println(top[i]);
}
}
public static int getMax(NumberThread[] thrs, int[] indices) {
int maxNum = 0;
int maxIdx = 0;
for(int i = 0; i < indices.length; i++) {
if(indices[i] >= 0) {
if(thrs[i].topNums[indices[i]] > maxNum) {
maxNum = thrs[i].topNums[indices[i]];
maxIdx = i;
}
}
}
System.out.println("iterate");
indices[maxIdx] = indices[maxIdx]-1;
return maxNum;
}
public static int getStart(int i, int total, int len) {
return i*len/total;
}
public static int getStop(int i, int total, int len) {
if(i != total-1) {
return (i+1)*len/total;
}
return len-1;
}
}
NumberThread.java
public class NumberThread implements Runnable {
int start, stop;
int[] numbers;
int[] topNums;
public NumberThread(int[] numbers, int start, int stop) {
this.numbers = numbers;
this.start = start;
this.stop = stop;
this.topNums = new int[25];
System.out.println(start + " " + stop);
}
#Override
public void run() {
for (int i = start; i <= stop; i++) {
inner: for (int j = topNums.length-1; j > 0; j--) {
if(numbers[i] > topNums[j]) {
topNums[j] = numbers[i];
break inner;
}
}
}
}
}
The numbers printed after main are not the same as the top numbers when I Arrays.sort the numbers-array and print the top 25. Some numbers seem to be missing.
Thanks a lot in advance.
I think that your NumberThread classes Run method isn't doing what it should do. It needs to find the 25 largest numbers in the partition you assign to it, for example if the array you are searching was already sorted then the 25 largest numbers could all be in 1 partition but what its's actually doing is overwriting the first number it finds that's smaller than the current number so you end up with less than 25 numbers and they might not be the largest.
For example consider the sequence 98 99 1 2 3... 98 would get written to topNums[19] but then overwritten with 99.
I'm also not sure about the getMax function, it seems to be trying to merge the different topNums arrays together; however the arrays aren't sorted so I don't see how it can work.

Algorithm comparison in java: test program does not work

I'm trying to compare the execution of the java implementation of QuickSort and its hybrid version (using InsertionSort for those partitions which are smaller than an integer k). I wrote a test class to analyze the behaviour of the algorithms for some values ok k (1 <= k <= 25). For each value of k the class compares for different sizes of the input array the two algorithms.
I can't run the program for some values of the size of the array, for instance for values greater than 4000. The execution reach some different values and then freeze, after a while it will finish but I have no output of the computation. (I'm using eclipse).
What could be the problem? I wish to perform the comparation of the two algoritms for an array size from 10 to 10000 (at least). The code is listed below:
public class Main {
private static final int MAX_K = 25;
private static final int MAX_SIZE = 4500;
private static final int ADD_SIZE = 100;
private static int size = 10;
private static QuickSort qSort;
private static HybridSort hSort;
private static void initArray(int[] A) {
Random rand = new Random();
for (int i = 0; i < A.length; i++) {
// A[i] = (int)(Math.random()*100000);
A[i] = rand.nextInt();
}
}
private static int[] A = new int[10];
private static int[] B = new int[10];
public static void main(String[] args) {
try {
FileWriter fstream = new FileWriter("out.txt");
BufferedWriter out = new BufferedWriter(fstream);
out.write("Init file");
qSort = new QuickSort();
hSort = new HybridSort();
/************************************************/
/* Comparison */
/************************************************/
for (int i = 1; i <= MAX_K; i++) {
hSort.setK(i);
int p = 0;
for (int j = size; j <= MAX_SIZE; j = j + ADD_SIZE) {
A = new int[j];
B = new int[j];
initArray(A);
initArray(B);
long sTime = System.nanoTime();
qSort.quickSort(A, 0, A.length - 1);
long qDuration = System.nanoTime() - sTime;
sTime = System.nanoTime();
hSort.hybridSort(B, 0, B.length - 1);
long hDuration = System.nanoTime() - sTime;
out.append(/* "\nA: " +printArray(A)+ */"K: " + i + " A["
+ j + "]\tQ = " + qDuration + " H = " + hDuration
+ "\n");
String h = Long.toString(hDuration);
String q = Long.toString(qDuration);
if (h.length() < q.length()) {
p++;
out.append("\t#OUTPERM for K: "
+ i
+ "\t\t"
+ hDuration
+ "\t\t < \t\t "
+ qDuration
+ "\t\t\t\t| A[]\t\t"
+ A.length
+ ((q.length() - h.length()) == 2 ? "\t Magn. 2"
: "") + "\n");
}
}
if (p > 0)
out.append("#P= " + p + " for K= " + i + "\n\n");
}
out.append("Close file");
out.close();
} catch (IOException e) {
}
}
}
The algorithm classes:
public class QuickSort {
public void quickSort(int[] A, int left, int right){
if (left < right) {
int m = Partition(A, left, right);
quickSort(A, left, m-1);
quickSort(A, m, right);
}
}
private int Partition(int[] A, int left, int right){
int pivot = A[right];
int i = left;
int j = right;
while (true) {
while ( (A[j] > pivot)) {
j--;
}
while ((A[i] < pivot)) {
i++;
}
if (i < j){
int swap = A[j];
A[j] = A[i];
A[i] = swap;
}else{
return i;
}
}
}
}
public class HybridSort {
int k;
int m;
InsertionSort iSort;
public HybridSort() {
k = 3;
iSort = new InsertionSort();
}
public void hybridSort(int[] A, int left, int right) {
if (left < right) {
if ((right - left) < k) {
iSort.sort(A,left,right);
} else {
m = Partition(A, left, right);
hybridSort(A, left, m - 1);
hybridSort(A, m, right);
}
}
}
private int Partition(int[] A, int left, int right) {
int pivot = A[right];
int i = left;
int j = right;
while (true) {
while ((A[j] > pivot) && (j >= 0)) {
j--;
}
while ((A[i] < pivot) && (i < A.length)) {
i++;
}
if (i < j) {
int swap = A[j];
A[j] = A[i];
A[i] = swap;
} else {
return i;
}
}
}
public void setK(int k) {
this.k = k;
}
}
Your implementation of Partition is not correct. Consider the small test below (I made Partition static for my convenience).
Both while loops won't be executed, because A[i] == A[j] == pivot. Moreover, i<j, so the two elements will be swapped, resulting in exactly the same array. Therefore, the outer while loop becomes infinite.
The same problem occurs for any array for which the first and last element are the same.
public class Test {
public static void main(String[] args) {
int[] A = {1, 1};
Partition(A, 0, 1);
}
private static int Partition(int[] A, int left, int right){
int pivot = A[right];
int i = left;
int j = right;
while (true) {
while ( (A[j] > pivot)) {
j--;
}
while ((A[i] < pivot)) {
i++;
}
if (i < j){
int swap = A[j];
A[j] = A[i];
A[i] = swap;
}else{
return i;
}
}
}
}
Have you tried increasing memory settings for your code to run in eclipse.
You may find this Setting memory of Java programs that runs from Eclipse helpful.
Some tips / possible solution?:
I haven't read your implementation of QuickSort or HybridSort but I am assuming they are correct.
If you are comparing the performance of two algorithms you should most definitely compare their performance to indentical inputs. Currently you are generating two random arrys (albeit of the same size). This isn't necessarily going to be an accurate test as I can easily find a test case where one algorithm will outperform the other if the random generator is out to troll you.
Your logic for comparing the two algorithms is a bit weird and incorrect according to me. Why do you compare the lengths of the strings of the times? according to your logic 1 is the same as 9 and 1,000,000,000 is the same as 9,999,999,999 which is clearly incorrect. One algorithm is almost 10 times faster than the other.
Moreover, one reason for no output might be the reason that you are only outputing when hybridsort is better than quicksort and not the other way around. I am sure there are other reasons as well but this could be one easily noticable reason (if your implementations are incorrect).
I do notice that you close your outputstream which is good as that is a very common reason why there is no output. You should however, close steams in the finally section of the try-catch as then they are guaranteed to close. You could be getting an IOException and in your case this would also not close the outputsteam and consequently lead to no ouput in your file.
Here is a sample structure that I would follow for doing any comparitive testing. It is easy to read and easy to debug with enough output for you to figure out which algorithm performs better. This is merely a suggestion.
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.Random;
public class Tester {
private static int[] initArray(int size) {
Random rand = new Random();
int[] arr = new int[size];
for (int i = 0; i < arr.length; i++) {
arr[i] = rand.nextInt();
}
return arr;
}
public static void main(String[] args) {
final int MAX_ITERATIONS = 25;
final int INITIAL_ARRAY_SIZE = 10;
final int MAX_ARRAY_SIZE = 4500;
final int ARRAY_SIZE_INCREMENT = 100;
long start;
int[] score = null;
PrintWriter out = null;
try {
out = new PrintWriter(new FileOutputStream("out.txt"));
for (int arraySize = INITIAL_ARRAY_SIZE; arraySize <= MAX_ARRAY_SIZE; arraySize += ARRAY_SIZE_INCREMENT) {
// score[0] is for quickSort and score[1] is for hybridSort
score = new int[2];
for (int iteration = 0; iteration < MAX_ITERATIONS; iteration++) {
int[] testArray = initArray(arraySize);
int[] testArrayCopy = new int[arraySize];
System.arraycopy(testArray, 0, testArrayCopy, 0, arraySize);
start = System.nanoTime();
// Do quicksort here using testArray
long qSortfinish = System.nanoTime() - start;
System.arraycopy(testArray, 0, testArrayCopy, 0, arraySize);
start = System.nanoTime();
// Do hybridsort here using testArrayCopy
long hybridSortfinish = System.nanoTime() - start;
// Keep score
if (qSortfinish < hybridSortfinish)
score[0]++;
else if (qSortfinish > hybridSortfinish) {
score[1]++;
} else {
score[0]++;
score[1]++;
}
}
out.println("Array Size: " + arraySize + " QuickSort: " + score[0] + " HybridSort: " + score[1]);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (out != null)
out.close();
}
}
}

Categories

Resources