Array Sorting Performance - java

This is a pretty simple, straightforward problem, but, of course, I've managed to do something wrong. First, I generated 5 different arrays of 10 random numbers--from 1 to 10, 1 to 100, up to 1 to 100,000. Then I took each array and performed 5 different types of sorts (for a total of 25), calculating the time it takes to perform the sorts. I cannot figure out why each and every result is 0ms regardless of the size of n. What am I doing wrong?
public class Lab16Sorting {
public static void main(String[] args)
{
final int TOTAL_NUMBERS = 10;
int count;
int[] num = new int[TOTAL_NUMBERS];
Random rand = new Random();
// Generate 10 numbers from 1 - 10
System.out.println("SORT 10");
System.out.println("----------------");
for (count = 0; count < TOTAL_NUMBERS; count++)
num[count] = rand.nextInt(10);
System.out.println("Array: " + num);
runSort(num);
// Generate 10 numbers from 1 - 100
System.out.println("\nSORT 100");
System.out.println("----------------");
for (count = 0; count < TOTAL_NUMBERS; count++)
num[count] = rand.nextInt(100);
System.out.println("Array: " + num);
runSort(num);
// Generate 10 numbers from 1 - 1,000
System.out.println("\nSORT 1,000");
System.out.println("----------------");
for (count = 0; count < TOTAL_NUMBERS; count++)
num[count] = rand.nextInt(1000);
System.out.println("Array: " + num);
runSort(num);
// Generate 10 numbers from 1 - 10,000
System.out.println("\nSORT 10,000");
System.out.println("----------------");
for (count = 0; count < TOTAL_NUMBERS; count++)
num[count] = rand.nextInt(10000);
System.out.println("Array: " + num);
runSort(num);
// Generate 10 numbers from 1 - 100,000
System.out.println("\nSORT 100,000");
System.out.println("----------------");
for (count = 0; count < TOTAL_NUMBERS; count++)
num[count] = rand.nextInt(100000);
System.out.println("Array: " + num);
runSort(num);
}
/**
* Run sort algorithms
*/
private static void runSort(int[] num)
{
long before;
long after;
// Run and display selection sort
before = System.currentTimeMillis();
selectionSort(num);
after = System.currentTimeMillis();
System.out.println("Selection sort took "+ (after-before) +" milliseconds");
// Run and display bubble sort
before = System.currentTimeMillis();
bubbleSort(num);
after = System.currentTimeMillis();
System.out.println("Bubble sort took "+ (after-before) +" milliseconds");
// Run and display insertion sort
before = System.currentTimeMillis();
insertionSort(num);
after = System.currentTimeMillis();
System.out.println("Insertion sort took "+ (after-before) +" milliseconds");
// Run and display merge sort
before = System.currentTimeMillis();
mergeSort(num);
after = System.currentTimeMillis();
System.out.println("Merge sort took "+ (after-before) +" milliseconds");
// Run and display quick sort
before = System.currentTimeMillis();
quickSort(num);
after = System.currentTimeMillis();
System.out.println("Quick sort took "+ (after-before) +" milliseconds");
}
I printed out the various array addresses and I see they're all the same (which makes sense since I'm using the same array object). I thought that was the problem and so I tried using different arrays (int[] num, int[] num2...) and I tried re-initializing the array after each runSort() method call with num = new int[TOTAL_NUMBERS].

That's because the size 10 is too less to actually find out the difference in timings between the various types of sorts. Try to increase your size to somewhere around 50,000 to 1,00,000, to actually be able to see the difference(even then its gonna be in few seconds).
And if your machine can take enough load, then go about sorting elements in the range of 10,00,000(highly non-advisable just for testing time difference).

RJ is correct, you array is just too small that the sorting algorithms don't matter.
Also see this thread
Test case for Insertion Sort, MergeSort and Quick Sort

The sorting algorithm is a tuned quicksort, adapted from Jon L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function", Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November 1993). This algorithm offers n*log(n) performance on many data sets that cause other quicksorts to degrade to quadratic performance.
Above is in java doc.

Related

Timing bubble sorting in different scenarios

