Recursive Insertion Sort - java

I have the following problem that I'm having trouble with, particularly in some of the parts where some of the code is given to me.
Problem Description: Given an array of integers, return an array containing the same integers sorted from the largest to the smallest using insertion sort. We'll use the convention of considering only part of the array that begins at a given index and ends at another. In this way, a recursive call can work through any part of the array. The initial call will pass in index 0 and the index to the last element.
insertionSort([2, 1, 3, -2, 8], 0, 4) → [8, 3, 2, 1, -2]
insertionSort([2, 6, -4], 0, 2) → [6, 2, -4]
insertionSort([2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22], 0, 10) → [22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2]
Code Given:
public int[] insertionSort(int[] nums, int begin, int end) {
}
void insert(int[] nums, int begin, int end, int element) {
int index=end;
while(index>=begin && nums[index]<element) {
index--;
}
for(int i=end; i>index; i--) {
nums[i+1] = nums[i];
}
nums[index+1] = element;
}
What I'm having trouble with is understanding what the "element" variable means in the "insert" method.
Here is the code I have written for it.
public int[] insertionSort(int[] nums, int begin, int end) {
if(begin >= end) return nums;
else if (begin < end){
int element = nums.length;
insert(nums, begin, end, element);
insertionSort(nums, begin, end);
}
return nums;
}
void insert(int[] nums, int begin, int end, int element) {
int index=end;
while(index>=begin && nums[index]<element) {
index--;
}
for(int i=end; i>index; i--) {
nums[i+1] = nums[i];
}
nums[index+1] = element;
}
This are the errors I get from my code:

Non recursive version:
public static int[] insertionSort(int[] nums, int begin, int end) {
for (int i = begin + 1; i <= end; i++) {
insert(nums, begin, i - 1, nums[i]);
}
return nums;
}
public static void insert(int[] nums, int begin, int end, int element) {
int index=end;
while(index>=begin && nums[index]<element) {
index--;
}
for(int i=end; i>index; i--) {
nums[i+1] = nums[i];
}
nums[index+1] = element;
}
public static void main(String[] args) {
int[] is = new int[]{5,6,7,2};
insertionSort(is, 0, is.length - 1);
System.out.println(Arrays.toString(is));
}
Recursive version:
public static int[] insertionSort(int[] nums, int begin, int end) {
if (begin>=end) {
return nums;
}
insertionSort(nums, begin, end-1);
insert(nums, begin, end-1, nums[end]);
return nums;
}
public static void insert(int[] nums, int begin, int end, int element) {
int index=end;
while(index>=begin && nums[index]<element) {
index--;
}
for(int i=end; i>index; i--) {
nums[i+1] = nums[i];
}
nums[index+1] = element;
}
public static void main(String[] args) {
int[] is = new int[]{5,6,7,2};
System.out.println();
insertionSort(is, 0, is.length - 1);
System.out.println(Arrays.toString(is));
}

so what you are doing wrong is passing the element as nums.length, element is the number to be inserted, that is after each recursive call it would be (begin+1)th element, and you will keep increasing begin by 1 as that part of array(0 to begin) would be already sorted.
SO the next time insertionsort would be called on begin+1 to end. Here is the working sample below.
public class Main
{
public static int[] insertionSort(int[] nums, int begin, int end) {
if(begin >= end) return nums;
else if (begin < end){
int element = nums[begin+1];
insert(nums, 0, begin, element);
insertionSort(nums, begin+1, end);
}
return nums;
}
static void insert(int[] nums, int begin, int end, int element) {
int index=end;
while(index>=begin && nums[index]<element) {
index--;
}
for(int i=end; i>index; i--) {
nums[i+1] = nums[i];
}
nums[index+1] = element;
}
public static void main(String[] args) {
int[] a = {3,41,0,10};
int[] t = insertionSort(a, 0, 3);
for (int i =0; i<4; i++){
System.out.println(t[i]);
}
}
}

