public static void insertionSort(int[] a) {
for(int i = 1; i < a.length; i++) {
int minVal = a[i];
int checkIdx = i-1;
while(checkIdx >= 0 && minVal < a[checkIdx]) {
a[checkIdx + 1] = a[checkIdx];
checkIdx--;
}
a[checkIdx + 1] = minVal;
}
}
This is my solution for insertion sort iteratively, but what I want is to transform this code recursively. I tried but I got stuck myself in one part.
public static void insertionSort(int[] arr, int i, int n)
{
int value = arr[i];
int j = i;
// Find index j within the sorted subset arr[0..i-1]
// where element arr[i] belongs
while (j > 0 && arr[j - 1] > value)
{
arr[j] = arr[j - 1];
j--;
}
arr[j] = value;
// Note that subarray arr[j..i-1] is shifted to
// the right by one position i.e. arr[j+1..i]
if (i + 1 <= n) {
insertionSort(arr, i + 1, n);
}
}
I got stuck myself in the while loop part, how can I convert it to recursively??
You are almost there. Only one thing.
You need to break out of recursion at some point. That will be the condition when the array is sorted and i+1 == n.
Very slightly edited code. The original array is {4,2,7,8,1,9,3,5,6,0} which is finally sorted.
public class insertionSort_Edited {
public static int[] insertionSort (int[] arr, int i, int n){
int value = arr[i];
int j = i;
// Find index j within the sorted subset arr[0..i-1]
// where element arr[i] belongs
while (j > 0 && arr[j - 1] > value)
{
arr[j] = arr[j - 1];
j--;
}
arr[j] = value;
// Note that subarray arr[j..i-1] is shifted to
// the right by one position i.e. arr[j+1..i]
if (i + 1 < n ) {
insertionSort(arr, i + 1, n);
}
return arr;
}
public static void main(String[] args) {
int[] MyArray= new int[]{4,2,7,8,1,9,3,5,6,0};
MyArray = insertionSort(MyArray, 0, 10);
for(int i=0;i<MyArray.length;i++){
System.out.println(MyArray[i]);
}
}
}
Gives the following output.
0
1
2
3
4
5
6
7
8
9
Ok so I have solved it, thx for helping me.
public static void swap(int[] a, int i, int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
public static void check(int[] array, int i) {
if (i == 0) {
return;
}
if (array[i] >= array[i - 1]) {
return;
}
swap(array, i, i - 1);
check(array, i - 1);
}
public static void recurInsertionSort(int[] a, int minPos, int last) {
check(a,minPos);
if(minPos + 1 <= last) {
recurInsertionSort(a,minPos + 1, last);
}
}
Related
This problem was asked in my algorithm course homework.
You have an n sized, sorted array at first. Lets say n=10 and the array is [1,2,3,4,5,6,7,8,9,10]. Then it is circularly shifted to the right by k. Lets say k=3. Now the array is [8,9,10,1,2,3,4,5,6,7].
What is the time complexity if you apply insertion sort on this array, depending on n and k?
I researched this question a lot, but couldn't find a solution on the internet. How to determine the time complexity of insertion sort on such shifted array?
First of all, the insertion sort:
static void insertionSort(int[] array) {
for (int i = 1; i < array.length; i++) {
int key = array[i];
int j = i - 1;
while (j >= 0 && array[j] > key) {
array[j + 1] = array[j];
j--;
}
array[j + 1] = key;
}
}
The time complexity mostly depends on the following lines because that's where comparing and swapping operations are done.
while (j >= 0 && array[j] > key) {
array[j + 1] = array[j];
j--;
}
Take a paper, draw a swap table for each j value.
Eventually, you will understand that the algorithm gets into while loop (n-k) times, and whenever it gets in, it does swap operation k times. So, time complexity is (n-k)*k.
Lets prove it.
Put a swap counter variable to the algorithm.
static int insertionSort(int[] array) {
int swapCount = 0;
for (int i = 1; i < array.length; i++) {
int key = array[i];
int j = i - 1;
while (j >= 0 && array[j] > key) {
array[j + 1] = array[j];
j--;
swapCount++;
}
array[j + 1] = key;
}
return swapCount;
}
Now, lets try it on our array described in the question.
public class App {
public static void main(String[] args) throws Exception {
int[] baseArray = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int n = baseArray.length;
int k = 3;
// Shift base array by k
int[] shiftedArray = shiftArray(baseArray, k);
// Calculate how many swaps done by the insertion sort
int swapCount = InsertionSort.insertionSort(shiftedArray);
// Theroitical value is calculated by using the formula (n-k)*k
int timeComplexityTheoritical = (n - k) * k;
System.out.print("Theoritical Time Complexity based on formula: " + timeComplexityTheoritical);
System.out.print(" - Swap Count: " + swapCount);
System.out.print(" - Is formula correct:" + (timeComplexityTheoritical == swapCount) + "\n");
}
// Shift array to the right circularly by k positions
static int[] shiftArray(int[] array, int k) {
int[] resultArray = array.clone();
int temp, previous;
for (int i = 0; i < k; i++) {
previous = resultArray[array.length - 1];
for (int j = 0; j < resultArray.length; j++) {
temp = resultArray[j];
resultArray[j] = previous;
previous = temp;
}
}
return resultArray;
}
static class InsertionSort {
static int insertionSort(int[] array) {
int swapCount = 0;
for (int i = 1; i < array.length; i++) {
int key = array[i];
int j = i - 1;
while (j >= 0 && array[j] > key) {
array[j + 1] = array[j];
j--;
swapCount++;
}
array[j + 1] = key;
}
return swapCount;
}
}
}
The output:
Theoritical Time Complexity based on formula: 21 - Swap Count: 21 - Is
formula correct:true
I've tried on array sized 2^16 and shifted it 2^16-1 times, each time the formula was correct.
The time complexity we found is not an upper bound or lower bound, it is the exact tight bound for this case. Therefore it is Theta. Θ((n-k)k).
Logic used to solve the question
Maintain a count variable, two pointers i and j and scan them from left to right(i) and right to left(j).
Assign i the index of first element <= k.
If i and j stop at a particular position that means they need to be exchanged and update count.
Exit the loop when i and j cross each other.
Return no of exchanges happened ; that is return count.
Question
Can anybody help me find out why count returns wrong for some cases(like the one in unit testing where it returns 4 but correct output is 3)? What's the bug here?
public class MinSwaps {
public static int minSwap(int[] arr, int n, int k) {
int count = 0;
int lo = 0;
int hi = arr.length - 1;
int i = lo - 1;
int j = hi + 1;
// assign i the position of first element <= k in arr
for (int l = 0; l < n; l++) {
if (arr[l] <= k) {
i = l;
break;
}
}
while (true) {
// keep scanning i(from left to right) until arr[i] > k
while (arr[++i] <= k) {
if (i == hi) {
break;
}
}
// keep scanning j(right to left) until arr[j] <= k
while (arr[--j] > k) {
if (j == lo) {
break;
}
}
// exit loop if i and j cross each other
if (i >= j) {
break;
}
// exchange elements at i and j ( when they have stopped )
exch(arr, i, j);
count++;
}
return count;
}
private static void exch(int[] a, int i, int j) {
int temp;
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
// unit testing
public static void main(String[] args) {
int[] arr = {4, 16, 3, 8, 13, 2, 19, 4, 12, 2, 7, 17, 4, 19, 1};
StdOut.println(minSwap(arr, 15, 9));
}
}
I implemented a QuickSort Algorithm which only works for 7 elements and then gives a StackOverflow Error for 8 elements or more. Goes into an infinite loop. Works fine for the number of elements that are present in the array but if I add one more element, it returns a StackOverflow Error
Here is my code:
public class QuickSort
{
public void main()
{
QuickSort o = new QuickSort();
int arr[] = {8,5,2,10,1,7,3};
o.sort(arr,0,arr.length-1);
for(int i=0;i<arr.length;i++)
System.out.print(arr[i]+" ");
}
void sort(int []arr,int l,int h)
{
if(l<h)
{
int pi = partition(arr,l,h);
sort(arr,l,pi);
sort(arr,pi+1,h);
}
}
int partition(int arr[],int l,int h)
{
int pivot = arr[l];
int i=l,j=h;
while(i<j)
{
while(arr[i]<=pivot)
{
i++;
}
while(arr[j]>pivot)
{
j--;
}
if(i<j)
{
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
}
int t = arr[j];
arr[j] = pivot;
arr[l] = t;
return j;
}
}
I believe the problem is that you don't put the pivot in the right place.
Here is your code with a small change:
int partition(int arr[],int l,int h){
int pivot = arr[l];
int i= l,j=h;
while(i < j){
while( i < j && arr[i]<=pivot){ i++;}
while( i < j && arr[j]>pivot){ j--;}
if(i< j){
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
}
//here it is determined where the pivot should go. It is easiest to understand with an example
//after the loop arr can be 3 1 2 4 5
//the pivot being 3 should be switched with the number 2 but index j sometimes points to number 2 and sometimes to number 4
//the following code determines the desired index
int lowerInd = arr[j] <= pivot ? j : j - 1;
int t = arr[lowerInd];
arr[lowerInd] = arr[l];
arr[l] = t;
return lowerInd;
}
Also, in your sort method, call sort(arr,l,pi - 1); instead of sort(arr,l,pi);
void sort(int[] arr,int l,int h){
if(l<h){
int pi = partition(arr,l,h);
sort(arr,l,pi - 1);
sort(arr,pi+1,h);
}
}
I'm trying to understand recursion and how to turn my currently iterative insertion sort into a recursive one.
What would I need to do to my code to make it recursive?
I think I need a base case so it doesn't become an infinite loop.
I'm not sure I entirely understand recursion. Maybe you can make it clearer for me?
I've done a lot of reading but I still don't know where to start.
Here is my code:
public class InsertionSort
{
public static void main(String a[])
{
int i;
int array[] =
{ 8, 33, 12, 99, 0, 17 };
System.out.println("Values of Array before the sort: ");
for (i = 0; i < array.length; i++)
{
System.out.print(array[i] + " ");
}
insertion_srt(array, array.length);
System.out.println("");
System.out.println("Values of Array after the sort: ");
for (i = 0; i < array.length; i++)
{
System.out.print(array[i] + " ");
}
}
public static void insertion_srt(int array[], int n)
{
for (int i = 1; i < n; i++)
{
int j = i;
int B = array[i];
while ((j > 0) && (array[j - 1] > B))
{
array[j] = array[j - 1];
j--;
}
array[j] = B;
}
}
}
This is great approach I personally likes. It does use three methods but they're very simple to understand. Think of the insertionOut as the outer for loop and the insertionIn as the inner nested for loop
public static void insertionRecursive(int[] a){
if(a.length > 0){ // base case
insertionOut(a, 1, a.length);
}
}
private static void insertionOut(int[] a, int i, int length){ //outer loop
if(i < length){ // iterates from 1 to the length
int temp = a[i]; // temp value
int k = i;
insertionIn(a, k, temp);
insertionOut(a, i + 1, length); // iterates through the loop
}
}
private static void insertionIn(int[] a, int k, int temp){ // inner loop
if(k > 0 && a[k - 1] > temp){
//this does a basic swap
a[k] = temp;
a[k] = a[k - 1];
a[k - 1] = temp;
insertionIn(a, k - 1, temp); // iterates through the loop
}
}
Transforming the outer for loop is kind of trivial. To overcome the while loop you need a little recursive helper function. You have to call the function in your main as insertion_srt(array, 0, array.length):
public static void insertion_srt(int array[], int beg_index, int n) {
if(beg_index >= n-1)
return;
int i = beg_index + 1;
int j = i;
int B = array[i];
j=helper(array, j, B);
array[j] = B;
insertion_srt(array, beg_index + 1, n);
}
private static int helper(int[] array, int j, int B) {
if(j <= 0 || array[j-1] <= B)
return j;
array[j] = array[j - 1];
return helper(array, j-1, B);
}
A good way to understand how recursion works is to understand the concept of Divide and conquer algorithm. This technique is a basis of efficient algorithms for all kinds of problems.
The idea behind it is to divide a problem into smaller subproblems that can all be solved in the same way:
Divide into 2 (or more) subproblems.
Solve each subproblem recursively.
Combine the results.
Insertion sort is not the best example of a divide and conquer algorithm, but it can still be approached this way. You can divide the problem into 2 subproblems:
last element
everything else
This way you will obtain so called tail recursion. All loops are relatively easy to transform into tail recursions.
public static void insertion_srt(int array[], int n, int j) {
if (j < n) {
int i;
int temp = array[j];
for (i=j; i > 0 && array[i-1] > temp; i--) array[i] = array[i-1];
array[i] = temp;
insertion_srt(array,n, j+1);
}
}
Try this simple recursive approach:
public static void insertionSort(int[] array, int index) {
if(array.length == index + 1) return;
insertionSort(array, index + 1);
// insert array[index] into the array
}
So I am trying to make the following code into a recursive method, insertion sort, but for as much as I try I cannot. Can anyone help me?
public static void insertionSort(int[] array){
for (int i = 1; i < array.length; i++){
int j = i;
int B = array[i];
while ((j > 0) && (array[j-1] > B)){
array[j] = array[j-1];
j--;
}
array[j] = B;
}
}
EDIT:
I was thinking of something like this, but it doesn't look very recursive to me...
public static void insertionSort(int[] array, int index){
if(index < array.length){
int j = index;
int B = array[index];
while ((j > 0) && (array[j-1] > B)){
array[j] = array[j-1];
j--;
}
array[j] = B;
insertionSort(array, index + 1);
}
}
Try this:
public class RecursiveInsertionSort {
static int[] arr = {5, 2, 4, 6, 1, 3};
int maxIndex = arr.length;
public static void main(String[] args) {
print(arr);
new RecursiveInsertionSort().sort(arr.length);
}
/*
The sorting function uses 'index' instead of 'copying the array' in each
recursive call to conserve memory and improve efficiency.
*/
private int sort(int maxIndex) {
if (maxIndex <= 1) {
// at this point maxIndex points to the second element in the array.
return maxIndex;
}
maxIndex = sort(maxIndex - 1); // recursive call
// save a copy of the value in variable 'key'.
// This value will be placed in the correct position
// after the while loop below ends.
int key = arr[maxIndex];
int i = maxIndex - 1;
// compare value in 'key' with all the elements in array
// that come before the element key.
while ((i >= 0) && (arr[i] > key)) {
arr[i+1] = arr[i];
i--;
}
arr[i+1] = key;
print(arr);
return maxIndex + 1;
}
// code to print the array on the console.
private static void print(int[] arr) {
System.out.println();
for (int i : arr) {
System.out.print(i + ", ");
}
}
}
public static void insertionSort(int[] array, int index) {
if(array.length == index + 1) return;
insertionSort(array, index + 1);
// insert array[index] into the array
}
You can try this code. It works correctly.
public static int[] InsertionSort(int[] dizi, int n)
{
int i;
if (n < 1) {
InsertionSort(dizi, n - 1);
}
else {
int key = dizi[n];
i = n - 1;
while (i >= 0 && dizi[i] > key) {
dizi[i + 1] = dizi[i];
i = i - 1;
}
dizi[i + 1] = key;
}
return dizi;
}
for the recursion algorithm, we start with the whole array A[1..n], we sort A[1..n-1] and then insert A[n] into the correct position.
public int[] insertionSort(int[] array)
{
//base case
if(array.length==1) return new int[]{ array[0] };
//get array[0..n-1] and sort it
int[] arrayToSort = new int[array.length - 1]{ };
System.arraycopy(array, 0, arrayToSort, 0, array.length -1);
int[] B = insertionSort(arrayToSort);
//now, insert array[n] into its correct position
int[] C = merge(B, array[array.length - 1]);
return C;
}
private int[] merge(int[] array, int n)
{
int[] arrayToReturn = new int[array.length + 1] {};
int j = array.length-1;
while(j>=0 && n <= array[j])
{
arrayToReturn[j+1]=array[j;
j--;
}
arrayToReturn[j] =
}
Try below code by providing ele as an integer array, sortedIndex=index of first element and index=index of second element:
public static void insertionSort(int[] ele, int sortedIndex, int index) {
if (sortedIndex < ele.length) {
if (index < ele.length) {
if (ele[sortedIndex] > ele[index]) {
ele[sortedIndex] += ele[index];
ele[index] = ele[sortedIndex] - ele[index];
ele[sortedIndex] = ele[sortedIndex] - ele[index];
}
insertionSort(ele, sortedIndex, index + 1);
return;
}
if (index == ele.length) {
sortedIndex++;
}
insertionSort(ele, sortedIndex, sortedIndex + 1);
}
}
public static void sort(int[] A, int p, int r) {
if (p < r) {
int q = r - 1;
sort(A, p, q);
combine(A, p, q, r);
}
}
private static void combine(int[] A, int p, int q, int r) {
int i = q - p;
int val = A[r];
while (i >= 0 && val < A[p + i]) {
A[p + i + 1] = A[p + i];
A[p + i] = val;
i--;
}
}
public static void main(String... strings) {
int[] A = { 2, 5, 3, 1, 7 };
sort(A, 0, A.length - 1);
Arrays.stream(A).sequential().forEach(i -> System.out.print(i + ", "));
}
public class test
{
public static void main(String[] args){
test h = new test();
int a[] = { 5, 8, 9, 13, 65, 74, 25, 44, 67, 2, 1 };
h.ins_rec(a, a.length-1);
for(int i=0; i<a.length; i++)
log(a[i]);
}
void ins_rec(int a[], int j){
if( j == 0 ) return;
ins_rec(a, j - 1);
int key = a[ j ];
sort(a, key, j - 1);
}
void sort(int a[], int key, int i){
if( (i < 0) || (a[i] < key) ) {
a[ i + 1 ] = key;
return;
}
a[ i + 1 ] = a[ i ];
sort(a, key, i - 1);
}
private static void log(int aMessage){
System.out.println("\t\t"+aMessage);
}
}