Time complexity of insertion sort on k-shifted array - java

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).

Related

Parallel sort and array sort not giving equal output

I am trying to insertion-sort (some modification) an array using threads. My problem is that sometimes after I sort, I get that para_array and arraysort are equal, sometimes not. The checking where the numbers are not equal I get something like this:
99940 and 99941
99938 and 99940
99935 and 99938
99934 and 99935
99932 and 99934
where para_array has the left values and arraysort has the right
I fill both the array before sorting with random(7363), one random for each so they have the same values.
I have to sort the k first numbers of the array, so what I do is I serially sort the k first like this:
//sort the k first wher 0 is largest number and k-1 is lowest
for (int i = 1; i < k; i++) {
int check = para_array[i];
int prev = i - 1;
while (prev >= 0 && para_array[prev] < check) {
para_array[prev + 1] = para_array[prev];
previous_element--;
}
para_array[prev + 1] = check;
}
I then start the threads. I have a list of threads to run:
for (Thread t : threads) {
t.start();
}
My thread:
public SortingThread(int[] arr, int start, int end, int k, Object lock) {
this.arr = arr;
this.start = start;
this.end = end;
this.k = k;
this.lock = lock;
}
#Override
public void run() {
for (int i = start; i < end; i++) {
//whill try to find a larger value in its own segment than k-2 if found sort it
synchronized (lock) {
if (arr[i] > arr[k - 1]) {
int set_correct = arr[i];
int j = k - 2;
while (j >= 0 && arr[j] < set_correct) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = set_correct;
}
}
}
}
The threads are created like this:
// Create and start all the threads
for (int i = 0; i < number_of_cores; i++) {
int start = i * portionSize;
int end = Math.min((i + 1) * portionSize, n);
threads.add(new SortingThread(para_array, start, end, k,locks.get(i)));
}
I then sort the other array with array.sort() and make it in decreasing order, then I check the k first values for both.

Algorithm to generate an array with n length and k number of inversions in O(n log n) time?