I think this is more or less what you are trying to do.
class RecursiveInsertionSort {
public static void main(String[ ] args) {
int[] input1 = {2, 1, 3, -2, 8};
int[] input2 = {2, 6, -4};
int[] input3 = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22};
int[] res1 = insertionSort(input1, 0, 4);
// res1 = [8, 3, 2, 1, -2]
int[] res2 = insertionSort(input2, 0, 2);
// res2 = [6, 2, -4]
int[] res3 = insertionSort(input3, 0, 10);
// res3 = [22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2]
}
public static int[] insertionSort(int[] nums, int begin, int end) {
if(begin >= end) {
return nums; // We are done
}
// Sort the first n-1 elements
insertionSort(nums, begin, end - 1);
// Insert the nth element in the first n-1 elements array
insert(nums, begin, end - 1, nums[end]);
return nums;
}
static void insert(int[] nums, int begin, int end, int element) {
int index = end;
while(index >= begin && nums[index] < element) {
index--;
}
for(int i = end; i > index; i--) {
nums[i + 1] = nums[i];
}
nums[index + 1] = element;
}
}

The below solution is passing all your test cases. Your insert method should be something like this
public static int[] insertionSort(int[] nums, int begin, int end) {
if (begin >= end) {
return nums;
}
for (int i = 0; i < end; i++) {
insert(nums, i, end - 1, nums[end]);
}
return nums;
}
Below is the complete solution for your quick reference.
public class Solution {
public static void main(String[] args) {
int[] input1 = { 2, 1, 3, -2, 8 };
int[] result1 = insertionSort(input1, 0, 4);
printArray(result1);
int[] input2 = { 2, 6, -4 };
int[] result2 = insertionSort(input2, 0, 2);
printArray(result2);
int[] input3 = { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22 };
int[] result3 = insertionSort(input3, 0, 10);
printArray(result3);
int[] input4 = { 6, 6, 6, };
int[] result4 = insertionSort(input4, 0, 2);
printArray(result4);
int[] input5 = { 8 };
int[] result5 = insertionSort(input5, 0, 0);
printArray(result5);
}
public static void printArray(int[] input) {
System.out.print("[ ");
for (int i = 0; i < input.length; i++) {
System.out.print(input[i] + " ");
}
System.out.println("]");
}
public static int[] insertionSort(int[] nums, int begin, int end) {
if (begin >= end) {
return nums;
}
for (int i = 0; i < end; i++) {
insert(nums, i, end - 1, nums[end]);
}
return nums;
}
static void insert(int[] nums, int begin, int end, int element) {
int index = end;
while (index >= begin && nums[index] < element) {
index--;
}
for (int i = end; i > index; i--) {
nums[i + 1] = nums[i];
}
nums[index + 1] = element;
}
}

Related

Java and Python MergeSort

