Insertion sort algorithm flaw in Java code - java

So I am going through some of the common sorting algorithms and have written this:
Code:
public void insertionSort() {
int key;
int i;
for ( int j = 1; j < this.a.length; j++ ) {
key = a[j];
i = j;
while ( i > 0 && a[i-1] > key ) {
a[i] = a[i-1];
i = i - 1;
}
a[i] = key;
}
}
Result:
jan#janspc:~/Dropbox/programming/java/algorithms$ javac sort.java
jan#janspc:~/Dropbox/programming/java/algorithms$ java Test
49, 68, 60, 14, 70, 8, 83, 96, 29, 7, 92, 35, 17, 84, 31, 62, 48, 95, 16, 22, 31, 97, 72, 55, 88, 63, 1, 63, 96, 32, 74, 15, 92, 77, 50, 13, 12, 36, 90, 93, 20, 15, 67, 88, 23, 31, 95, 90, 86, 65, 35, 27, 60, 4, 90, 11, 22, 97, 65, 88, 23, 1, 25, 21, 9, 81, 87, 56, 2, 4, 63, 52, 55, 86, 62, 30, 55, 64, 19, 10, 45, 92, 87, 43, 39, 95, 20, 43, 3, 30, 74, 64, 4, 90, 91, 93, 94, 44, 87, 21,
49, 1, 1, 2, 3, 4, 4, 4, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 16, 17, 19, 20, 20, 21, 21, 22, 22, 23, 23, 25, 27, 29, 30, 30, 31, 31, 31, 32, 35, 35, 36, 39, 43, 43, 44, 45, 48, 50, 52, 55, 55, 55, 56, 60, 60, 62, 62, 63, 63, 63, 64, 64, 65, 65, 67, 68, 70, 72, 74, 74, 77, 81, 83, 84, 86, 86, 87, 87, 87, 88, 88, 88, 90, 90, 90, 90, 91, 92, 92, 92, 93, 93, 94, 95, 95, 95, 96, 96, 97, 97,
Execution took: 110628 nano sek?
As you can see from testing, the first value is not affected by sort. What's wrong with my algorithm?

In the first iteration, the while loop doesn't execute, because i < 0. In the next iteration, the while loop doesn't run because i == 0.
You should probably use while (i >= 0 && a[i] > key) (not tested though)