I'm writing an algorithm that will return an array with determined length and number of inversions (number pairs, where the left side number is larger than the right side number). I.e. array [3, 1, 4, 2] contains three inversions (3, 1), (3, 2) and (4, 2). So in practice, when given the length of n=3 and number of inversions k=3, the algorithm should generate an array [3, 1, 4, 2] (or another array that fulfills these requirements).
Since the number of inversions is also the number of swaps that has to be made for the array to be sorted in ascending order, I approached this problem by creating an array from 1 to n - 1 and using an insertion sort algorithm in reverse to make k swaps.
This approach works just fine for smaller inputs, but the algorithm should be able to efficiently generate arrays up to n=10^6 and k=n(n-1)/2 and anything in between, so the algorithm should be working in O(n log n) time instead of O(n^2). Below is the code:
import java.util.*;
public class Inversions {
public int[] generate(int n, long k) {
// Don't mind these special cases
if (n == 1) {
int[] arr = {1};
return arr;
}
if (k == 0) {
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = 1;
}
return arr;
}
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = i + 1;
}
int inversions = 0;
int i = 0;
while (inversions < k && i < n) {
int j = i - 1;
while (j >= 0 && arr[j] < arr[j + 1] && inversions < k) {
int helper = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = helper;
inversions++;
j--;
}
i++;
}
return arr;
}
}
And the main class for testing with different input arrays:
public class Main {
public static void main(String[] args) {
Inversions in = new Inversions();
int[] arr1 = in.generate(4,3);
int[] arr2 = in.generate(4,0);
int[] arr3 = in.generate(4,6);
System.out.println(Arrays.toString(arr1)); // [3,1,4,2]
System.out.println(Arrays.toString(arr2)); // [1,1,1,1]
System.out.println(Arrays.toString(arr3)); // [4,3,2,1]
}
}
The algorithm does not return exactly the same arrays as the sample results, but passes all the tests, except the ones where the input size is very large. I have also tried different variations with merge sort, since it's working in O(n log n time) but with no avail.
It would be great if you guys have some ideas. If you are not familiar with Java, doesn't matter, pseudocode or any other kinds of suggestions are more than welcome!
If you reverse the initial m elements in the array, you create m(m-1)/2 inversions.
If you reverse the initial m+1 elements, you create m(m+1)/2 inversions.
The difference between these is only m.
So:
Generate a sorted array
Find the largest m such that m(m-1)/2 <= k
Reverse the first m elements in the array to create m(m-1)/2 inversions
Shift the next element forward k - m(m-1)/2 positions to create the remaining required inversions.
This takes O(n) time, which is better than you require.
Another O(n) algorithm: Start with a sorted array. When you swap the first and last elements, you get x = 2 * (n-2) + 1 inversions. Consider these two elements fixed and work on the remaining array only. If x is too large, consider a smaller array. Repeat this as long as needed.
Untested code:
for (int first=0, last = n-1; remainingInversions>0; ) {
int x = 2 * (last-first-1) + 1;
if (x <= remainingInversion) {
first++;
last--;
remainingInversion -= x;
} else {
last--; // consider a smaller array
}
}
If k >= n - 1, put element n - 1 first in the array, so that it is inverted with n - 1 elements; otherwise put it last in the array, so that it is inverted with 0 elements. Continue this greedy approach to determine where the rest of the elements go.
Here's a solution that implements generate() to run in linear time with a little bit of math.
public class Inversions {
public static int[] generate(int n, long k) {
int[] array = new int[n];
// locate k in various sums of (n-1), (n-2), ..., 1
int a = (int) Math.sqrt((n * (n - 1) - 2 * k)); // between the sum of [(n-1)+...+(n-a)] and the sum of [(n-1)+...+(n-a-1)]
int b = n - 1 - a; // counts of (n-1), (n-2), ..., (n-a)
int c = (int) (k - n * b + (b * b + b) / 2); // spillover = k - [(n-1)+(n-b)]*b/2;
// put elements in the array
for (int i = 0; i < b; i++) {
array[i] = n - 1 - i;
}
for (int i = b; i < n - 1 - c; i++) {
array[i] = i - b;
}
array[n - 1 - c] = n - 1 - b;
for (int i = n - c; i < n; i++) {
array[i] = i - b - 1;
}
return array;
}
public static void main(String[] args) {
int n = Integer.parseInt(args[0]);
long k = Long.parseLong(args[1]);
for (int i = 0; i < n; i++) {
StdOut.print(generate(n, k)[i] + " ");
}
}
}
In fact, every time you exchange the last element with the one before it, the number of inversions increments. Here is a java solution:
public static int[] generate(int n, long k) {
int[] arr = new int[n];
for(int i = 0; i < n; i++) {
arr[i] = i;
}
long inversions = 0;
int j = (n-1);
int s = 0;
while(inversions < k) {
int temp = arr[j];
arr[j] = arr[j-1];
arr[j-1] = temp;
inversions++;
j--;
if(j == s) {
j = (n-1);
s++;
}
}
return arr;
}
I got an implementation in Python with O(n) complexity.
It is based on two rules.
Reversing an array of size m gives m*(m-1)/2 inversions.
Shifting an element by m positions, creates m inversions.
def get_m(k):
m=0
while m*(m-1)/2<=k:
m+=1
else:
m-=1
return m
def generate(l, k):
"""
Generate array of length l with k inversions.
"""
# Generate a sorted array of length l
arr = list(range(0,l))
# If no inversions are needed, return sorted array.
if k==0:
return arr
# Find largest m such that m*(m-1)/2 <= k
m=get_m(k)
# Reverse first m elements in the array which will give m*(m-1)/2 inversions
arr = arr[m-1::-1]+arr[m:]
# Calculate for any remaining inversions
remaining_k = k-(m*(m-1)/2)
# For remaining inversions, move the last element to its left by remaining_k
if remaining_k>0:
arr.insert(int(len(arr)-remaining_k - 1), arr[-1])
arr = arr[:-1]
return arr
if __name__ == '__main__':
l = int(sys.argv[1])
k = int(sys.argv[2])
arr = generate(l, k)
print(arr)
There's a very easy way to create n inversions...
That is to move the last element to the front.
It's not exactly efficient due to the additional memory used, but I would do something like this:
Create an array that is twice the length n.
Fill it from the start to the middle with a sentinel (i.e. null) if we use an Integer[] instead of int[].
Fill it from the middle, ascending.
Then do something like the below...
I'm sure I have off by one errors and other bugs but the general idea is captured in the below code.
int start = 0;
int mid = arr.length / 2;
int end = arr.length - 1;
while (v > 0)
{
if (v < (end - mid))
{
arr[start++] = arr[mid + v];
arr[mid + v] = null;
}
else
{
arr[start++] = arr[end];
v -= (end - mid);
end--;
}
}
So we have an array filled with the starting values, a bunch of nulls, then the original incremental values, with one that may have become null, and an "end" pointer that points to the middle of the original zone.
So the final step is to copy from 0 -> endPos, ignoring the nulls, to the final array.
The logic is not much difficult. For example, we have 10 numbers [0,1,2,3,4,5,6,7,8,9] say, to generate like 18 inversions. Firstly, insert 9 before 0, --->[9,0,1,2,3,4,5,6,7,8], which generates 9 inversions. Still 9 inversions left, so we insert 8 before 0, ---->[9,8,0,1,2,3,4,5,6,7], so we get additional 8 inversions. Finally, 1 inversions left, we insert 7 before 6----->[9,8,0,1,2,3,4,5,7,6]. I only use arrays in this case. This program works in O(n) complexity. The following code only considering n numbers (0,1,2.....n-1) and their inversions.
public static int[] generate(int n, long k) {
int[] a = new int[n];
int[] b = new int[n];
for (int i = 1; i < n; i++) {
a[i] = 1 + a[i - 1];
}
if (n == 0 || k == 0) return a;
else {
int i = 0;
while (k > 0) {
if (k > n - i - 1) {
b[i] = a[n - 1 - i];
}
else {
//auxilary array c to store value
int[] c = new int[(int) (k + 1)];
for (int j = i; j < n - 1 - k; j++) {
b[j] = j - i;
}
for (int j = (int) (n - 1 - k); j < n; j++) {
c[j - (int) (n - 1 - k)] = j - i;
}
b[(int) (n - 1 - k)] = c[(int) k];
for (int j = (int) (n - k); j < n; j++) {
b[j] = c[j - (int) (n - k)];
}
break;
}
k = k - (n - 1 - i);
i++;
}
return b;
}
}
#zhong yang: It works nicely in the expected range 0 <= k <= n(n-1)/2 but it should be better to throw either an exception or null if k is out of this range instead of returning some array!