I am trying determine the running times of bubble sort algorithm in three different kinds of input:
1) randomly selected numbers
2) already sorted numbers
3) sorted in reverse order numbers
My expectation about their running time was:
Reverse ordered numbers would take longer than other two.
Already sorted numbers would have the fastest running time.
Randomly selected numbers would lie between these two.
I've tested the algorithm with inputs containing more than 100.000 numbers. The results wasn't like I expected. Already sorted numbers had the fastest running time but randomly selected numbers took almost twice as much time to execute compared to reverse ordered numbers. I was wondering why this is happening?
Here is how I test the inputs
int[] random = fillRandom();
int[] sorted = fillSorted();
int[] reverse = fillReverse();
int[] temp;
long time, totalTime = 0;
for (int i = 0; i < 100; i++) {
temp = random.clone();
time = System.currentTimeMillis();
BubbleSort.sort(temp);
time = System.currentTimeMillis() - time;
totalTime += time;
}
System.out.println("random - average time: " + totalTime/100.0 + " ms");
totalTime = 0;
for (int i = 0; i < 100; i++) {
temp = sorted.clone();
time = System.currentTimeMillis();
BubbleSort.sort(temp);
time = System.currentTimeMillis() - time;
totalTime += time;
}
System.out.println("sorted - average time: " + totalTime/100.0 + " ms");
totalTime = 0;
for (int i = 0; i < 100; i++) {
temp = reverse.clone();
time = System.currentTimeMillis();
BubbleSort.sort(temp);
time = System.currentTimeMillis() - time;
totalTime += time;
}
System.out.println("reverse - average time: " + totalTime/100.0 + " ms");
Benchmarks for java code are not easy, as JVM might apply a lot of optimizations to your code at runtime. It can optimize out a loop if computation result is not used, it can inline some code, JIT can compile some code into native and many other things. As a result, benchmark output is very unstable.
There are tools like jmh that simplify benchmarking a lot.
I recommend you to check this article, it has an example of benchmark for sorting algorithm.

How to measure the time it took to sort an array for each sorting algorithms?

I'm trying to create a program that measures the time it takes for each sorting algorithm to sort 50 random integers. The array not sorted is first printed and then the array sorted is printed. The output I get for each sorting algorithm when the time measured is 0. What could I change in my code to do this better?
public static void main(String[] args)
{
System.out.println("Please enter the size of array:");
Scanner input = new Scanner(System.in);
int arraySize =input.nextInt();
int[] array = new int[arraySize];
if (arraySize == 50) {
initValues();
printValues();
System.out.println("values is sorted: " + isSorted());
System.out.println();
// make call to sorting method here (just remove //)
selectionSort();
long startTime = System.currentTimeMillis();
long total = 0;
long stopTime = System.currentTimeMillis();
long elapsedTime = stopTime-startTime;
selectionSort();
//bubbleSort();
//shortBubble();
//insertionSort();
//mergeSort(0, SIZE - 1);
//quickSort(0, SIZE - 1);
//heapSort();
printValues();
System.out.println("values is sorted: " + isSorted());
System.out.println();
System.out.println("The time it took to sort was: " +elapsedTime);
}
else {
System.out.println("The size of the array should be 50");
}
}
Thank you in advance!
It's quite hard to perform a micro benchmark correctly, but for a very simple start you can do this:
Don't use currentTimeMillis, use nanoTime instead for measuring elapsed time
Use a loop and perform the sort e.g. 10K times and measure that and then divide it by 10K etc

Calculate Average of Previous Loop - Java