You need >= here:
while ( i >= 0 && a[i] > key ){
Without this change it never compares the following elements against the first one.

while ( i > 0 && a[i] > key ){ should be while ( i >= 0 && a[i] > key ){
Best luck...

In Insertion Sort we need to check each and every element from array and compare with other element getting more accurate result. The problem in your code in while loop
we need line
while ( i >= 0 && a[i] > key )

Here is another implementation of insertion sort in java
public class InsertionSort {
static int intArray[] = { 1000, 1, 100, 101, 15 };
public static void doSort() {
for (int outer = 1; outer < intArray.length; outer++) {
for(int inner=outer;inner>0; inner--){
if(intArray[inner]<intArray[inner-1]){
int temp=intArray[inner];
intArray[inner]=intArray[inner-1];
intArray[inner-1]=temp;
continue;
}
}
}
}
public static void printArray() {
for (int i = 0; i < intArray.length; i++) {
System.out.print(" " + intArray[i]);
}
}
public static void main(String args[]) {
System.out.print("Array Before Sorting->");
printArray();
doSort();
System.out.print("\nArray After Sorting ->");
printArray();
}
}
Detailed explanation of the code and/or the algortithm can be seen at -
http://www.javabrahman.com/algorithms-in-java/insertion-sort-in-java/

here is a very easy implementation of insertion sort
package insertion_sort;
public class insertion_sort {
public static void main(String ar[]) {
int[] a = {24, 13, 9, 64, 7, 23, 34, 47, 87, 9, 37, 1992};
insertion(a,12);
}
public static void insertion(int[] a, int n) {
for (int i = 1; i <= n - 1; i++) {
int value = a[i];
int hole = i;
while (hole > 0 && a[hole - 1] > value) {
a[hole] = a[hole - 1];
hole = hole - 1;
}
a[hole] = value;
}
print(a);
}
public static void print(int[] A) {
for (int i = 0; i < A.length; i++) {
System.out.print(A[i] + " ");
}
System.out.println();
}
}

Below is the pseudo code of Insertion sort(taken from CLR "Introduction to algorithms" book).
Insertion-Sort(A)
for (j=2 to A.length)
key = A[j]>
i = j-1
while i>0 && A[i]>key
A[i+1] = A[i]
i = i-1
A[i+1] = key
Your code is almost similar to above pseudo code. All you need is to change initialization of int j=0 to int j=1 in for loop:
for ( int j = 1; j < this.a.length; j++ ) {
key = a[j];
i = j - 1;
while ( i > 0 && a[i] > key ) {
a[i + 1] = a[i];
i = i - 1;
}
a[i+1] = key;
}

Corrected code:
public void insertionSort() {
int key;
int i;
for ( int j = 1; j < this.a.length; j++ ) {
key = a[j];
i = j;
while ( i > 0 && a[i-1] > key ) {
a[i] = a[i-1];
i = i - 1;
}
a[i] = key;
}
}

public static int[] insrtSort(int array[]){
for(int i=0 ; i<array.length-1;i++){
int value=array[i+1],k=i;
while(value<array[k] ){
array[k+1]=array[k];
if(k!=0)
k--;
else
array[0]=value;
}
if(k!=0)
array[k+1]=value;
}
return array;
}

This is the same code but as a method that can be passed an array of ints to sort.
public static int[] insertionSort(int[] array) {
int key;
int i;
for ( int j = 1; j < array.length; j++ ) {
key = array[j];
i = j;
while ( i > 0 && array[i-1] < key ) {
array[i] = array[i-1];
i = i - 1;
}
array[i] = key;
}
return array;
}

Related

Quicksort implementation program array out of bounds error and not sorting generated numbers

I am new to programming and cannot seem to figure out my errors when trying to write a Quicksort program. I have most of the implementation done with the exception of a few errors that I cannot seem to figure out. Here is my current code:
public class Quicksort {
public static void main(String[] args) {
Integer[] numbers = new Integer[20];
for (int i = 0; i < numbers.length; i++) {
numbers[i] = (int) (Math.random() * 100);
}
printArray(numbers);
quicksort(numbers);
printArray(numbers);
}
public static <T> void printArray(T[] array) {
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + (i < array.length - 1 ? ", " : "\n"));
}
}
public static <T> void printArrayPartition(T[] array, int low, int high, int pivot) {
for (int i = 0; i < array.length; i++) {
String element = "" + array[i];
if (i == pivot)
element = "*" + element + "*";
if (i == low)
element = "[" + element;
if (i == high)
element += "]";
System.out.print(element + (i < array.length - 1 ? ", " : "\n"));
}
}
public static <T extends Comparable<T>> void quicksort(T[] array) {
quicksort(array, 0, array.length - 1);
}
private static <T extends Comparable<T>> void quicksort(T[] array, int low, int high) {
if (low < high) {
int pivotIndex = partition(array, low, high);
int pivot = pivotIndex;
printArrayPartition(array, low, high, pivot);
quicksort(array, low - 1, pivotIndex - 1);
quicksort(array, pivotIndex + 1, high + 1);
}
}
private static <T extends Comparable<T>> int partition(T[] array, int low, int high) {
T pivotValue = array[high];
int left = low;
for (int i = 0; i < array.length; i++) {
if (array[i].compareTo(pivotValue) > 0) {
left++;
}
}
swap(array, high, left);
return left;
}
private static <T> void swap(T[] array, int a, int b) {
T temp = array[a];
array[a] = array[b];
array[b] = temp;
}
}
When running this program I am getting ArrayIndexOutOfBounds error and I'm not sure why. I have traced few my code a few times and still cannot seem to figure it out.
Stack trace:
54, 91, 26, 43, 98, 65, 88, 78, 88, 60, 58, 75, 74, 46, 79, 81, 64, 49, 67, 31
[54, 91, 26, 43, 98, 65, 88, 78, 88, 60, 58, 75, 74, 46, 79, 81, 64, 49, *31*, 67]
54, 91, 26, 43, 98, 65, 88, 78, 88, 60, 58, 75, 74, 46, *49*, 81, 64, 79], 31, 67
54, 91, 26, 43, 98, 65, 88, 78, 88, 60, 58, 75, 74, 49], *46*, 81, 64, 79, 31, 67
54, 91, 26, 43, 98, 65, 88, 78, 88, 60, 58, 75, *49*, 74], 46, 81, 64, 79, 31, 67
54, 91, 26, *75*, 98, 65, 88, 78, 88, 60, 58, 43], 49, 74, 46, 81, 64, 79, 31, 67
54, 91, 46], 75, 98, 65, 88, 78, 88, 60, 58, 43, 49, 74, *26*, 81, 64, 79, 31, 67
54, 91, *74*, 75, 98, 65, 88, 78, 88, 60, 58, 43, 49, 46], 26, 81, 64, 79, 31, 67
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -6
at Quicksort.swap(Quicksort.java:79)
at Quicksort.partition(Quicksort.java:72)
at Quicksort.quicksort(Quicksort.java:47)
at Quicksort.quicksort(Quicksort.java:52)
at Quicksort.quicksort(Quicksort.java:52)
at Quicksort.quicksort(Quicksort.java:52)
at Quicksort.quicksort(Quicksort.java:52)
at Quicksort.quicksort(Quicksort.java:52)
at Quicksort.quicksort(Quicksort.java:52)
at Quicksort.quicksort(Quicksort.java:52)
at Quicksort.quicksort(Quicksort.java:41)
at Quicksort.main(Quicksort.java:13)
In your recursive calls:
quicksort(array, low - 1, pivotIndex - 1);
quicksort(array, pivotIndex + 1, high + 1);
You subtract one from low and pivotIndex and then later pass those values to
swap(array, high, left); //via int left = low;
Which in turn calls the index of high and low. When you start the method low is set to zero. And then you subtract one to get a negative number. If the condition: if (array[i].compareTo(pivotValue) > 0) is never met then left will never be increased and you will be passing a negative number to swap(…). And in the swap() method:
T temp = array[a]; //a is left here
array[a] = array[b];
array[b] = temp;
You directly try to call the index of left which might be a negative number, thus the indexoutofboundsexception with a negative index
And in the same fashion the quicksort(array, pivotIndex + 1, high + 1); can add one to high and thus cause it to go out of bounds

