Heap Sort Questions - java

I am working on a homework problem that involves a heap sort implementation in java. Here is what I have so far
public class HeapSort {
public static void maxHeapify(int[] a, int i) {
int largest;
int l = 2*i;
int r = (2*i)+1;
if (l<=a.length-1 && a[l]>a[i]) {
largest = l;
}
else {
largest = i;
}
if (r<a.length-1 && a[r]>a[largest]) {
largest = r;
}
if (largest != i) {
int temp = a[i];
a[i] = a[largest];
a[largest] = temp;
maxHeapify(a,largest);
}
}
public static void buildMaxHeap(int[] a) {
for (int i=(a.length-1/2); i>=1; i--) {
maxHeapify(a,i);
}
}
public static void heapSort(int[] a) {
buildMaxHeap(a);
for (int i=a.length-1; i>=1; i--) {
int temp = a[0];
a[0] = a[i];
a[0] = temp;
maxHeapify(a,1);
}
}
Here is a main I put together to test (with output)
public static void main(String[] args) {
int[] tester = {3,2,9,45,7,15,21,11,36};
System.out.println(Arrays.toString(tester));
heapSort(tester);
System.out.println(Arrays.toString(tester));
}
[3, 2, 9, 45, 7, 15, 21, 11, 36]
[3, 45, 36, 21, 9, 15, 2, 11, 7]
I am not currently getting any errors but the output is just a bit off. Any help is very much appreciated. Thanks!
*Edited to add sample output

At a quick glance, I'd say you are missing a number of calls to maxHeapify(). It looks like you only maxHeapify() half of the heap (the half that ends in the rightmost branch), but not the rest. You must call maxHeapify() for all elements in a[0] to a[length/2].
You should move the recursive call to maxHeapify() out of the conditional for swapping. For the initial build of the heap, you must propagate all the way up to the root.
And you don't maxHeapify() the 'largest' element, but the one one level up the heap, so always i/2.

if (r<a.length-1 && a[r]>a[largest]) {
largest = r;
}
should be
if (r<=a.length-1 && a[r]>a[largest]) {
largest = r;
}
I believe you also have to call maxHeapify(a,0); instead of maxHeapify(a,1); in the last loop. Apart from that the -1/2 ordering issue in the comments mentioned above. That should do the job.

Related

Cannot read field "value" because "anotherByte" is null

Here I have a Quick Sort algorithm. The base class has the function isLessThan()
abstract public class Sort<T extends Comparable<T>> {
protected T[] array;
public boolean isLessThan(T obj1, T obj2) {
if (obj1.compareTo(obj2) < 0)
return true;
else
return false;
}
abstract public void sort(T[] array);
}
The actual algorithm picks a partition, splits the array into high, low and then recursively partitions the high and low arrays. However I cannot get past the part where I add elements to high and low:
public class Quick<T extends Comparable<T>> extends Sort<T> {
T[] low, high;
public void addLow(T element, int index) {
low[index] = element;
}
public void addHigh(T element, int index) {
high[index] = element;
}
public T[] partition(T[] arr, T partition) {
int lowCount = 0;
int highCount = 0;
low = (T[]) new Comparable[arr.length];
high = (T[]) new Comparable[arr.length];
// here I am adding each element to either high or low
for (int i = 0; i < arr.length; i++) {
if (arr[i] != null) {
if (isLessThan(arr[i], partition)) {
addLow(arr[i], i);
lowCount++;
} else {
addHigh(arr[i], i);
highCount++;
}
}
}
// the rest of this code probably isn't relevant to my problem
// sort low, then high
if (lowCount > 1) {
low = partition(low, low[0]);
}
if (highCount > 1) {
high = partition(high, high[0]);
}
// merge
T[] arr2 = (T[]) new Comparable[low.length + high.length];
int count = 0;
for(int i = 0; i < low.length; i++) {
arr2[i] = low[i];
count++;
}
for(int j = 0; j < high.length;j++) {
arr2[count++] = high[j];
}
return arr2;
}
public void sort(T[] arr)
{
T partition = arr[0];
arr = partition(arr, partition);
//set super to array
super.array = arr;
}
}
For some reason, I get this error when calling isLessThan():
Exception in thread "main" java.lang.NullPointerException: Cannot read field "value" because "anotherByte" is null
at java.base/java.lang.Byte.compareTo(Byte.java:490)
at java.base/java.lang.Byte.compareTo(Byte.java:56)
at Sort.isLessThan(Sort.java:6)
at Quick.partition(Quick.java:20)
at Quick.partition(Quick.java:33)
at Quick.sort(Quick.java:59)
at Main.main(Main.java:7)
What is causing this error?
My main looks like this:
public class Main {
public static void main(String[] args) {
Byte[] array = {121, 25, 44, 17, 30, 55, 29, 7, 81, 45, 79, 41, 108, 60, 83, 29, 77, 5, 17, 110};
Quick s = new Quick();
s.sort(array);
}
}
Your assumption the rest of this code probably isn't relevant to my problem is wrong. Because it is low[0] that is null indeed.
// the rest of this code probably isn't relevant to my problem
// sort low, then high
if (lowCount > 1) {
System.out.println("LOW: " + low[0]);
low = processPartition(low, low[0]);
}
if (highCount > 1) {
System.out.println("HIGH: " + high[0]);
high = processPartition(high, high[0]);
}
You instantiate both arrays and say they have the same dimension as the original array. This is okay.
low = (T[]) new Comparable[arr.length];
high = (T[]) new Comparable[arr.length];
But your mistake is, that you use the wrong indexing approach! You take the index from the for-loop and pass it as index to the arrays.
for (int i = 0; i < arr.length; i++) {
if (arr[i] != null) {
if (isLessThan(arr[i], partition)) {
addLow(arr[i], i);
lowCount++;
} else {
addHigh(arr[i], i);
highCount++;
}
}
But what happens?
With the very first comparison you have 121 on 121. This is not less than but equal. In case of higher or equal you go into the else-part and call addHigh().
So index 0 is gone for a High.
Now the comparison goes on and on and all the others are LessThan() because 121 is the highest number in your list.
But, as you hand in the index from the loop, the first LessThan()-value does not go into low[0] but low[1]. low[0] is null!
And then you later call low = processPartition(low, low[0]); and get your NPE.
So you have at least 1 thing to do:
DON'T USE the index i out of your for-loop! That's wrong!
DO USE your counter lowCount and highCount instead! They will always point to the correct field in the array!
Please note, that this will only explain why you get the first NPE here and help you to solve it.
When you run this code the same NPE-message will occur, but at another point in the process. This time, because you alway pass the arrays around and constantly change them. When the code somewhen comes back to the very first round and proceeds, it will find highCount > 1 and tries to process the high[]-array. But this has changed in the meantime and high[0] is null.
You have to rethink you entire sorting approach here.
I hope this helps at least to figure out what went wrong in the first place.

Find prime numbers using Array list

I want to find prime numbers given range using ArrayList. I have done following code.
import java.util.ArrayList;
import java.util.Iterator;
public class PrimeNumbers {
public static void main(String args) {
PrimeNumbers aaa=new PrimeNumbers();
Iterator<Integer> itr = aaa.printAllPrime(1, 10).iterator();
while(itr.hasNext()){
System.out.println(itr.next());
}
}
public ArrayList<Integer> printAllPrime(int k, int j) {
ArrayList<Integer> arrlist = new ArrayList<Integer>();
int count=0;
for(int i=k;i<=j;i++) {
for(int l=1;l<=i;l++) {
if(i%l == 0) {
count++;
}
}
//System.out.println(i+" "+count);
if(count == 2) {
arrlist.add(i);
}
}
return arrlist;
}
}
Expected:
[2, 3, 5, 7]
Current result:
[2, 4, 3, 5, 10]
I am fresh to java and please help me to find where I have done wrong here. Thank you.
Initialize count inside the first for loop, before the second one. Since count is never reset to 0 after each iteration, you are getting the wrong number.
public ArrayList<Integer> printAllPrime(int k, int j) {
ArrayList<Integer> arrlist = new ArrayList<Integer>();
// int count=0; <- here is incorrect
for(int i=k;i<=j;i++) {
int count = 0; // put it here
for(int l=1;l<=i;l++) {
if(i%l == 0) {
count++;
}
}
//System.out.println(i+" "+count);
if(count == 2) {
arrlist.add(i);
}
}
return arrlist;
}
That way, count will be for each individual number.
Hope this works for you!
for(int l=1;l<=i;l++) {
if(i%l == 0) {
count++;
}
}
In this part of your code, you literally check if, for example 4%2 == 0,
ofc it is, so 4 is also put in the array.
Also, your code can be significantly improved with some simple math.
So, if you test all the numbers up to the square root, you can rest
assured that the number is prime. For example, the square root of 23
is around 4.8, so you would test 23 to see if it can be divided by 2,
3 or 4. It cannot be, so 23 is prime.
Read more here

boolean method with array argument

I am trying for too long to figure out this exersies but I am stuck here. I need to write a boolean method that will an array as argument and should return true if numbers in array are in decreasing order. Bu any time that I am trying I am having the same value or errors. Here is my code:
public class Question1c{
public static void main (String[] args){
int[] arr = {1, 9, 3, 4, 5, 6};
boolean product = isDecreasing(arr);
System.out.println(product);
}
public static boolean isDecreasing (int[] numbers){
int first = numbers[0];
for (int i : numbers){
if(first <= i){
first = i;
return true;
}
//else{
// return false;
//}
}return false;
}
}
The problem in your code is that you cannot return true until after you went through the entire array. However, you can return false as soon as you detect an "inversion" - i.e. a situation when the number that follows the one you've seen before is greater than the prior number.
You are reasonably close to a working solution - you need to remove return true, uncomment the else, and change the final return false to return true.
To make your code more readable, rename first to prior. Also consider changing the "foreach" version of the for loop to a regular for loop that skips the initial element of the array. This would let you detect decreasing order, as opposed to non-increasing, which you currently detect.
Not sure I understand, but wouldn't this solve your issue?
public class Question1c{
public static void main (String[] args){
int[] arr = {1, 9, 3, 4, 5, 6};
boolean product = isDecreasing(arr);
System.out.println(product);
}
public static boolean isDecreasing (int[] numbers){
for (int i = 0; i < numbers.Length; i++){
if (i == 0)
continue;
if (numbers[i - 1] >= numbers[i])
return false;
}
return true;
}
}
You're essentially just aiming to check that the previous item in the array isn't greater than or equal to the current item in the array, aren't you?
You initialize first with numbers[0] this causes several problems:
An empty array throws IndexOutOfBoundsException
the first check automatically passes (numbers[0] <= numbers[0])
you best check the length of numbers for 0 and use a "normal" for loop (using an index).
Your return values is also the negation of what it should be.
This might solve your issue.
public class Question{
public static void main (String[] args){
int[] arr = {1, 9, 3, 4, 5, 6};
boolean product = isDecreasing(arr);
System.out.println(product);
}
public static boolean isDecreasing (int[] numbers){
int first = numbers[0];
for (int i = 1; i < numbers.length ; i++) {
if (first <= numbers[i]) {
return false;
}
first = numbers[i];
}
return true;
}
}

algorithm removing duplicate elements in array without auxillay storage

I am working on this famous interview question on removing duplicate elements in array without using auxillary storage and preserving the order;
I have read a bunch of posts; Algorithm: efficient way to remove duplicate integers from an array, Removing Duplicates from an Array using C.
They are either implemented in C (without explanation) or the Java Code provided just fails when there is consecutive duplicates such as [1,1,1,3,3].
I am not quite confident with using C, my background is Java. So I implemented the code myself;
it follows like this:
use two loops, the outer-loop traverses the array and inner loop checks for duplicates and if present replace it with null.
Then I go over the duplicate-replaced-null array and remove null elements and replacing it with the next non-null element.
The total run-time I see now is O(n^2)+O(n) ~ O(n^2). Reading the above posts, I understood this is the best we can do, if no sorting and auxiliary storage is allowed.
My code is here: I am looking for ways to optimize any further (if there is a possibility) or a better/simplisitc logic;
public class RemoveDup {
public static void main (String[] args){
Integer[] arr2={3,45,1,2,3,3,3,3,2,1,45,2,10};
Integer[] res= removeDup(arr2);
System.out.println(Arrays.toString(res));
}
private static Integer[] removeDup(Integer[] data) {
int size = data.length;
int count = 1;
for (int i = 0; i < size; i++) {
Integer temp = data[i];
for (int j = i + 1; j < size && temp != null; j++) {
if (data[j] == temp) {
data[j] = null;
}
}
}
for (int i = 1; i < size; i++) {
Integer current = data[i];
if (data[i] != null) {
data[count++] = current;
}
}
return Arrays.copyOf(data, count);
}
}
EDIT 1; Reformatted code from #keshlam throws ArrayIndexOutofBound Exception:
private static int removeDupes(int[] array) {
System.out.println("method called");
if(array.length < 2)
return array.length;
int outsize=1; // first is always kept
for (int consider = 1; consider < array.length; ++consider) {
for(int compare=0;compare<outsize;++compare) {
if(array[consider]!=array[compare])
array[outsize++]=array[consider]; // already present; advance to next compare
else break;
// if we get here, we know it's new so append it to output
//array[outsize++]=array[consider]; // could test first, not worth it.
}
}
System.out.println(Arrays.toString(array));
// length is last written position plus 1
return outsize;
}
OK, here's my answer, which should be O(N*N) worst case. (With smaller constant, since even worstcase I'm testing N against -- on average -- 1/2 N, but this is computer science rather than software engineering and a mere 2X speedup isn't significant. Thanks to #Alexandru for pointing that out.)
1) Split cursor (input and output advanced separately),
2) Each new value only has to be compared to what's already been kept, and compare can stop if a match is found. (The hint keyword was "incremental")
3) First element need not be tested.
4) I'm taking advantage of labelled continue where I could have instead set a flag before breaking and then tested the flag. Comes out to the same thing; this is a bit more elegant.
4.5) I could have tested whether outsize==consider and not copied if that was true. But testing for it would take about as many cycles as doing the possibly-unnecessary copy, and the majority case is that they will not be the same, so it's easier to just let a possibly redundant copy take place.
5) I'm not recopying the data in the key function; I've factored out the copy-for-printing operation to a separate function to make clear that removeDupes does run entirely in the target array plus a few automatic variables on the stack. And I'm not spending time zeroing out the leftover elements at the end of the array; that may be wasted work (as in this case). Though I don't think it would actually change the formal complexity.
import java.util.Arrays;
public class RemoveDupes {
private static int removeDupes(final int[] array) {
if(array.length < 2)
return array.length;
int outsize=1; // first is always kept
outerloop: for (int consider = 1; consider < array.length; ++consider) {
for(int compare=0;compare<outsize;++compare)
if(array[consider]==array[compare])
continue outerloop; // already present; advance to next compare
// if we get here, we know it's new so append it to output
array[outsize++]=array[consider]; // could test first, not worth it.
}
return outsize; // length is last written position plus 1
}
private static void printRemoveDupes(int[] array) {
int newlength=removeDupes(array);
System.out.println(Arrays.toString(Arrays.copyOfRange(array, 0, newlength)));
}
public static void main(final String[] args) {
printRemoveDupes(new int[] { 3, 45, 1, 2, 3, 3, 3, 3, 2, 1, 45, 2, 10 });
printRemoveDupes(new int[] { 2, 2, 3, 3 });
printRemoveDupes(new int[] { 1, 1, 1, 1, 1, 1, 1, 1 });
}
}
LATE ADDITION: Since folks expressed confusion about point 4 in my explanation, here's the loop rewritten without labelled continue:
for (int consider = 1; consider < array.length; ++consider) {
boolean matchfound=false;
for(int compare=0;compare<outsize;++compare) {
if(array[consider]==array[compare]) {
matchfound=true;
break;
}
if(!matchFound) // only add it to the output if not found
array[outsize++]=array[consider];
}
Hope that helps. Labelled continue is a rarely-used feature of Java, so it isn't too surprising that some folks haven't seen it before. It's useful, but it does make code harder to read; I probably wouldn't use it in anything much more complicated than this simple algorithm.
Here one version which doesn't use additional memory (except for the array it returns) and doesn't sort either.
I believe this is slightly worse than O(n*log n).
Edit: I'm wrong. This is slightly better than O(n^3).
public class Dupes {
private static int[] removeDupes(final int[] array) {
int end = array.length - 1;
for (int i = 0; i <= end; i++) {
for (int j = i + 1; j <= end; j++) {
if (array[i] == array[j]) {
for (int k = j; k < end; k++) {
array[k] = array[k + 1];
}
end--;
j--;
}
}
}
return Arrays.copyOf(array, end + 1);
}
public static void main(final String[] args) {
System.out.println(Arrays.toString(removeDupes(new int[] { 3, 45, 1, 2, 3, 3, 3, 3, 2, 1, 45, 2, 10 })));
System.out.println(Arrays.toString(removeDupes(new int[] { 2, 2, 3, 3 })));
System.out.println(Arrays.toString(removeDupes(new int[] { 1, 1, 1, 1, 1, 1, 1, 1 })));
}
}
and here's a modified version which doesn't shift all of the elements from after the dupe. Instead it simply switches the dupe with the last, non-matching element. This obviously can't guarantee order.
private static int[] removeDupes(final int[] array) {
int end = array.length - 1;
for (int i = 0; i <= end; i++) {
for (int j = i + 1; j <= end; j++) {
if (array[i] == array[j]) {
while (end >= j && array[j] == array[end]) {
end--;
}
if (end > j) {
array[j] = array[end];
end--;
}
}
}
}
return Arrays.copyOf(array, end + 1);
}
Here you have a worst case of O(n^2) where the return points to the first non unique element. So everything before it is unique.
Instead of C++ iterators indices in Java can be used.
std::vecotr<int>::iterator unique(std::vector<int>& aVector){
auto end = aVector.end();
auto start = aVector.begin();
while(start != end){
auto num = *start; // the element to check against
auto temp = ++start; // start get incremented here
while (temp != end){
if (*temp == num){
std::swap(temp,end);
end--;
}
else
temp++; // the temp is in else so that if the swap occurs the algo should still check the swapped element.
}
}
return end;
}
Java equivalent code: (the return will be an int which is the index of the first not unique element)
int unique(int[] anArray){
int end = anArray.length-1;
int start = 0;
while(start != end){
int num = anArry[start]; // the element to check against
int temp = ++start; // start get incremented here
while (temp != end){
if (anArry[temp] == num){
swap(temp,end); // swaps the values at index of temp and end
end--;
}
else
temp++; // the temp is in else so that if the swap occurs the algo should still check the swapped element.
}
}
return end;
}
The slight difference in this algo and yours is in your point 2. Where instead of replacing the current element with null you go with swapping it with the last possibly unique element which on the first swap is the last element of array, on second swap the second last and so on.
You might as well consider looking at the std::unique implementation in C++ which is linear in one less than the distance between first and last: Compares each pair of elements, and possibly performs assignments on some of them., but as it was noted by #keshlam it is used on sorted arrays only. The return value is the same as in my algo. Here is the code directly from the standard library:
template<class _FwdIt, class _Pr> inline
_FwdIt _Unique(_FwdIt _First, _FwdIt _Last, _Pr _Pred)
{ // remove each satisfying _Pred with previous
if (_First != _Last)
for (_FwdIt _Firstb; (_Firstb = _First), ++_First != _Last; )
if (_Pred(*_Firstb, *_First))
{ // copy down
for (; ++_First != _Last; )
if (!_Pred(*_Firstb, *_First))
*++_Firstb = _Move(*_First);
return (++_Firstb);
}
return (_Last);
}
To bring in a bit perspective - one solution in Haskell, it uses lists instead of arrays
and returns the reversed order, which can be fixed by applying reverse at the end.
import Data.List (foldl')
removeDup :: (Eq a) => [a] -> [a]
removeDup = foldl' (\acc x-> if x `elem` acc then acc else x:acc) []

Coin Exchange in java Code stackOverflowError

cannot find the problem, everytime when I'm running this code it goes stackoverflow due to this line
countCombine += count(array,money - (array[i]*(int)(money/array[i])));
basically problem is very easy.
Given a value N, if we want to make change for N cents, and we have infinite supply of each of S = { S1, S2, .. , Sm} valued coins, how many ways can we make the change? The order of coins doesn’t matter.
For example, for N = 4 and S = {1,2,3}, there are four solutions: {1,1,1,1},{1,1,2},{2,2},{1,3}. So output should be 4. For N = 10 and S = {2, 5, 3, 6}, there are five solutions: {2,2,2,2,2}, {2,2,3,3}, {2,2,6}, {2,3,5} and {5,5}. So the output should be 5.
public class CoinExchangeProblem {
int countCombine = 0;
private int count(int array[],int money){
// sort the array
// Arrays.sort(array);
// System.out.println(Arrays.toString(array));
if (money == 0) {
return 1;
} else if (money < 0) {
return 0;
}
for(int i = 0; i < array.length; i++){
countCombine += count(array,money - (array[i]*(int)(money/array[i])));
}
return countCombine;
}
public static void main(String[] args) {
CoinExchangeProblem coinExch = new CoinExchangeProblem();
System.out.println(coinExch.count(new int[]{1,2,3}, 4));
// System.out.println(coinExch.count(new int[]{2, 5, 3, 6}, 10));
}
}
When this part
(array[i]*(int)(money/array[i]))
equals zero your are a victim of infinite recursion where you are calling the function with the same amount of money
You can change it to :
if(money >= array[i])
countCombine += count(array,money - (array[i]*(int)(money/array[i])));
so you will never get a zero here, but test it for more examples as i didn't test it a lot , but I think that it is logically right

Categories

Resources