So, I am working on this code for my AP Computer Science class, and I ran into a problem.
First, here is my code:
//loop counters
int counterOne = 0;
int counterElse = 0;
int loop = 1;
int iNum = 1000;
//create file
PrintWriter outFile = new PrintWriter(new File("newFile.txt"));
for (int counter = 1; counter <= iNum; counter++)
{
while (loop >= 1)
{
Random rand = new Random();
int iRand = rand.nextInt(5)+1;
if (iRand != 1)
{
counterElse++;
loop++;
}//end of if of if-else
else
{
counterOne++;
loop = 0;
}//end of else of if-else
}//end of while loop
int tries = counterElse+counterOne;
//int average = (tries + prevTriesSum) / counter
System.out.println("It took " + tries + " try/tries to win!");
//outFile.println("It tool an average of " + average + " tries to win.");
}//end of for loop
How do I calculate the average of the trials? As you can see from the end of my code, I commented out a line that I would want to calculate the average. This is because I don't know how to calculate prevTriesSum, which represents the sum of all of the other trials. Here is an example: Assume the loop runs six times, and with the first run, it takes 3 tries, 5 on the second run, 7 on the third, 11 on the fourth, 2 on the fifth, and 4 on the sixth (the most recent one. now tries = 4).
I would want prevTriesSum to equal 3 + 5 + 7 + 11 + 2 + 4.
How do I get the program to calculate that?
Your average is computed in integer arithmetic which means any fractional part is discarded. Consider using a floating point type for the average, and prefix the right hand side of the assignment with 1.0 * to force the calculation to occur in floating point.
You must not reinitialise the random generator in the loop, else you ruin its statistical properties. Do it once before you enter the loop.
Before the while loop, add
int prevTriesSum = 0;
Replace your commented int average = line with
prevTriesSum += tries;
And after the for loop add
double average = (prevTriesSum + 0.0) / counter;
outFile.println("It tool an average of " + average + " tries to win.");
As for the random number generator, Bathsheba is correct. You must move that above the for loop. Just move the declaration.
You'll also need to change your for loop slightly. As it stands, it will equal 1001 when the for loop terminates. Change it as follows:
for (int counter = 0; counter < iNum; counter++)
This will ensure that your average calculation is correct.

Why does my array search take 0 nanoseconds after search is looped beyond 2000 times?