Java: Selection Sort My implementation vs. another

The following is my implementation of Selection Sort:
package algorithm.selectionsort;
public class SelectionSort {
public static void main(String[] args) {
int[] myArray = selectionSort(new int[] { 9, 9, 9, 8, 7, 73, 32, 109, 1100, 432, 321, 0 });
for (int element : myArray) {
System.out.print("" + element + " ");
}
}
public static int[] selectionSort(int[] a) {
int min;
for (int i = 0; i < a.length - 1; i++) {
min = i;
for (int j = i + 1; j < a.length; j++) {
if (a[j] < a[min]) {
min = j;
int temp = a[i];
a[i] = a[min];
a[min] = temp;
}
}
}
return a;
}
}
I noticed that my instructor codes it slightly differently:
public static int[] selectionSort(int[] a) {
int min;
for (int i = 0; i < a.length - 1; i++) {
min = i;
for (int j = i + 1; j < a.length; j++) {
if (a[j] < a[min]) {
min = j;
}
}
int temp = a[i];
a[i] = a[min];
a[min] = temp;
}
return a;
}
Both implementations work. I'm curious as to what the difference here is. Is it efficiency?
The difference between your instructor's and yours is that he iterate through the array and for each element, search for the minimum, then perform a swap with the element after the wall index.
For yours, you iterate through the array and for each element, while searching for the minimum, if current value is < then the current tentative min, perform a swap with the element after the wall index.
So instead of swapping n times, you could possible swap n*n times for worst case:
Your swap for just one pass (worst case):
100, 90, 88, 70, 55, 43, 32, 28, 19, 10
90, 100, 88, 70, 55, 43, 32, 28, 19, 10
88, 100, 90, 70, 55, 43, 32, 28, 19, 10
70, 100, 90, 88, 55, 43, 32, 28, 19, 10
55, 100, 90, 88, 70, 43, 32, 28, 19, 10
43, 100, 90, 88, 70, 55, 32, 28, 19, 10
32, 100, 90, 88, 70, 55, 43, 28, 19, 10
28, 100, 90, 88, 70, 55, 43, 32, 19, 10
19, 100, 90, 88, 70, 55, 43, 32, 28, 10
10, 100, 90, 88, 70, 55, 43, 32, 28, 19
Your instructor's swap for just one pass (worst case):
100, 90, 88, 70, 55, 43, 32, 28, 19, 10
10, 90, 88, 70, 55, 43, 32, 28, 19, 100
In essence, you swap the values while in the midst of searching for the min. The "min" you swapped may not be the lowest value in the array.
ofcouse your instructor's code is more efficiency and more elegant.
What is Selection Sort?
The algorithm divides the input list into two parts: the sublist of items already sorted, which is built up from left to right at the front (left) of the list, and the sublist of items remaining to be sorted that occupy the rest of the list. Initially, the sorted sublist is empty and the unsorted sublist is the entire input list. The algorithm proceeds by finding the smallest (or largest, depending on sorting order) element in the unsorted sublist, exchanging (swapping) it with the leftmost unsorted element (putting it in sorted order), and moving the sublist boundaries one element to the right.
If the length of the list to be sorted is n, then just n times of exchange should be done, but in your code, it's n*(n-1)*(n-2)....