I am new to Java and I have been trying to do MergeSort, in a similar way I did it in Python.
This is how I do it in Python:
def merge_sort(a):
length = len(a)
if length > 1:
left = a[: len(a) // 2]
right = a[len(a) // 2 :]
merge_sort(left)
merge_sort(right)
merge(a, left, right)
def merge(a, left, right):
length = len(a)
left_half = len(left)
right_half = len(right)
i1, i2 = 0, 0
for i in range(length):
if i2 >= right_half or (i1 < left_half and left[i1] < right[i2]):
a[i] = left[i1]
i1 += 1
else:
a[i] = right[i2]
i2 += 1
This is my Java code and it returns index error.
import java.util.Arrays;
public class Merge_sort1 {
public static void main(String[] args) {
int[] a = {5, 3, 0, 1, 9, 6, 7, 4, 8, 2};
System.out.println("Array before sorting");
System.out.println(Arrays.toString(a));
mergeSort(a);
System.out.println("Array after sorting");
System.out.println(Arrays.toString(a));
}
public static void mergeSort(int[] a) {
if (a.length > 1) {
int mid = a.length / 2;
int[] left = Arrays.copyOfRange(a, 0, mid - 1);
int[] right = Arrays.copyOfRange(a, mid, a.length - 1);
mergeSort(left);
mergeSort(right);
merge(a, left, right);
}
}
public static void merge(int[] a, int[] l, int[] r) {
int i1 = 0;
int i2 = 0;
for(int i = 0; i < a.length; i++) {
if(i2 >= r.length || (i1 < l.length && l[i1] < r[i2])) {
a[i] = l[i1];
i1++;
a[i] = r[i2];
i2++;
}
}
}
}
I would really appreciate it if anyone can explain to me what I'm doing wrong and the best way to fix it.
Thank you
The copyOfRange call is erroneous; note that the second argument is exclusive rather than inclusive. Which means the second argument of the method minus 1 is the last element to be copied. So when calling copyOfRange(a, b, c) for example, the array a is copied from index b to c - 1, not c.
Also, the if statement in merge should be an if-else one (you forgot the else part).
So here is the code fixed, with proper output:
import java.util.Arrays;
public class Main {
public static void main(final String[] args) {
int[] a = {5, 3, 0, 1, 9, 6, 7, 4, 8, 2};
System.out.println("Array before sorting");
System.out.println(Arrays.toString(a));
mergeSort(a);
System.out.println("Array after sorting");
System.out.println(Arrays.toString(a));
}
public static void mergeSort(int[] a) {
if (a.length > 1) {
int mid = a.length / 2;
int[] left = Arrays.copyOfRange(a, 0, mid);
int[] right = Arrays.copyOfRange(a, mid, a.length);
mergeSort(left);
mergeSort(right);
merge(a, left, right);
}
}
public static void merge(int[] a, int[] l, int[] r) {
int i1 = 0;
int i2 = 0;
for(int i = 0; i < a.length; i++) {
if(i2 >= r.length || (i1 < l.length && l[i1] < r[i2])) {
a[i] = l[i1];
i1++;
}
else {
a[i] = r[i2];
i2++;
}
}
}
}

Moving larger numbers to right, and smaller numbers to left of given value

I have a homework problem that gives me this array:
[3, 22, 1, 5, 6, 10, 4]
And I need to move all numbers that are larger than the last value, 4, to the right of the value and all of the values that are smaller to the left.
The numbers do not necessarily need to be in order. So, the output of the program would be:
[3, 1, 4, 22, 5, 6, 10]
For some reason I am really struggling to think of an algorithm that would allow for this to happen. I have tried creating a loop that swaps the last value with larger numbers, but if a smallest value is mixed in the array somewhere odd it will be to the right of the value which is not correct.
Can anyone help me with this?
I won't help you complete the home-work. But I will guide you to think where this example of yours is headed. It is the first step of quick sort - Partitioning the array.
public class QuickSortImpl {
private static void swap(int[] array, int l, int h) {
int temp = array[h];
array[h] = array[l];
array[l] = temp;
}
public static int partition(int[] array, int low, int high) {
int pivot = high;
int firsthigh = low;
int x,y;
for (int i = low; i < high; i++) {
x = array[i];
y = array[pivot];
if (array[i] < array[pivot]) {
swap(array, i, firsthigh);
firsthigh++;
}
}
swap(array, pivot, firsthigh);
return firsthigh;
}
private static void printArray(int[] arr ) {
for ( int i =0; i < arr.length; i++ ) {
System.out.print(" " + arr[i]);
}
System.out.println();
}
public static void quickSort(int[] array, int low, int high) {
if ( low < high ) {
int pivot = partition(array, low, high);
quickSort(array, low, pivot - 1);
quickSort(array, pivot + 1, high);
}
}
public static void main(String[] args) {
int[] arr = { 3, 22, 1, 5, 6, 10, 4};
quickSort(arr, 0, arr.length -1 );
printArray(arr);
}
}
#brent_mb, take a look at this simple example for your cause:
public static void main(String[] args) {
Integer[] listOfNumbers = {1,4,5,6,74,2,7,8,5,2,6,989,3};
//sort by number 6
FirstCustomComparator comparator = new FirstCustomComparator(6);
Arrays.sort(listOfNumbers, 0, listOfNumbers.length, comparator);
for (int number : listOfNumbers) {
System.out.print(number+" ");
}
}
FirstCustomComparator class:
public class FirstCustomComparator implements Comparator<Integer> {
private final int exception;
public FirstCustomComparator(int i)
{
exception = i;
}
#Override
public int compare(Integer a, Integer b)
{
if (a < exception)
{
return -1;
}
return a.compareTo(b);
}
}

Right shift content of int array to num

I tried:
public static void main(String[] args) {
int array [] = {2, 5, 1, 4, 7, 9, 0};
for (int i = 0; i < array.length-2; i++) {
swapNum(array[i], array[i+2]);
System.out.println(Arrays.toString(array));
}
System.out.println(Arrays.toString(array));
}
public static void swapNum(int a, int b){
int tmp = a;
a = b;
b = tmp;
}
But found that it is not swapping values. Then I took help from here
https://codereview.stackexchange.com/questions/86016/left-shifting-an-array-of-ints
public void anotherTry() {
int nums [] = {4, 5, 2, 1, 6, 8};
for (int i = 0, start = 0; i < nums.length; i++) {
if (i == 0)
start = nums[i];
if (i == (nums.length - 1)) {
nums[i] = start;
break;
}
nums[i+2] = nums[i];
System.out.println(Arrays.toString(nums));
}
System.out.println(Arrays.toString(nums));
}
Its gives array out of bound of exception.
Where I am wrong?
Role of start variable. If start always will be equal to nums[i]?
You can't swap values like that in Java. However, since you are using an array and want to swap values within the array, you can rewrite your swap method to work with indexes:
public static void main(String[] args) {
int array [] = {2, 5, 1, 4, 7, 9, 0};
for (int i = 0; i < array.length-2; i++) {
swapNum(array, i, i+2);
System.out.println(Arrays.toString(array));
}
System.out.println(Arrays.toString(array));
}
public static void swapNum(int[] values, int i, int j){
int tmp = values[i];
values[i] = values[j];
values[j] = tmp;
}

What's wrong with my HeapSort code?

I'm attempting to write a heapsort method in java but it's not working exactly as I want it to:
public class HeapSort {
private static int n;
private static void swap(int[] A, int a, int b)
{
int tmp = A[a];
A[a] = A[b];
A[b] = tmp;
}
private static void insert(int[] A, int i)
{
int left = i * 2;
int right = left + 1;
int max = i;
if (left <= n && A[left] < A[max]){
max = left;
}
if (right <= n && A[right] > A[max]) {
max = right;
}
if (max != i) {
swap(A, i, max);
insert(A, max);
}
}
public static void HeapSort(int[] A)
{
n = A.length - 1;
for (int i = n / 2; i >= 0; i--)
insert(A, i);
for (int i = n; i > 0; i--) {
swap(A, 0, i);
n--;
insert(A, 0);
}
}
public static void main(String[] args){
int[] A = new int[] {9, 2, 8, 1, 4};
System.out.println(java.util.Arrays.toString(arr));
HeapSort(A);
System.out.println(java.util.Arrays.toString(arr));
}
}
It works with some arrays however arrays like 9, 2, 8, 1, 4 will get sorted into 1, 4, 2, 8, 9. So why isn't it sorting the array in the correct way?
if (left <= n && A[left] > A[i]){
max = left;
}
Try this and see.
I have made the complete program as below. This works fine for input you provided.
public class HeapSort {
private static int n;
private static void swap(int[] A, int a, int b)
{
int tmp = A[a];
A[a] = A[b];
A[b] = tmp;
}
private static void insert(int[] A, int i)
{
int left = i * 2;
int right = left + 1;
int max = i;
if (left <= n && A[left] > A[i]){
max = left;
}
if (right <= n && A[right] > A[max]) {
max = right;
}
if (max != i) {
swap(A, i, max);
insert(A, max);
}
}
public static void HeapSort(int[] A)
{
n = A.length - 1;
for (int i = n / 2; i >= 0; i--)
insert(A, i);
for (int i = n; i > 0; i--) {
swap(A, 0, i);
n--;
insert(A, 0);
}
}
public static void main(String[] args){
int[] A = new int[] {19, 6, 28, 1, 0};
int[] B = new int[] {1, 2, 4, 8, 9, 0};
System.out.println(java.util.Arrays.toString(A));
System.out.println(java.util.Arrays.toString(B));
HeapSort(A);
HeapSort(B);
System.out.println(java.util.Arrays.toString(A));
System.out.println(java.util.Arrays.toString(B));
}
}
Here is the output.
[19, 6, 28, 1, 0]
[1, 2, 4, 8, 9, 0]
[0, 1, 6, 19, 28]
[0, 1, 2, 4, 8, 9]
If you define left = i * 2, the root of your heap should be stored in A[1], not A[0]. By not using the array at index 0, you can always say that the left and right children of a node i are 2*i and 2*i+1, respectively.
Basically, in your HeapSort, you should change 0 to 1 (there are 4 of them). Test it with array {0, 9, 2, 8, 1, 4}.
And also, a comparison in insert is also wrong. It should be A[left] > A[max].

QuickSort in Java not delivering sorted results

I tried to implement the code for QuickSort using the algorithm which was mentioned on http://en.wikipedia.org/wiki/Quicksort#Algorithm .
But, I am not able to get a sorted output. Rather, I am only getting the same array as the output.
Can anybody review it for me and tell me what's wrong with my code?
public class QuickSort {
private int[] arr;
private void quick_sort(int[] input, int lo, int hi){
this.arr = input;
if(lo<hi){
int p = partition(arr, lo, hi);
if(lo < p-1)
quick_sort(arr, lo, p-1);
if(hi > p+1)
quick_sort(arr, p+1, hi);
}
}
private int partition(int[] arr, int lo, int hi){
int pivotIndex = hi; //last element
int pivotVal = arr[pivotIndex];
int j = lo;
for(int i = lo; i<hi; i++){
if(arr[i] < pivotVal){
swap(arr[j],arr[i]);
j++;
}
}
swap(arr[j],pivotVal);
return j;
}
private void swap(int l, int r){
l = l+r;
r = l-r;
l = l-r;
}
private void printArray(){
for(int i : arr)
System.out.print(i+", ");
}
public static void main(String[] args) {
QuickSort q = new QuickSort();
int[] input = {10, 5, 15, 3, 20, 30, 25, 19};
q.quick_sort(input, 0, input.length-1);
q.printArray();
}
};
Output:
10, 5, 15, 3, 20, 30, 25, 19,
Your swap method is incorrect. Java is always pass by value, and primitives can't be modified like that. Instead, pass in the array (the value of an array, as an Object instance, is its' reference) and the indexes to swap like
private void swap(int[] arr, int l, int r) {
int t = arr[l];
arr[l] = arr[r];
arr[r] = t;
}
And then you can call it like
private int partition(int[] arr, int lo, int hi) {
int pivotIndex = hi; // last element
int j = lo;
for (int i = lo; i < hi; i++) {
if (arr[i] < arr[pivotIndex]) {
swap(arr, j, i);
j++;
}
}
swap(arr, j, pivotIndex);
return j;
}
Output (with just those changes) is
3, 5, 10, 15, 19, 20, 25, 30,
Also, you could print the array like
System.out.println(Arrays.toString(arr));

Categories