I wrote a program for a Java class I am taking to search a String array of 10 elements for a specific target. The program searches for the target from the beginning of the array to the end of the array and then searches from the end of the array to the beginning of the array. Each search is timed and looped 1000 times. After each search method has been looped 1000 times, the fastest search method is chosen to search the array for whatever number of 'reps' I passed as an argument in the main method.
The problem I am having is when I change the number of loops to beyond 2000. From roughly 2100 the time it takes to search the array in nanoseconds is frequently 0. Is this because the JVM has warmed up and the time it takes to search a 10 element array can't be measured in nanoseconds? I realize that probably sounds silly.
I am just going to paste the whole program here for reference(the program is far from complete but compiles and runs):
public class LinearStringSearch {
// Array filled with random Strings
String[] randomStrings = {"apple", "yellow", "fire", "wood", "zinc",
"ram", "mouse", "fish", "cheese", "dirt"};
// Save target arguments for global access(console printing purposes)
int indexOfTarget;
String target;
String target2;
long startTime;
long startTime2;
long estimatedTime;
long estimatedTime2;
long sumForward;
long sumBackward;
long counterFrontToEnd;
long counterEndToFront;
long counterTied;
// Arrays for search times
ArrayList<Long> forwardSearchTimes = new ArrayList<>();
ArrayList<Long> backwardSearchTimes = new ArrayList<>();
/**
*
* #param target - the item you want to retrieve from array
* #param sa - the name of the array
* #return i - the target, otherwise return error code: -1
*/
int linearStringSearch(String target, String[] sa) {
this.target = target; // set class variable for print access
startTime = System.nanoTime(); // Start speed test
for(int i = 0; i < sa.length; ++i) {
if (sa[i].equals(target)) {
estimatedTime = System.nanoTime() - startTime; // End speed test
indexOfTarget = i; // update index for printing purposes
forwardSearchTimes.add(estimatedTime);
System.out.println("Forwards - Target found at index:" + i + " " + estimatedTime);
return i; // return the index of target
}
}
return -1; // -1 means that target was not found
}
/**
*
* #param target - the item you want to retrieve from array
* #param sa - the name of the array
* #return i - the target, otherwise return error code: -1
*/
int reverseLinearStringSearch(String target, String[] sa) {
this.target2 = target; // set class variable for print access
startTime2 = System.nanoTime(); // Start speed test
for(int i = sa.length-1; i >= 0; --i) {
if (sa[i].equals(target)) {
estimatedTime2 = System.nanoTime() - startTime2; // End speed test
backwardSearchTimes.add(estimatedTime2);
System.out.println("Backwards: - Target found at index:" + i + " " + ", Time: " + estimatedTime2);
return i; // return the index of target
}
}
return -1; // -1 means that target was not found
}
/**
*
* #param estimatedTime - estimated time of search beginning to end
* #param estimatedTime2 - estimated time of search end to beginning
* #return fastest method
*/
public String deduceFastestSearchMethod() {
if(sumForward < sumBackward) {
return "Linear search found " + "'"
+ target + "'" + " fastest overall";
}
if(sumForward > sumBackward) {
return "Reverse linear search found " +
"'" + target + "'" + " fastest overall";
}
return "Same";
}
public void counter(){
if(estimatedTime < estimatedTime2) {
counterFrontToEnd++;
}
else if(estimatedTime > estimatedTime2) {
counterEndToFront++;
}
else {
counterTied++;
}
}
// Implement Fisher–Yates shuffle
public void shuffleArray(String[] sa){
Random rnd = new Random();
for (int i = sa.length - 1; i > 0; i--){
int index = rnd.nextInt(i + 1);
// Simple swap
String a = sa[index];
sa[index] = sa[i];
sa[i] = a;
}
}
/********************************************************Methods for Repetitions**************************************************/
// Set the number of times each method is called
public void setReps(String target, String[] sa, long reps) {
boolean chosenFastest = false;
boolean forwardsIsFaster = false;
shuffleArray(sa); // Shuffle the order of Strings in array
for (int i = 0; i < reps; i++){
if(chosenFastest){
if(forwardsIsFaster)
linearStringSearch(target, sa);
else
reverseLinearStringSearch(target, sa);
}
else {
linearStringSearch(target, sa);
reverseLinearStringSearch(target, sa);
counter(); // counts winner
}
if (i == 1000)
chosenFastest = true;
if(sumForward < sumBackward)
forwardsIsFaster = true;
System.out.println("Loop #: " + i + "\n");
}
System.out.println("Linear search was faster: " + counterFrontToEnd + " times");
System.out.println("Reverse linear search was faster: " + counterEndToFront + " times");
System.out.println("Tied: " + counterTied + " times");
System.out.println("\nTarget " + "'" + target2 + "'" + " found at index: " + indexOfTarget);
calcSearchTimesForward(reps);
calcSearchTimesReverse(reps);
}
public void calcSearchTimesForward(long reps) {
sumForward = 0;
double average = 0;
for (Long i : forwardSearchTimes)
sumForward += i;
average = (double)sumForward/reps;
System.out.println("\nAverage speed searching array front to end(" + reps + " trials):" );
System.out.println("Nanoseconds: " + average);
}
public void calcSearchTimesReverse(long reps) {
sumBackward = 0;
double average = 0;
for (Long i : backwardSearchTimes)
sumBackward += i;
average = (double)sumBackward/reps;
System.out.println("\nAverage speed searching array end to front(" + reps + " trials):" );
System.out.println("Nanoseconds: " + average);
}
/*
* The target string is searched from the beginning of the array to the end of the array, then
* from the end of the array to the beginning of the array.
*
*/
public static void main(String[] args) {
LinearStringSearch lss = new LinearStringSearch();
// Set repetitions
lss.setReps("mouse", lss.randomStrings, 10000); // Pass arguments
// Print fastest search
System.out.println();
System.out.println(lss.deduceFastestSearchMethod());
}
}
Here is the output:
//................
Backwards: - Target found at index:3 , Time: 453 nanoseconds
Loop #: 9992
Backwards: - Target found at index:3 , Time: 0 nanoseconds
Loop #: 9993
Backwards: - Target found at index:3 , Time: 0 nanoseconds
Loop #: 9994
Backwards: - Target found at index:3 , Time: 0 nanoseconds
Loop #: 9995
Backwards: - Target found at index:3 , Time: 0 nanoseconds
Loop #: 9996
Backwards: - Target found at index:3 , Time: 0 nanoseconds
Loop #: 9997
Backwards: - Target found at index:3 , Time: 0 nanoseconds
Loop #: 9998
Backwards: - Target found at index:3 , Time: 0 nanoseconds
Loop #: 9999
Linear search was faster: 432 times
Reverse linear search was faster: 282 times
Tied: 287 times
Target 'mouse' found at index: 3
Average speed searching array front to end(10000 trials):
Nanoseconds: 167.1195
Average speed searching array end to front(10000 trials):
Nanoseconds: 967.341
Linear search found 'mouse' fastest overall
Generally, a JVM will implement System.nanoTime() using the most accurate timer the operating system provides, but that usually isn't accurate down to the nano second, not is querying that timer instantenous (on my hardware, it takes 2 microseconds). And even if it were, your program is not guaranteed exclusive use of the hardware by the operating system, i.e. if another process wants the CPU, the operating system may suspend your program for a couple milliseconds to give the other process a chance to run.
Therefore, if you want a reliable benchmark, you can only assume the timer to be accurate to a couple milliseconds. The typical workaround is something like this:
long start = System.nanoTime();
for (int i = 0; i < reps; i++) {
codeToTest();
}
long end = System.nanoTime();
System.out.println((end - start) / reps + " ns");
where reps is chosen so elapsed time is suitably big.
For a truly good benchmark, you should also take the effects of just in time compilation into account. A quite comprehensive list may be found at How do I write a correct micro-benchmark in Java?

