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].
Related
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;
}
}
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++;
}
}
}
}
for the last few days I've been trying really hard to write this algorithm but without success. The code works and most of the time it gives me the right result but there are some cases where it fails. For example with this array {3, 8, 1, 9, 10, 7, 6, 2, 5, 4} and k = 6 it should give me 6 as result but it gives me 7. Can someone help me? I can't figure out what's the problem.
Here is the code:
class MOMSelect {
static int median(int a[], int i, int n) {
if(i <= n)
Arrays.sort(a, i, n);
else
Arrays.sort(a, n, i);
return a[n/2];
}
static int medianOfMediansSelect(int a[], int left, int right, int k) {
int n = right - left + 1;
int i;
int[] medians = new int[(n + 4) / 5];
for (i = 0; i < n/5; i++) {
medians[i] = median(a, left + i * 5, 5);
}
if (i*5 < n) {
medians[i] = median(a,left + i * 5, n % 5);
i++;
}
int medianOfMedians = (i == 1)? medians[i - 1]: median(medians, 0, medians.length);
int pivotIndex = partition(a, left, right, medianOfMedians);
if (pivotIndex == k - 1) {
return a[pivotIndex];
}
else if (pivotIndex - left > k - 1) {
return medianOfMediansSelect(a, left, pivotIndex - 1, k);
}
else {
return medianOfMediansSelect(a, pivotIndex + 1, right, k);
}
}
static void swap(int[] a, int i, int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
static int partition(int[] a, int left, int right, int x) {
int i;
for (i = left; i < right; i++)
if (a[i] == x)
break;
swap(a, i, right);
i = left;
for (int j = left; j <= right - 1; j++) {
if(a[j] <= x) {
swap(a, i, j);
i++;
}
}
swap(a, i, right);
return i;
}
public static void main(String[] args) {
int a[] = {3, 8, 1, 9, 10, 7, 6, 2, 5, 4};
int n = a.length;
int k = 1;
System.out.println(medianOfMediansSelect(a, 0, n - 1, k));
}
}
Thanks in advance to everyone
Ok I solved. Further than my bad understanding of the Arrays.sort() method there was a stupid mistake on the if stucture where I check the pivotPosition value on the method medianOfMediansSelect()
More precisely on this line
else if (pivotIndex - left > k - 1) {
I should have done like this
else if (pivotIndex > k - 1) {
So, I modified your median method to correct the problem. You should check Arrays.sort method for a clear understanding.
Now it gives 6, for k=6.
Here is it,
static int median(int a[], int i, int n)
{
Arrays.sort(a, i, i + n - 1);
return a[i + n / 2];
}
I have the following codes and instead of typing the numbers using scanner function. I want to use an array instead . How do I do this? I need help. Thanks in advance
public class salomon {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int[] a = new int[n];
int[] minHeap = new int[n];
int[] maxHeap = new int[n];
int minHeapSize = 0;
int maxHeapSize = 0;
float currentMedian = 0;
for (int a_i = 0; a_i < n; a_i++) {
a[a_i] = in.nextInt();
if (a[a_i] < currentMedian) {
maxHeap[maxHeapSize++] = a[a_i];
// making sure the max heap has maximum value at the top
if (maxHeap[maxHeapSize - 1] > maxHeap[0]) {
swap(maxHeap, maxHeapSize - 1, 0);
}
} else {
minHeap[minHeapSize++] = a[a_i];
// making sure the min heap has minimum value at the top
if (minHeap[minHeapSize - 1] < minHeap[0]) {
swap(minHeap, minHeapSize - 1, 0);
}
}
// if the difference is more than one
if (Math.abs(maxHeapSize - minHeapSize) > 1) {
if (maxHeapSize > minHeapSize) {
swap(maxHeap, maxHeapSize - 1, 0);
minHeap[minHeapSize++] = maxHeap[--maxHeapSize];
swap(minHeap, 0, minHeapSize - 1);
buildMaxHeap(maxHeap, maxHeapSize);
} else {
swap(minHeap, minHeapSize - 1, 0);
maxHeap[maxHeapSize++] = minHeap[--minHeapSize];
swap(maxHeap, 0, maxHeapSize - 1);
buildMinHeap(minHeap, minHeapSize);
}
}
// calculate the median
if (maxHeapSize == minHeapSize) {
currentMedian = (minHeap[0] + maxHeap[0]);
currentMedian = currentMedian / 2;
} else if (maxHeapSize > minHeapSize) {
currentMedian = maxHeap[0];
} else {
currentMedian = minHeap[0];
}
System.out.println(currentMedian);
}
}
static void buildMaxHeap(int[] input, int heapSize) {
int depth = (heapSize - 1) / 2;
for (int i = depth; i >= 0; i--) {
maxHeapify(input, i, heapSize);
}
}
static void maxHeapify(int[] input, int i, int heapSize) {
int left = 2 * i + 1;
int right = 2 * i + 2;
// find the largest
int largest = i;
if (left < heapSize && input[left] > input[largest]) {
largest = left;
}
if (right < heapSize && input[right] > input[largest]) {
largest = right;
}
if (largest != i) {
//swap
swap(input, i, largest);
//recursive call
maxHeapify(input, largest, heapSize);
}
}
static void buildMinHeap(int[] input, int heapSize) {
int depth = (heapSize - 1) / 2;
for (int i = depth; i >= 0; i--) {
minHeapify(input, i, heapSize);
}
}
static void minHeapify(int[] input, int i, int heapSize) {
int left = 2 * i + 1;
int right = 2 * i + 2;
// find the smallest
int smallest = i;
if (left < heapSize && input[left] < input[smallest]) {
smallest = left;
}
if (right < heapSize && input[right] < input[smallest]) {
smallest = right;
}
if (smallest != i) {
//swap
swap(input, i, smallest);
//recursive call
minHeapify(input, smallest, heapSize);
}
}
static void swap(int[] input, int i, int j) {
if (i == j)
return;
int temp = input[i];
input[i] = input[j];
input[j] = temp;
}
}
When I typed 6, 12, 4, 5, 3, 8, 7 and enter - I get the Moving median
12.0
8.0
5.0
4.5
5.0
6.0
I want to replace the scanner with an array {6, 12, 4, 5, 3, 8, 7}`
instead and how do I adjust the code. Thanks
The first value 6 is the array length. Assuming you intend for that to remain, you would remove everything that "isn't an elephant" (namely all of the median calculations), and rename int[] a to int[] f. Like,
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int[] f = new int[n];
for (int i = 0; i < n; i++) {
f[i] = in.nextInt();
}
System.out.println(Arrays.toString(f));
}
When executed with your example input, this outputs
[12, 4, 5, 3, 8, 7]
If you really did want the six as well, then you would need to add it. Like,
int[] f = new int[n + 1];
f[0] = n;
for (int i = 1; i <= n; i++) {
f[i] = in.nextInt();
}
System.out.println(Arrays.toString(f));
which outputs (as requested)
[6, 12, 4, 5, 3, 8, 7]
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;
}