Unsorted didgit in Insertion Sort Algorithm - java

// this describes the insertion sort algorithm
public class InsertionSort {
public static void main(String[] args) {
//array of unsorted integers
int [] array = { 10, 4, 1, 11, 5, 3, 8, 2, 0, 9};
int n = array.length;
for ( int j = 1; j<n; j++) {
//assign a value to the second element in the array
int key = array[j];
//assign a value to the 1st element in the list
int i = j-1;
//loop executes as long as i>0 and that the element befor the key is greater than the key itself
while( i>0 && array[i]>key) {
//move the bigger element 1 block forward
array[i+1] = array[i];
// keep moving until the element is in the right position
i =i-1;
}
array[i+1] = key;//assign the key to the appropritae location
}
for (int i=0; i<n; i++)
System.out.print(array[i] + " ");
System.out.println();
}
}
this is the ouput, As you can see, everything is sorted besides 10, which is still out of place in the array
10 0 1 2 3 4 5 8 9 11

This line has a problem:
while( i>0 && array[i]>key) {
The first iteration, j equals 1 and so i equals 0. And your loop doesn't run, because 0 is not greater than zero. But it should run, so the condition needs to change to "greater than or equals zero":
while( i>=0 && array[i]>key) {
That will fix your sort.

Related

Find the pair (i,j) such that i<j and and (a[i] + a[j]) is maximum

Given an unsorted array – arr find a pair arr[i] and arr[j] such that
arr[i] < arr[j] & i<j and (arr[i] + arr[j]) is maximum.
Expected time complexity – O(n)
For array a = {4, 1, 3, 2, 5, 3}
pair is (4, 5).
Here is the code I've tried..
void findPair(int[] a){
int n = a.length;
int max = a[0];
int secondMax = Integer.MIN_VALUE;
for(int i=1; i<n; i++){
if(a[i]>max){
secondMax = max;
max = a[i];
}
}
if(secondMax == Integer.MIN_VALUE){
System.out.println("-1 -1");
}
else{
System.out.println(secondMax+" "+max);
}
}
Here's a solution using a stack. The idea is that the stack always contains a descending sequence, such that for each number you look at, it can be paired with the largest number in the stack lower than it.
It's safe to pop the numbers off as you use them, because e.g. if you have a 6 and the top of the stack is 3, there is no need to keep the 3 around in case it can be paired with a bigger number; if there's a 7 later, you would wait to pair it with the 6 instead of the 3.
public void solution(int[] arr) {
Stack<Integer> stack = new Stack<>();
int bestX = -1, bestY = -1, bestSum = -1;
for(int y : arr) {
while(!stack.isEmpty() && stack.peek() < y) {
int x = stack.pop();
if(x + y > bestSum) { bestX = x; bestY = y; bestSum = x + y; }
}
stack.push(y);
}
System.out.println(bestX + " " + bestY);
}
The time complexity is O(n) despite the nested loop, because the inner loop always pops from the stack, and each element is only pushed once so it can only be popped once.
I thought about your question a lot and I think I found an acceptable solution.
You should split the array into subarrays starting from the end of the array (right side). Building the sub arrays is in iterative manner. You start with the right-most number and you add to the subarray all the numbers before him that are lower than him. The iteration goes to the next subarray when you reach a number which is bigger/equal to the right-most number in the subarray.
Example:
Your array is: {1,7,3,4,5,4,6,2}
Output should be: (5,6)
The splitting should be:
{{1, 7}, {3, 4, 5, 4, 6}, {2}}
<--(3) <--(2) <--(1)
You start from the last index with the value of 2. The number before him is 6 so that's the end of the first subarray. Next you start with 6, all the numbers before him until 7 are lower than 6 so you add them to that subarray. The last subarray starts with 7 and adds 1. See arrows for clarification.
Next, check within each subarray which number from left to the right-most number is max and mark it for possible pair with the right-most number.
In our example it would be: (1,7), (5,6).
There are only two options because {2} has only 1 variable. In the subarray with 6 as right-most the max number is 5 and in the subarray with 7 as right-most 1 is the only other number so it is also the max.
If no pair is found, return "no possible pair found".
Finally, check sum and return biggest pair: (5,6)
1+7 = 8 < 5+6 = 11
Why is this O(n) ?
You scan the array once for splitting: O(n)
Each subarray of size d you scan for max value: O(d)
Sum of all subarrays scanning: O(n)
Total: O(n)
I'm not strong in Java so my code can be written in Python and the conversion should be easy (because Python is easy!). If you wish for Python code, let me know and I'll write some for you. Also, I can explain more why this algorithm works (If not fully understood).
DISCLAIMER: Solution is O(n^2), not O(n) as required by the OP
What about using 2 nested loops:
i from 0 to a.length
j from i+1 to a.length
This ensures that i<j
Then have an if to ensure that a[i]<a[j] and find the max
int currentMax = -1;
int foundI = -1;
int foundJ = -1;
for(int i=0; i<a.length; i++) {
for(int j=i+1; j<a.length; j++) {
if(a[i] < a[j] && a[i] + a[j] > currentMax) {
currentMax = a[i] + a[j];
foundI = i;
foundJ = j;
}
}
}
Output:
System.out.println("i:" + foundI);
System.out.println("j:" + foundJ);
System.out.println("a[i]:" + a[foundI]);
System.out.println("a[j]:" + a[foundJ]);
System.out.println("sum:" + currentMax);
i:0
j:4
a[i]:4
a[j]:5
sum:9

Why is there a difference between two similar implementations of a 'for' loop?

I'm trying to write an insertion sort method, and I have managed to finish it, but I don't understand why my first version cannot work correctly.
Here's my first attempt:
public static void insertionSort(int[] list) {
for (int i = 1; i < list.length; i++) {
int current = list[i];
for (int k = i - 1; k >= 0 && current < list[k]; k--) {
list[i] = list[k];
list[k] = current;
}
}
}
public static void main(String[] args) {
int[] list = {8, 22, 90, 10};
insertionSort(list);
}
My output for the above code is: 8, 10, 10, 22
But the answer would be correct if the inside for-loop, at line 5, is changed from: list[i] = list[k]; to: list[k + 1] = list[k];
To my understanding, k + 1 is equal to i, but it must be different in loop counting and I can't figure out how. I have tried many sets of input, and only values that lie between the range of the 2 first indexes (in this case 8 and 22) would be incorrect.
k + 1 is equal to i, but only in the first iteration of the inner for loop. int k = i - 1 is only run once per iteration of the outer for loop.
In the second iteration of the inner for loop, k is decremented but i is not. Therefore, k + 1 and i are not interchangeable inside the inner for loop.
// second iteration of the outer for loop, second iteration of the inner for loop:
list[i] = list[k]; // means "list[2] = list[0]
// whereas
list[k + 1] = list[k]; // means "list[1] = list[0]"

How to check if the numbers are in sequence in LinkedList

I need to check if the numbers I stored in my LinkedList are in sequence.
Example sets are: 123, 124, 125, 1900, 1901.
If the code encounters the 123, it checks for the next which is 124 until 125 then stops since 1900 is not the next number after 125 when you are naturally counting. So I need to get the indexes of the first(123) and last sequence(125). Then on to the next sequence, 1900 and 1901.
for(int o = 0; o < zeroIndex.size(); o++)
{
if(-1 == (zeroIndex.get(o) - zeroIndex.get(o+1)))
{
System.out.println(zeroIndex.get(o) + "trailing");
}
}
String serialIndex = "";
for(int o = 1; o < zeroIndex.size(); o++)
{serialIndex += "("+Integer.toString(o-1);
while(i<zeroIndex.size() && zeroIndex.get(o-1)+1 == zeroIndex.get(o))
{ i++;
//System.out.println(zeroIndex.get(o) + "trailing");
}
serialIndex = serialIndex+Integer.toString(i-1)+"),";
}
System.out.println(serialIndex);
We will loop to the linked list and check if the previous is one less than current value.If this condition is true we will increment i else we will break will loop and add that i to ans
for example
123, 124, 125, 1900, 1901.
we will start from
124 ----- our serialIndex string will be (0 and 124 is one greater than 123 so we increment i. when we reach 1900 we will break the while loop as 1900 is not 1 greater than 125 and now our serialIndex string will b (0,2).
In the end we will have serialIndex string as (0,2),(3,4)
I do not have your full code to test so this is best i can do.If you encounter any error please let me know.
This works with O(n)
import java.util.LinkedList;
public class TestLinkedList {
public static void main(String[] args) {
LinkedList<Integer> a = new LinkedList<Integer>();
a.add(124);
a.add(125);
a.add(126);
a.add(1900);
a.add(1901);
int index = 0;
int index1 = 0;
for (int i = 0; i < a.size(); i++) {
if (i+1 < a.size() && a.get(i) + 1 == a.get(i + 1)) {
index1 = i + 1;
} else {
if (index != index1) {
System.out.println(index + " " + index1);
}
index = i+1;
index1 = i+1;
}
}
}
}
output
0 2
3 4
Here is a quick example on how to do it. First, create our list.
List<Integer> a = new LinkedList<Integer>();
a.add(124);
a.add(125);
a.add(126);
a.add(1900);
a.add(1901);
So, now that we have a list, let start. First, declaring our variables
int current; //will hold the current value during the iteration
int indexStart = 0; //the index of the beginning of the current sequence
int previous = a.get(0); //the previous value
int length = a.size(); //the length (optionnal, but this will be used later)
Then, here come the funny par (fully commented)
//Iterate from 1 to the end (0 is already in `previous`
for(int i = 1 ; i < length; ++i){
//get the current value
current = a.get(i);
//if the sequence is broken, print the index and print also the sublist using `List.subList`.
if(current != previous + 1){
System.out.format("Sequence from %d to %d%n", indexStart, i - 1);
System.out.println(a.subList(indexStart, i));
//reset the start of the current sequence
indexStart = i;
}
//update the previous value with the current for the next iteration.
previous = current;
}
//Print the last sequence.
System.out.format("Sequence from %d to %d%n", indexStart, length - 1);
System.out.println(a.subList(indexStart, length));
This will print :
Sequence from 0 to 2
[124, 125, 126]
Sequence from 3 to 4
[1900, 1901]
This is quite simple, just iterate the loop and keep the previous and current value to be able check if the sequence is correct or not.
Note that with a LinkedList, I would have used an Iterator but I need an int index so this would have give a longer solution, so to keep this simple, I used List.get.

Exception in thread java.lang.ArrayIndexOutOfBoundsException: 5

I'm a newbie who is trying to complete the below tutorial
// Create a method called countEvens
// Return the number of even ints in the given array.
// Note: the % "mod" operator computes the remainder, e.g. 5 % 2 is 1.
/*
* SAMPLE OUTPUT:
*
* 3
* 0
* 2
*
*/
Below is my code
public static void main(String[] args) {
int a[] = {2, 1, 2, 3, 4};
countEvens(a); // -> 3
int b[] = {2, 2, 0};
countEvens(b); // -> 3
int c[] = { 1, 3, 5};
countEvens(c); // -> 0
}
public static void countEvens(int[] x){
int i = 1;
int count = 0;
while ( i <= x.length){
if (x[i] % 2 == 0){
count ++;
}
i ++;
}
System.out.println(count);
}
The code can be run, but I get the below error message
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
at apollo.exercises.ch05_conditionals.Ex5_CountEvens.countEvens(Ex5_CountEvens.java:23)
at apollo.exercises.ch05_conditionals.Ex5_CountEvens.main(Ex5_CountEvens.java:10)
May I know what I'm doing wrong here?
The line
while ( i <= x.length)
should be
while ( i < x.length)
If the length of xis 5, for example, the indices are 0, 1, 2, 3 and 4. The index goes from 0 up to one less than the length of the array.
However the tidiest way to do this is to use a for each loop rather than a while loop:
public static void countEvens(int[] x) {
int count = 0;
for (int number : x)
if (number % 2 == 0)
count++;
System.out.println(count);
}
'i' should go from 0 to length()-1, because array indices start at 0, and the index of the last element is length()-1.
Therefore, a correct version of your code would be:
public static void countEvens(int[] x){
int i = 0;
int count = 0;
while ( i < x.length){
if (x[i] % 2 == 0){
count ++;
}
i ++;
}
System.out.println(count);
}
For your specific purpose, a for loop would be simpler.
for(int i = 0; i< x.length(); i++){
if(x[i]%2==0){
count++;
}
}
At while ( i <= x.length), you're looping until i is equal to the length of x. The last index of an array is always length - 1, so change the less-than-or-equals (<=) to just less-than (<). Also, initialize i to 0, as Java arrays are zero-based.
Arrays in Java (and most other languages) are indexed starting at 0. However the length of an array is the count of the elements in the array. So for your array a[]
int a[] = {2,1,2,3,4};
The index goes up to 4, whereas the length is 5.
You are getting an index out of bounds error because you are iterating through the array from 1~5 because of the <= (less than equal to) operator, but the indices of the array are 0~4. When you access each element of the array you should use
if (x[i-1] % 2 == 0) //iterates from 0~4 rather than 1~5
otherwise you can set the iterator int i = 0; and use the less than < operator to ensure the iterator moves 0~4

Quicksort ArrayList<MyObject> with multiple of the same Values (myObject.getId()) isn't sorting completely

I've got a quicksort algorithm to sort my ArrayLists. Since I'm working with ArrayLists instead of Arrays, I had to modify / add some parts of code compared to the traditional way.
Everything works as intended except for one small thing: The ArrayList isn't sorted correctly when I have multiple Objects with the same sorting-Value.
So, first of all, here is my code:
public class Sort
{
... // Other sorting classes that always have an unique sorting-value anyway, so are working fine
// The following sorting class can have double sorting-values, and here the sorting goes wrong
public static class OPI{
public static ArrayList<OrderedProductItem> opisByProductId;
public static void sortOrderedProductItems(ArrayList<OrderedProductItem> orderedProductItems){
opisByProductId = new ArrayList<OrderedProductItem>();
if(orderedProductItems != null && orderedProductItems.size() > 0){
// Since Java automatically creates a pointer behind the scenes,
// we need to make a new ArrayList and fill them with the values
for(OrderedProductItem opi : orderedProductItems)
opisByProductId.add(opi);
quicksortOpisByProductId(0, opisByProductId.size() - 1);
}
}
private static void quicksortOpisByProductId(int low, int high){
int i = low, j = high;
// Get the middle element from the middle of the list
int middle = opisByProductId.get(low + (high - low) / 2).getProductId();
// Divide into two lists
while(i <= j){
// If the current value from the left list is smaller than the middle
// element, then get the next element from the left list
while(opisByProductId.get(i).getProductId() < middle){
i++;
if(i > j){
i = j;
break;
}
}
// If the current value from the right list is larger than the middle
// element, then get the next element from the right list
while(opisByProductId.get(j).getProductId() > middle){
j--;
if(j < i){
j = i;
break;
}
}
// If we have found a value in the left list which is larger than
// the middle element and if we have found a value in the right list
// which is smaller than the middle element, then we exchange the values
// PS: It might happen that the same values swap places
if(i < j){
OrderedProductItem temp = opisByProductId.get(i);
opisByProductId.set(i, opisByProductId.get(j));
opisByProductId.set(j, temp);
}
if(i <= j){
i++;
j--;
}
}
// Recursion
if(low < j)
quicksortOpisByProductId(low, j);
if(i < high)
quicksortOpisByProductId(i, high);
}
}
}
Example List:
Before the sorting algorithm:
position ProductId
0 12
1 12
2 54
3 54
4 12
5 4
6 4
7 4
After the sorting algorithm:
position ProductId
0 4
1 4
2 12
3 12
4 12
5 4
6 54
7 54
Ok i Debugged your program and here what i found
Your High keeps going down never returned upward.
if(low < j)
quicksortOpisByProductId(low, j);
if(i < high)
quicksortOpisByProductId(i, high);
I changed this to
if(low < j)
quicksortOpisByProductId(low, j);
if(i < high)
quicksortOpisByProductId(i, opisByProductId.size() - 1);
And it works
Untouched your program changed the array 7 times
With this added it loops an additional 3 times taking it up to 10 times.
Sorting Visualization
Ok, I figured out my mistake. In the while-loops I had
// If the current value from the left list is smaller than the middle
// element, then get the next element from the left list
while(opisByProductId.get(i).getProductId() < middle){
i++;
if(i > j){
i = j;
break;
}
}
// If the current value from the right list is larger than the middle
// element, then get the next element from the right list
while(opisByProductId.get(j).getProductId() > middle){
j--;
if(j < i){
j = i;
break;
}
}
Where I use the j and i in the if-statement. Instead I now use the following, fixing my issue:
// If the current value from the left list is smaller than the middle
// element, then get the next element from the left list
while(opisByProductId.get(i).getProductId() < middle){
i++;
if(i > high){ // <- high instead of j
i = high; // <- high instead of j
break;
}
}
// If the current value from the right list is larger than the middle
// element, then get the next element from the right list
while(opisByProductId.get(j).getProductId() > middle){
j--;
if(j < low){ // <- low instead of i
j = low; // <- low instead of i
break;
}
}
EDIT:
Created a UnitTest with #DaveP's test-data and it succeeded:
package business;
import java.util.ArrayList;
import junit.framework.Assert;
import org.junit.Test;
import viewmodels.OrderedProductItem;
public class SUnitTest
{
... // Other UnitTests
#Test
public void testDoubleSorting(){
// Arrange
// Could be with any of them, but we do it with the OrderedProductItems,
// since they can contain doubles
ArrayList<OrderedProductItem> opis = new ArrayList<OrderedProductItem>();
int[] unsortedIds = new int[]{
12, 12, 54, 54, 12, 4, 4, 4, 7, 76, 45, 44, 1, 2, 34, 5, 4
};
// Sorted array of the exact same ID's for comparison
int[] sortedIds = new int[]{
1, 2, 4, 4, 4, 4, 5, 7, 12, 12, 12, 34, 44, 45, 54, 54, 76
};
for(int i = 0; i < unsortedIds.length; i++)
// OrderedProductItem uses setProductId in its Constructor
opis.add(new OrderedProductItem(unsortedIds[i]));
// Invoke
Sort.OPI.sortOrderedProductItems(opis);
ArrayList<OrderedProductItem> resultOpis = Sort.OPI.opisByProductId;
// Assert
Assert.assertNotNull("resultOpis should not be null", resultOpis);
Assert.assertEquals("resultOpis' size should equal the unsortedIds' size", unsortedIds.length, resultOpis.size());
for(int i = 0; i < sortedIds.length; i++){
Assert.assertNotNull("The OrderedProductItem at " + String.valueOf(i) + " should not be null", resultOpis.get(i));
Assert.assertEquals("The OrderedProductItem's ProductId at " + String.valueOf(i) + " should be " + String.valueOf(sortedIds[i]), sortedIds[i], resultOpis.get(i).getProductId());
}
}
}

Categories

Resources