how to get more signficant digits to print from a long value?

I am trying to print a long value held by elapsed, can someone help me with the format of how to do it?
This prints 0.0
but i know it has more significant digits (maybe like .0005324 or something)
System.out.println("It took " + (double)elapsed + " milliseconds to complete SELECTION_SORT algorithm.");
'
System.currentTimeMillis();
long start = System.currentTimeMillis();
int sortedArr[] = selectionSort(arr1);
long elapsed = System.currentTimeMillis() - start;
System.out.println("\n///////////SELECTIONSort//////////////");
System.out.println("\nSelection sort implemented below prints a sorted list:");
print(sortedArr);
System.out.printf("It took %.7f ms....", elapsed);
//System.out.println("It took " + (double)elapsed + " milliseconds to complete SELECTION_SORT algorithm.");'
'
private static int[] selectionSort(int[] arr) {
int minIndex, tmp;
int n = arr.length;
for (int i = 0; i < n - 1; i++) {
minIndex = i;
for (int j = i + 1; j < n; j++)
if (arr[j] < arr[minIndex])
minIndex = j;
if (minIndex != i) {
tmp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = tmp;
}
}
return arr;
}'
Changing the format won't give you more resolution which is what your real problem is hee if you print 1 ms with 7 digits you just get 1.0000000 every time. This doesn't help you at all.
What you need is a high resolution timer
long start = System.nanoTime();
int sortedArr[] = selectionSort(arr1);
long elapsed = System.nanoTime() - start;
System.out.println("\n///////////SELECTIONSort//////////////");
System.out.println("\nSelection sort implemented below prints a sorted list:");
print(sortedArr);
System.out.printf("It took %.3f ms....", elapsed / 1e6);
However, if you do this once you are fooling yourself because Java compiles code dynamically and gets fast the more you run it. It can get 100x faster or more making the first number you see pretty useless.
Normally I suggest you run loops many times and ignore the first 10,000+ times. This will change the results so much that you will see that the first digit was completely wrong. I suggest you try this
for(int iter = 1; iter<=100000; iter *= 10) {
long start = System.nanoTime();
int[] sortedArr = null
for(int i=0;i<iter;i++)
sortedArr = selectionSort(arr1);
long elapsed = System.nanoTime() - start;
System.out.println("\n///////////SELECTIONSort//////////////");
System.out.println("\nSelection sort implemented below prints a sorted list:");
print(sortedArr);
System.out.printf("It took %.3f ms on average....", elapsed / 1e6 / iter);
}
You will see you results improve 10x maybe even 100x just by running the code for longer.
You can use print formatting. For a double or float, to get 7 places after the decimal place, you would do:
System.out.printf("It took %.7f ms....", elapsed);
EDIT:
You are actually using a long, not a double, so you cannot have significant digits, because long only takes on integer values.
A long is an integer value and does not have decimal places.
To get an approximation of the runtime, run the same sort in a loop, say 1000 times and then divide the measured time by 1000.
For example:
System.out.println("It took " + ((double)elapsed) / NUMBER_OF_ITERATONS);
Try this:
String.format("%.7f",longvalue);
by using above line you can format your long or any floating point numbers. Here 7 is referred how many digits you want after '.' .

Categories