Random Tour Generation Issues

I am trying to generate a random tour from the graph. I am using the adjacency-list method.
There is a problem with the vertices. When I add a vertex to a particular list, the vertex gets added to all the lists in the graph. I do not understand why! Here's the code:
public static void main(String[] args) {
defaultData(6);
}
public static void defaultData(int n) {
Integer costs[] = { 26, 95, 38, 74, 80, 73, 73, 92, 22, 97, 13, 81, 41,
17, 4, 2, 47, 54, 21, 68, 78, 4, 77, 3, 66, 55, 99, 42, 62, 39, 8, 36,
53, 74, 26, 8, 42, 66, 30, 58, 69, 14, 49, 39, 85, 98, 72, 3, 18, 99,
96, 66, 64, 36, 17, 44, 70, 0, 8, 14, 62, 41, 84, 59, 94, 27, 5, 27,
96, 10, 15, 52, 43, 20, 2, 86, 45, 43, 32, 17, 49, 92, 9, 15, 6, 49,
72, 7, 51, 21, 2, 26, 63, 82, 98, 48, 21, 96, 16 };
ArrayList<ArrayList<Integer>> costGraph = new ArrayList<>();
ArrayList<ArrayList<Integer>> completeGraph = new ArrayList<>();
Random rand = new Random(System.currentTimeMillis());
int costIndex = 0;
for (int i = 0; i <= n; i++) {
ArrayList<Integer> cost = new ArrayList<>();
ArrayList<Integer> edge = new ArrayList<>();
for (int j = 0; j <= n; j++) {
if (i == j) {
continue;
}
edge.add(j);
cost.add(costs[costIndex]);
costIndex++;
}
completeGraph.add(edge);
costGraph.add(cost);
}
System.out.println(completeGraph);
ArrayList<ArrayList<Integer>> dummyGraph =
(ArrayList<ArrayList<Integer>>)completeGraph.clone();
ArrayList<ArrayList<Integer>> randomTour = new ArrayList<>();
ArrayList<Integer> dummyList = new ArrayList<>();
for (int i = 0; i <= n; i++) {
randomTour.add(dummyList);
}
System.out.println(dummyGraph);
int edgeCount = 0;
Integer row = rand.nextInt(n);
Integer start = row;
while(edgeCount <= n-1){
//dummyList = dummyGraph.get(row);
// To keep the bounds of the random equal
// to the new reduced size of the lists in the graph
Integer col = dummyGraph.get(row).get(rand.nextInt(n-edgeCount));
randomTour.get(row).add(col);
System.out.println(row);
System.out.println(randomTour);
edgeCount++;
for(int k = 0; k < n; k++)
dummyGraph.get(k).remove(row);
row = col;
}
randomTour.get(row).add(start);
System.out.println(randomTour);
}
I would be very grateful for a timely response. Thanks in advance!
You don't want to do this:
for (int i = 0; i <= n; i++) {
randomTour.add(dummyList);
}
It keeps adding the same reference lots of times, so all the ArrayLists in the ArrayList are actually the same object.
Instead you want to do this:
for (int i = 0; i <= n; i++) {
randomTour.add(new ArrayList<Integer>());
}
That way the ArrayList instances in the ArrayList are all different.
I hope this answer was timely enough!