Bucket Sort Algorithm Code Issues

I need to implement the following in java.
Input: an array of integers
Output: Rearrange the array to have the following:
Suppose the first element in the original array has the value x
In the new array, suppose that x is in position I, that is data[I] = x. Then, data[j] <= x for all x and for all j > I. This means that all the values to the "left" of x are less than or equal to x and all the values to the "right" are larger than x.
An example is as follows: Suppose the array has the elements in this initial order: 4,3,9,2,7,6,5. After applying your algorithm, you should get: 3,2,4,5,9,7,6. That is, the leftmost element, 4, is positioned in the resulting array so that all elements less than 4 (2 and 3) are to its left (in no particular order), and all elements larger than 4 are to its right (in no particular order).
There is no space requirement for the algorithm, only that the problem is solved in O(n) time.
I have implemented a bucket sort, but am having some difficulties with the code.
public class Problem4
{
public static void partition(int[] A)
{
int x = A[0];
int l = A.length;
int[] bucket = int [];
for(int i=0; i<bucket.length; i++){
bucket[i]=0;
}
for (int i=0; i<l; i++){
bucket[x[i]]++;
}
int outPos=0;
for(int i=0; i<bucket.length; i++){
for(int j=0; j<bucket[i]; j++){
x[outPos++]=i;
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] A = {4,3,9,2,7,6,5};
System.out.println("Before partition:");
for(int i = 0; i < A.length; i++)
{
System.out.print(A[i] + " ");
}
partition(A);
System.out.println("After partition:");
System.out.println("Before partition:");
for(int i = 0; i < A.length; i++)
{
System.out.print(A[i] + " ");
}
}
}
The lines:
int[] bucket = int[],
bucket[x[i]]++;, and
x[outpost++] = i;
are causing me troubles. I am getting the error
The type of expression must be an array type but is resolved to an int.
The problem stems from that first line where I am trying to create a new array called bucket. I would appreciate any suggestions! Thanks!
I don't think you need to resort to a bucket sort. Instead you can simply walk through the array, placing elements that are less than the split value at the front and elements that are greater at the back. We can use two variables, front and back to keep track of the insert position at the front and back of the array. Starting at position 1 in the array, if the value is less than the split value we place at front and increment front and the current index. If the value is greater we swap it with the value at back and decrement back, but we keep the current index.
Here's some code to illustrate:
public static void main(String[] args)
{
int[] A = {4,3,9,2,7,6,5};
sort(A);
System.out.println(Arrays.toString(A));
}
public static void sort(int[] arr)
{
int split = arr[0];
int front = 0;
int back = arr.length-1;
for(int i=1; front != back; )
{
if(arr[i] <= split)
{
arr[front] = arr[i];
front += 1;
i++;
}
else
{
swap(arr, i, back);
back -= 1;
}
}
arr[front] = split;
}
public static void swap(int[] arr, int i, int j)
{
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
Output:
[3, 2, 4, 7, 6, 5, 9]
Another approach you can use is to use the standard partition algorithm of QuickSort.
I have modified your code and the following code
public class Problem4
{
/* This function takes last element as pivot,
places the pivot element at its correct
position in sorted array, and places all
smaller (smaller than pivot) to left of
pivot and all greater elements to right
of pivot */
public static int partition(int arr[], int low, int high)
{
int pivot = arr[high];
int i = (low-1); // index of smaller element
for (int j=low; j<high; j++)
{
// If current element is smaller than or
// equal to pivot
if (arr[j] <= pivot)
{
i++;
// swap arr[i] and arr[j]
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
// swap arr[i+1] and arr[high] (or pivot)
int temp = arr[i+1];
arr[i+1] = arr[high];
arr[high] = temp;
return i+1;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] A = {4,3,9,2,7,6,5};
System.out.println("Before partition:");
for(int i = 0; i < A.length; i++)
{
System.out.print(A[i] + " ");
}
// swap and call the standard partition algo of QuickSort
// on last element pivot. swap arr[low] and arr[high]
int low = 0;
int high = A.length-1;
int temp = A[low];
A[low] = A[high];
A[high] = temp;
partition(A, low, high);
System.out.println("\nAfter partition:");
for(int i = 0; i < A.length; i++)
{
System.out.print(A[i] + " ");
}
}
}
Outputs
Before partition:
4 3 9 2 7 6 5
After partition:
3 2 4 5 7 6 9
Hope it helps!

Sorting two non-sequential arrays to one array ascending

I was trying to sort two arrays with non sequential numbers into one array after I did with sequential numbers. Do I need to order the arrays separately or is there a more effective way?
If I run the code below my output will be 4,16,2,11,19.. and it should be 0,1,2,3,4..
int myFirstArray [] = { 16, 2, 11, 34, 77, 1, 0, 10, 3 };
int mySecondArray [] = { 4, 19, 6, 32, 8, 10, 66 };
int firstPos = 0, secondPos = 0;
int myThirdArray [] = new int[myFirstArray.length + mySecondArray.length];
for (int i = 0; i < myThirdArray.length; i++) {
if (firstPos < myFirstArray.length && secondPos < mySecondArray.length) {
if (mySecondArray[secondPos] < myFirstArray[firstPos]) {
myThirdArray[i] = mySecondArray[secondPos];
secondPos++;
}
else {
myThirdArray[i] = myFirstArray[firstPos];
firstPos++;
}
}
else if (secondPos < mySecondArray.length) {
myThirdArray[i] = mySecondArray[secondPos];
secondPos++;
}
else {
myThirdArray[i] = myFirstArray[firstPos];
firstPos++;
}
}
for(int i = 0; i < myThirdArray.length; i++) {
System.out.println(myThirdArray[i]);
}
If you had 2 sorted arrays and want to combine them into one sorted array then your code would be correct. But you are comparing the first 2 elements of your unsorted arrays and create a topically sorted array, meaning some elements of the array are sorted compared to others ie 4 < 16, 2 < 11 < 19.
Your logic is not far away from Mergesort. You split your array into halves and split them again and merges the 2 halves. You end up merging arrays of size 1, then merging arrays of size 2 and so on and so on. Your merging code is correct. You can see more details here.
// Merges two subarrays of arr[].
// First subarray is arr[l..m]
// Second subarray is arr[m+1..r]
void merge(int arr[], int l, int m, int r)
{
// Find sizes of two subarrays to be merged
int n1 = m - l + 1;
int n2 = r - m;
/* Create temp arrays */
int L[] = new int [n1];
int R[] = new int [n2];
/*Copy data to temp arrays*/
for (int i=0; i<n1; ++i)
L[i] = arr[l + i];
for (int j=0; j<n2; ++j)
R[j] = arr[m + 1+ j];
/* Merge the temp arrays */
// Initial indexes of first and second subarrays
int i = 0, j = 0;
// Initial index of merged subarry array
int k = l;
while (i < n1 && j < n2)
{
if (L[i] <= R[j])
{
arr[k] = L[i];
i++;
}
else
{
arr[k] = R[j];
j++;
}
k++;
}
/* Copy remaining elements of L[] if any */
while (i < n1)
{
arr[k] = L[i];
i++;
k++;
}
/* Copy remaining elements of R[] if any */
while (j < n2)
{
arr[k] = R[j];
j++;
k++;
}
}
// Main function that sorts arr[l..r] using
// merge()
void sort(int arr[], int l, int r)
{
if (l < r)
{
// Find the middle point
int m = (l+r)/2;
// Sort first and second halves
sort(arr, l, m);
sort(arr , m+1, r);
// Merge the sorted halves
merge(arr, l, m, r);
}
}
It is always better to sort your both arrays first and then merge both the array in single array.
// Function to merge array in sorted order
// a[] will be the first unsorted array.
// b[] will be the second unsorted array.
public static int[] sortedMerge(int a[], int b[]){
int n = a.length;
int m = b.length;
int totalSize=n+m;
//result array
int[] res =new int[totalSize];
// Sorting a[] and b[]
Arrays.sort(a);
Arrays.sort(b);
// Merge two sorted arrays into res[]
int i = 0, j = 0, k = 0;
while (i < n && j < m) {
if (a[i] <= b[j]) {
res[k] = a[i];
i += 1;
k += 1;
} else {
res[k] = b[j];
j += 1;
k += 1;
}
}
while (i < n) { // Merging remaining
// elements of a[] (if any)
res[k] = a[i];
i += 1;
k += 1;
}
while (j < m) { // Merging remaining
// elements of b[] (if any)
res[k] = b[j];
j += 1;
k += 1;
}
return res;
}
This way the Time Complexity will be O(nlogn + mlogm + (n + m)) and
Space Complexity will be O ( (n + m) ). If you think to merge the array first and then sort the merged array then the space complexity will be the same but time complexity will change to O((n + m)(log(n + m))), which will be definitely higher than first one .
create a new array3 with size sum of array1.length and array2.length
use System.arrayCopy() to copy array1 to array3 starting at index 0
use System.arrayCopy() to copy array2 to array3 starting at index array1.length
sort array3 in the way you prefer e.g. Arrays.sort() or any other algorithm

Converting a Java Method into a recursive method? (insertion sort)

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
}

Categories