My quick sort algorithm in Java doesn't work properly

this is my quick sort code on Java. I've tried this code for 3 different types of lists;
Random list
Sorted List
Reversed sorted list
It's working for only sorted list, but for sorted list it prints;
1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 66, 68, 64, 69, 62, 70, 60, 71, 58, 72, 56, 73, 54, 74, 52, 75, 50, 76, 48, 77, 46, 78, 44, 79, 42, 80, 40, 81, 38, 82, 36, 83, 34, 84, 32, 85, 30, 86, 28, 87, 26, 88, 24, 89, 22, 90, 20, 91, 18, 92, 16, 93, 14, 94, 12, 95, 10, 96, 8, 97, 6, 98, 4, 99, 2, 100
For the random list it changes.
I couldn't solve that problem, can anyone help?
Thanks in advance.
class QuickSort {
public int Partition(int[] numbers, int left, int right){
int pivot = numbers[left];
while (true)
{
while (numbers[left] < pivot)
left++;
while (numbers[right] > pivot)
right--;
if (left < right)
{
int temp = numbers[right];
numbers[right] = numbers[left];
numbers[left] = temp;
left++;
right--;
}
else
{
return right;
}
}
}
public void QuickSort(int[] arr, int left, int right){
// For Recusrion
if(left < right)
{
int pivot = Partition(arr, left, right);
if(pivot > 1)
QuickSort(arr, left, pivot - 1);
if(pivot + 1 < right)
QuickSort(arr, pivot + 1, right);
}
}
////////////////////////////////////////////////////////////
public void printArray(int[] arr){
for (int i = 0; i < arr.length; i++){
if (i==arr.length-1)
System.out.print(arr[i]);
else
System.out.print(arr[i]+", ");
}
System.out.println();
}
public int[] fillArraySorted(int len){
int[] result=new int[len];
int counter = 1;
for(int i=0; i<len; i++){
result[i]=counter;
counter++;
}
return result;
}
public int[] fillArrayRan(int len){
int[] result=new int[len];
Random r = new Random();
for(int i=0; i<len; i++){
result[i]=r.nextInt(100)+1;
}
return result;
}
public int[] fillArraySortedReversed(int len){
int[] result=new int[len];
int counter = len;
for(int i=0; i<len; i++){
result[i]=counter;
counter--;
}
return result;
}
}
}

Problem with Divide and Conquer Maximum Consecutive Subarray (MCS)

I want to find a nonempty, contiguous subarray for a given input array of integers, that can have duplicate values. I tried the divide and conquer method to find the maximum consecutive subarray of an array, which returns a different result as expected. Please find the code below.
private static int maxSumRec(int[] a, int low, int high) {
int leftSum = 0, rightSum = 0;
int sum = 0;
if (low == high) { // Base case
return a[low];
}
int mid = (low + high) >> 1; // (low + high) / 2
int maxLeftSum = maxSumRec(a, low, mid);
int maxRightSum = maxSumRec(a, mid + 1, high);
//max-crossing-subarray
for (int i = mid; i >= low; i--) {
sum += a[i];
if (sum > leftSum) {
leftSum = sum;
}
}
sum = 0;
for (int i = mid + 1; i <= high; i++) {
sum += a[i];
if (sum > rightSum) {
rightSum = sum;
}
}
return max3(maxLeftSum, maxRightSum, (leftSum + rightSum));
}
private static int max3(int a, int b, int c) {
return a > b ? (a > c ? a : c) : (b > c ? b : c);
}
public static void main(String[] args) {
//INPUT
int a[] = {
-5, 71, 23, 41, 34, 1, 3, 6, 2, 91, 312, 42, 31, 67, 12, 10, 18, 56, 90, 21, 45, 47, 89, 1999999990,
78, -7, 76, 75, 74, 73, 72, 80, 24, 25, 61, 69, 84, 0, -1, 145, 1902, 200, 199, 198, 197, 196, 195, 194,
78, 77, 76, 75, 74, 73, 72, 80, 24, 25, 61, 69, 84, 0, -1, 145, 1902, 200, 199, 198, 197, 196, 195, 194,
5, 71, 23, 41, 34, 1, 3, 6, 2, 91, 312, 42, 31, 67, 12, 10, 18, 56, 90, 21, 45, 47, 89, 1999999990
};
int maxSum = maxSumRec(a, 0, a.length - 1);
System.out.println("Max sum is " + maxSum);
}
This code returns the result as 2000005400. The non recursive version of MCS returns a different result i.e. 2000010721 and its found from {1-94}.
I'm unable to figure out the reason. Please let me know if there's a bug in the code.
The sum from 1 to 95 (it's :4000010711 ) is actually greater than the one from 1 to 94.
Your ints are too long.
You need to use long to get the right result.
Note:
int are between -2147483648 and 2147483647
int test=2147483647;
System.out.println(test);
System.out.println(test+1);
you will get:
2147483647
-2147483648
Try this :
public class Sample5 {
private static long maxSumRec(int[] a, int low, int high) {
long leftSum = 0, rightSum = 0;
long sum = 0;
if (low == high) { // Base case
return a[low];
}
int mid = (low + high)/2; // (low + high) / 2
long maxLeftSum = maxSumRec(a, low, mid);
long maxRightSum = maxSumRec(a, mid + 1, high);
//max-crossing-subarray
for (int i = mid; i >= low; i--) {
sum += a[i];
if (sum > leftSum) {
leftSum = sum;
}
}
sum = 0;
for (int i = mid + 1; i <= high; i++) {
sum += a[i];
if (sum > rightSum) {
rightSum = sum;
}
}
System.out.println("final left sum "+leftSum);
System.out.println("final right sum "+rightSum);
System.out.println("leftSum+rightSUM:"+(leftSum + rightSum));
return max3(maxLeftSum, maxRightSum, (leftSum + rightSum));
}
private static long max3(long a, long b, long c) {
return a > b ? (a > c ? a : c) : (b > c ? b : c);
}
private static int sum(int[] a,int i,int j){
int r=0;
for(int k=i;k<=j;k++){
r+=a[k];
}
return r;
}
public static void main(String[] args) {
//INPUT
int a[] = {
-5, 71, 23, 41, 34, 1, 3, 6, 2, 91, 312, 42, 31, 67, 12, 10, 18, 56, 90, 21, 45, 47, 89, 1999999990,
78, -7, 76, 75, 74, 73, 72, 80, 24, 25, 61, 69, 84, 0, -1, 145, 1902, 200, 199, 198, 197, 196, 195, 194,
78, 77, 76, 75, 74, 73, 72, 80, 24, 25, 61, 69, 84, 0, -1, 145, 1902, 200, 199, 198, 197, 196, 195, 194,
5, 71, 23, 41, 34, 1, 3, 6, 2, 91, 312, 42, 31, 67, 12, 10, 18, 56, 90, 21, 45, 47, 89, 1999999990
};
long maxSum = maxSumRec(a, 0, a.length-1);
System.out.println("Max sum is " + maxSum);
//WITH INTS
System.out.println("with ints, the sum 1 to 94 is " + sum(a,1,94));
System.out.println("with ints, the sum 1 to 95 is " + sum(a,1,95));
}
}
You will get :
final left sum 2000005311
final right sum 2000005400
leftSum+rightSUM:4000010711
Max sum is 4000010711
with ints, the sum 1 to 94 is 2000010721
with ints, the sum 1 to 95 is -294956585
dont have enough points to add a comment so created an answer for a quick comment:
Ricky's answer works most of the time but for array such as [-2,-1] it won't work. simply add:
leftSum = a[mid];rightSum = a[mid+1];
somewhere before you use them and it'll do the trick.

Categories