I am trying to implement a min heap in java which sorts based on two parameters. Each element of the min heap is an object which contains an int and a string. My current implementation sorts solely based on the integer but I also need it to sort in alphabetical order. For example, if the contents of the objects are as follows:
{ (stopped, 3), (anywhere, 1), (food, 17), (get, 3), (done, 1)}
the output when removing elements from the heap must be:
{(anywhere, 1), (done, 1), (get, 3), (stopped, 3), (food, 17)}
My sink and swim functions are described below:
private void swim(int n){
while (n > 1 && greater(n/2, n)){
exchange(n, n/2);
n = n/2;
}
}
private boolean greater(int i, int j){
return elements[i].getValue() >= elements[j].getValue();
}
private void exchange(int i, int j){
Node tmp = elements[i];
elements[i] = elements[j];
elements[j] = tmp;
}
private void sink(int k){
while(2*k <=n){
int i = 2*k;
if(i < n && greater(i, i+1)) i++;
if(!greater(k,i)) break;
exchange(k,i);
k = i;
}
}
Any help would be greatly appreciated!
Update
Thank you very much to #AlbertoSinigaglia, your solution worked!
you just need to update the greater method in this way:
return /*1*/ elements[i].getValue()>elements[j].getValue
||
/*2*/ (elements[i].getValue()==elements[j].getValue() && elements[i].getString().compareTo(elements[j].getString())>0)
With 1 you check if the int Value is greater, if yes, well ends there, if else it's not, it should be o = or < and we need to take care of the = case, so if the Values are equals, then we compare the String with the compareTo() method, which will return >0 in case the first String is greater than the second string
I'm looking a simple solution to get the minimum number "ArrayList of Integers" needed to have all numbers from 1 to n, with the next condition:
Each ArrayList must be created from 3 parameters (a, b and n)
"a" and "b" set the numbers in the ArrayList
"n" is the limit
The condition is:
If a ≤ b ===> a ≤ j ≤ b
if a>b ===> 1 ≤ j ≤ b and a ≤ j ≤ n
Note: "j" are the numbers on the ArrayList.
this is my code:
public Integers(int a, int b, int n) {//constructor
this.numbers = new ArrayList<Integer>();
makeList(a, b, n);
}
public void makeList(int a, int b, int n) {
if (a < b) {
while (a <= b) {
this.numbers.add(a);
a++;
}
} else {
int aux = 1;
while (aux <= b) {
this.numbers.add(aux);
aux++;
}
int aux2 = a;
while (aux2 <= n) {
this.numbers.add(aux2);
aux2++;
}
}
}
public void showNumbers() {
for (int x = 0; x < this.numbers.size(); x++) {
System.out.print(this.numbers.get(x) + "\t");
}
}
this is an example with n=20:
public static void main(String[] args) {
Integers first= new Integers(1, 10, 20);
first.showNumbers();//1 2 3 ...8 9 10
System.out.println();
Integers second= new Integers(15, 5, 20);
second.showNumbers();//1 2 3 4 5 15 16 17 18 19 20
System.out.println();
Integers third= new Integers(15, 20, 20);
third.showNumbers();//15 16 17 18 19 20
System.out.println();
Integers fourth= new Integers(4, 17, 20);
fourth.showNumbers();//4 5 6 ... 15 16 17
System.out.println();
System.out.println("Solution expected is: 2 ====> <second and fourth>");
}
and the answer that I expect is 2 (second and fourth).
If you know what n is from the start, it might be simpler to store a boolean array of n values. Then every time you construct an ArrayList, you just mark off if that value would appear in the ArrayList.
Other than this, you pretty much would have to brute-force (I think this would be equivalent to the vertex-cover problem so you'd at best be able to approximate in faster times than brute-forcing).
Hence, I'd try this implementation of your Integer class:
public class Integer {
private int a, b;
private boolean flipped;
public Integer(int _a, int _b){
a = Math.min(_a, _b);
b = Math.max(_a, _b);
flipped = b < a;
}
public void markOff(boolean [] arr){
for(int i = 0; i < arr.length; i++){
if(a <= i && i <= b){
arr[i] = arr[i] || !flipped;
}else{
arr[i] = arr[i] || flipped;
}
}
}
}
So in the above, markOff just checks if each index would appear in the ArrayList you'd create (I'll leave figuring out the boolean logic up to you, but the idea is just to set all the extra elements to true as necessary - so if a new index is covered by the array, you'd mark it off, but you don't un-mark already marked ones.) You can optimize it to not traverse the whole array and look more like your makeList if you want to.
In order to find the minimal set of arrays that would cover up to n, you'd have to do something like the following:
public static int driveSoln(int n, Integer[] covers){
return helper(covers, new boolean[n], 0, 0);
}
private static int helper(Integer[] covers, boolean[] marked, int idx, int used){
boolean done;
for(boolean d: marked) done = done && d;
if(done) return used;
if(idx >= covers.length) return -1;
boolean [] markCopy = marked.clone();
covers[i].markOff(marked);
int dontUse = helper(covers, markCopy, idx + 1, used);
int use = helper(covers, marked, idx + 1, used + 1);
return Math.min(use, dontUse);
}
Intuitively, what I do here is for each inputted cover, chose whether or not to use it and keep looking at the rest. The recursion here "remembers" my choices. I'm guaranteed to (sadly) check all the choices, so this is quite slow, but definitely right. An optimization might be to ignore subsets: if an array only covers items already covered by 1 array, discard it.
I need to use binary search to locate 45.3 in the array. Here's what I have so far.
public class Bsearch {
public static final int NOT_FOUND = -1;
public static int binarySearch(int[] a, int x) {
int low = 0;
int high = a.length - 1;
int mid;
while (low <= high) {
mid = (low + high) / 2;
if (a[mid].compareTo(x) < 0)
low = mid + 1;
else if (a[mid].compareTo(x) > 0)
high = mid - 1;
else
return mid;
}
return NOT_FOUND;
}
public static void main(String[] args) {
int SIZE = 6;
int[] a = new Integer[SIZE] = { 10, -3, 5, 24, 45.3, 10.5 };
System.out.println("45.3 Found" + binarySearch(a, 45.3));
}
}
All my errors seem to be stemming from this area-
int [] a = new Integer [ SIZE ]={ 10,-3,5,24,45.3,10.5 };
System.out.println("45.3 Found" +binarySearch(a, 45.3));
All this is new to me so sorry for any obvious mistakes.
For binary search Data Array should be sorted, and sorted in the right order, but the array you are passing to binarySearch(int[] a, int x) is not sorted so first sort the array and then apply binary search on it.
Also check your logic for binary search, you are comparing middle element with 0 it should be compared with the element to be searched(key)
while(high >= low) {
int middle = (low + high) / 2;
if(data[middle] == key) {
return true;
}
if(data[middle] < key) {
low = middle + 1;
}
if(data[middle] > key) {
high = middle - 1;
}
}
The problem is indeed in this line:
int[] a = new Integer[SIZE] = { 10, -3, 5, 24, 45.3, 10.5 };
There are a number of issues:
You can't assign an Integer[] to an int[] variable. Change it to new int[]
You can't put a floating point number in an array of integers; change your numbers 45.3 and 10.5 to integers.
You have two options in Java: when you create a new array with the new operator, you either specify size of the array, or the contents.
So either:
int[] a = new int[SIZE];
Or
int[] a = new int[] { 10, -3, 5, 24, 45, 10 };
Both will work.
You have to decide whether you want to use primitive types (int) of class wrappers (Integer) and stick to it.
Your method binarySearch takes an int[] as a parameter, but you are using methods (compareTo) that are only available on Integer.
But actually, comparing is much simpler with primitive types:
if (a[mid] < x)
low = mid + 1;
else if (a[mid] > x)
high = mid - 1;
else
return mid;
I'm trying to calculate the total, mean and median of an array thats populated by input received by a textfield. I've managed to work out the total and the mean, I just can't get the median to work. I think the array needs to be sorted before I can do this, but I'm not sure how to do this. Is this the problem, or is there another one that I didn't find? Here is my code:
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.*;
import java.awt.event.*;
public class whileloopq extends Applet implements ActionListener
{
Label label;
TextField input;
int num;
int index;
int[] numArray = new int[20];
int sum;
int total;
double avg;
int median;
public void init ()
{
label = new Label("Enter numbers");
input = new TextField(5);
add(label);
add(input);
input.addActionListener(this);
index = 0;
}
public void actionPerformed (ActionEvent ev)
{
int num = Integer.parseInt(input.getText());
numArray[index] = num;
index++;
if (index == 20)
input.setEnabled(false);
input.setText("");
sum = 0;
for (int i = 0; i < numArray.length; i++)
{
sum += numArray[i];
}
total = sum;
avg = total / index;
median = numArray[numArray.length/2];
repaint();
}
public void paint (Graphics graf)
{
graf.drawString("Total = " + Integer.toString(total), 25, 85);
graf.drawString("Average = " + Double.toString(avg), 25, 100);
graf.drawString("Median = " + Integer.toString(median), 25, 115);
}
}
The Arrays class in Java has a static sort function, which you can invoke with Arrays.sort(numArray).
Arrays.sort(numArray);
double median;
if (numArray.length % 2 == 0)
median = ((double)numArray[numArray.length/2] + (double)numArray[numArray.length/2 - 1])/2;
else
median = (double) numArray[numArray.length/2];
Sorting the array is unnecessary and inefficient. There's a variation of the QuickSort (QuickSelect) algorithm which has an average run time of O(n); if you sort first, you're down to O(n log n). It actually finds the nth smallest item in a list; for a median, you just use n = half the list length. Let's call it quickNth (list, n).
The concept is that to find the nth smallest, choose a 'pivot' value. (Exactly how you choose it isn't critical; if you know the data will be thoroughly random, you can take the first item on the list.)
Split the original list into three smaller lists:
One with values smaller than the pivot.
One with values equal to the pivot.
And one with values greater than the pivot.
You then have three cases:
The "smaller" list has >= n items. In that case, you know that the nth smallest is in that list. Return quickNth(smaller, n).
The smaller list has < n items, but the sum of the lengths of the smaller and equal lists have >= n items. In this case, the nth is equal to any item in the "equal" list; you're done.
n is greater than the sum of the lengths of the smaller and equal lists. In that case, you can essentially skip over those two, and adjust n accordingly. Return quickNth(greater, n - length(smaller) - length(equal)).
Done.
If you're not sure that the data is thoroughly random, you need to be more sophisticated about choosing the pivot. Taking the median of the first value in the list, the last value in the list, and the one midway between the two works pretty well.
If you're very unlucky with your choice of pivots, and you always choose the smallest or highest value as your pivot, this takes O(n^2) time; that's bad. But, it's also very unlikely if you choose your pivot with a decent algorithm.
Sample code:
import java.util.*;
public class Utility {
/****************
* #param coll an ArrayList of Comparable objects
* #return the median of coll
*****************/
public static <T extends Number> double median(ArrayList<T> coll, Comparator<T> comp) {
double result;
int n = coll.size()/2;
if (coll.size() % 2 == 0) // even number of items; find the middle two and average them
result = (nth(coll, n-1, comp).doubleValue() + nth(coll, n, comp).doubleValue()) / 2.0;
else // odd number of items; return the one in the middle
result = nth(coll, n, comp).doubleValue();
return result;
} // median(coll)
/*****************
* #param coll a collection of Comparable objects
* #param n the position of the desired object, using the ordering defined on the list elements
* #return the nth smallest object
*******************/
public static <T> T nth(ArrayList<T> coll, int n, Comparator<T> comp) {
T result, pivot;
ArrayList<T> underPivot = new ArrayList<>(), overPivot = new ArrayList<>(), equalPivot = new ArrayList<>();
// choosing a pivot is a whole topic in itself.
// this implementation uses the simple strategy of grabbing something from the middle of the ArrayList.
pivot = coll.get(n/2);
// split coll into 3 lists based on comparison with the pivot
for (T obj : coll) {
int order = comp.compare(obj, pivot);
if (order < 0) // obj < pivot
underPivot.add(obj);
else if (order > 0) // obj > pivot
overPivot.add(obj);
else // obj = pivot
equalPivot.add(obj);
} // for each obj in coll
// recurse on the appropriate list
if (n < underPivot.size())
result = nth(underPivot, n, comp);
else if (n < underPivot.size() + equalPivot.size()) // equal to pivot; just return it
result = pivot;
else // everything in underPivot and equalPivot is too small. Adjust n accordingly in the recursion.
result = nth(overPivot, n - underPivot.size() - equalPivot.size(), comp);
return result;
} // nth(coll, n)
public static void main (String[] args) {
Comparator<Integer> comp = Comparator.naturalOrder();
Random rnd = new Random();
for (int size = 1; size <= 10; size++) {
ArrayList<Integer> coll = new ArrayList<>(size);
for (int i = 0; i < size; i++)
coll.add(rnd.nextInt(100));
System.out.println("Median of " + coll.toString() + " is " + median(coll, comp));
} // for a range of possible input sizes
} // main(args)
} // Utility
If you want to use any external library here is Apache commons math library using you can calculate the Median.
For more methods and use take look at the API documentation
import org.apache.commons.math3.*;
.....
......
........
//calculate median
public double getMedian(double[] values){
Median median = new Median();
double medianValue = median.evaluate(values);
return medianValue;
}
.......
For more on evaluate method AbstractUnivariateStatistic#evaluate
Update
Calculate in program
Generally, median is calculated using the following two formulas given here
If n is odd then Median (M) = value of ((n + 1)/2)th item term.
If n is even then Median (M) = value of [((n)/2)th item term + ((n)/2 + 1)th item term ]/2
In your program you have numArray, first you need to sort array using Arrays#sort
Arrays.sort(numArray);
int middle = numArray.length/2;
int medianValue = 0; //declare variable
if (numArray.length%2 == 1)
medianValue = numArray[middle];
else
medianValue = (numArray[middle-1] + numArray[middle]) / 2;
Arrays.sort(numArray);
return (numArray[size/2] + numArray[(size-1)/2]) / 2;
Arrays.sort(numArray);
int middle = ((numArray.length) / 2);
if(numArray.length % 2 == 0){
int medianA = numArray[middle];
int medianB = numArray[middle-1];
median = (medianA + medianB) / 2;
} else{
median = numArray[middle + 1];
}
EDIT: I initially had medianB setting to middle+1 in the even length arrays, this was wrong due to arrays starting count at 0. I have updated it to use middle-1 which is correct and should work properly for an array with an even length.
You can find good explanation at https://www.youtube.com/watch?time_continue=23&v=VmogG01IjYc
The idea it to use 2 Heaps viz one max heap and mean heap.
class Heap {
private Queue<Integer> low = new PriorityQueue<>(Comparator.reverseOrder());
private Queue<Integer> high = new PriorityQueue<>();
public void add(int number) {
Queue<Integer> target = low.size() <= high.size() ? low : high;
target.add(number);
balance();
}
private void balance() {
while(!low.isEmpty() && !high.isEmpty() && low.peek() > high.peek()) {
Integer lowHead= low.poll();
Integer highHead = high.poll();
low.add(highHead);
high.add(lowHead);
}
}
public double median() {
if(low.isEmpty() && high.isEmpty()) {
throw new IllegalStateException("Heap is empty");
} else {
return low.size() == high.size() ? (low.peek() + high.peek()) / 2.0 : low.peek();
}
}
}
Try sorting the array first. Then after it's sorted, if the array has an even amount of elements the mean of the middle two is the median, if it has a odd number, the middle element is the median.
Use Arrays.sort and then take the middle element (in case the number n of elements in the array is odd) or take the average of the two middle elements (in case n is even).
public static long median(long[] l)
{
Arrays.sort(l);
int middle = l.length / 2;
if (l.length % 2 == 0)
{
long left = l[middle - 1];
long right = l[middle];
return (left + right) / 2;
}
else
{
return l[middle];
}
}
Here are some examples:
#Test
public void evenTest()
{
long[] l = {
5, 6, 1, 3, 2
};
Assert.assertEquals((3 + 4) / 2, median(l));
}
#Test
public oddTest()
{
long[] l = {
5, 1, 3, 2, 4
};
Assert.assertEquals(3, median(l));
}
And in case your input is a Collection, you might use Google Guava to do something like this:
public static long median(Collection<Long> numbers)
{
return median(Longs.toArray(numbers)); // requires import com.google.common.primitives.Longs;
}
I was looking at the same statistics problems. The approach you are thinking it is good and it will work. (Answer to the sorting has been given)
But in case you are interested in algorithm performance, I think there are a couple of algorithms that have better performance than just sorting the array, one (QuickSelect) is indicated by #bruce-feist's answer and is very well explained.
[Java implementation: https://discuss.leetcode.com/topic/14611/java-quick-select ]
But there is a variation of this algorithm named median of medians, you can find a good explanation on this link:
http://austinrochford.com/posts/2013-10-28-median-of-medians.html
Java implementation of this:
- https://stackoverflow.com/a/27719796/957979
I faced a similar problem yesterday.
I wrote a method with Java generics in order to calculate the median value of every collection of Numbers; you can apply my method to collections of Doubles, Integers, Floats and returns a double. Please consider that my method creates another collection in order to not alter the original one.
I provide also a test, have fun. ;-)
public static <T extends Number & Comparable<T>> double median(Collection<T> numbers){
if(numbers.isEmpty()){
throw new IllegalArgumentException("Cannot compute median on empty collection of numbers");
}
List<T> numbersList = new ArrayList<>(numbers);
Collections.sort(numbersList);
int middle = numbersList.size()/2;
if(numbersList.size() % 2 == 0){
return 0.5 * (numbersList.get(middle).doubleValue() + numbersList.get(middle-1).doubleValue());
} else {
return numbersList.get(middle).doubleValue();
}
}
JUnit test code snippet:
/**
* Test of median method, of class Utils.
*/
#Test
public void testMedian() {
System.out.println("median");
Double expResult = 3.0;
Double result = Utils.median(Arrays.asList(3.0,2.0,1.0,9.0,13.0));
assertEquals(expResult, result);
expResult = 3.5;
result = Utils.median(Arrays.asList(3.0,2.0,1.0,9.0,4.0,13.0));
assertEquals(expResult, result);
}
Usage example (consider the class name is Utils):
List<Integer> intValues = ... //omitted init
Set<Float> floatValues = ... //omitted init
.....
double intListMedian = Utils.median(intValues);
double floatSetMedian = Utils.median(floatValues);
Note: my method works on collections, you can convert arrays of numbers to list of numbers as pointed here
And nobody paying attention when list contains only one element (list.size == 1). All your answers will crash with index out of bound exception, because integer division returns zero (1 / 2 = 0). Correct answer (in Kotlin):
MEDIAN("MEDIAN") {
override fun calculate(values: List<BigDecimal>): BigDecimal? {
if (values.size == 1) {
return values.first()
}
if (values.size > 1) {
val valuesSorted = values.sorted()
val mid = valuesSorted.size / 2
return if (valuesSorted.size % 2 != 0) {
valuesSorted[mid]
} else {
AVERAGE.calculate(listOf(valuesSorted[mid - 1], valuesSorted[mid]))
}
}
return null
}
},
As #Bruce-Feist mentions, for a large number of elements, I'd avoid any solution involving sort if performance is something you are concerned about. A different approach than those suggested in the other answers is Hoare's algorithm to find the k-th smallest of element of n items. This algorithm runs in O(n).
public int findKthSmallest(int[] array, int k)
{
if (array.length < 10)
{
Arrays.sort(array);
return array[k];
}
int start = 0;
int end = array.length - 1;
int x, temp;
int i, j;
while (start < end)
{
x = array[k];
i = start;
j = end;
do
{
while (array[i] < x)
i++;
while (x < array[j])
j--;
if (i <= j)
{
temp = array[i];
array[i] = array[j];
array[j] = temp;
i++;
j--;
}
} while (i <= j);
if (j < k)
start = i;
if (k < i)
end = j;
}
return array[k];
}
And to find the median:
public int median(int[] array)
{
int length = array.length;
if ((length & 1) == 0) // even
return (findKthSmallest(array, array.length / 2) + findKthSmallest(array, array.length / 2 + 1)) / 2;
else // odd
return findKthSmallest(array, array.length / 2);
}
public static int median(int[] arr) {
int median = 0;
java.util.Arrays.sort(arr);
for (int i=0;i<arr.length;i++) {
if (arr.length % 2 == 1) {
median = Math.round(arr[arr.length/2]);
} else {
median = (arr[(arr.length/2)] + arr[(arr.length/2)-1])/2;
}
}
return median;
}
Check out the Arrays.sort methods:
http://docs.oracle.com/javase/6/docs/api/java/util/Arrays.html
You should also really abstract finding the median into its own method, and just return the value to the calling method. This will make testing your code much easier.
public int[] data={31, 29, 47, 48, 23, 30, 21
, 40, 23, 39, 47, 47, 42, 44, 23, 26, 44, 32, 20, 40};
public double median()
{
Arrays.sort(this.data);
double result=0;
int size=this.data.length;
if(size%2==1)
{
result=data[((size-1)/2)+1];
System.out.println(" uneven size : "+result);
}
else
{
int middle_pair_first_index =(size-1)/2;
result=(data[middle_pair_first_index+1]+data[middle_pair_first_index])/2;
System.out.println(" Even size : "+result);
}
return result;
}
package arrays;
public class Arraymidleelement {
static public double middleArrayElement(int [] arr)
{
double mid;
if(arr.length%2==0)
{
mid=((double)arr[arr.length/2]+(double)arr[arr.length/2-1])/2;
return mid;
}
return arr[arr.length/2];
}
public static void main(String[] args) {
int arr[]= {1,2,3,4,5,6};
System.out.println( middleArrayElement(arr));
}
}
I want to convert decimal numbers to binary numbers. I want to store them in an array.
First I need to create an array that has a certain length so that I can store the binary numbers. After that I perform the conversion, here is how I do it:
public class Aufg3 {
public static void main(String[] args) {
int[] test = decToBin(12, getBinArray(12));
for(int i = 0; i < test.length; i++){
System.out.println(test[i]);
}
}
public static int[] getBinArray(int number){
int res = number, length = 0;
while(res != 0){
res /= 2;
length++;
}
return new int[length];
}
public static int[] decToBin(int number, int[] array){
int res = number, k = array.length-1;
while(res != 0){
if(res%2 == 0){
array[k] = 0;
}else{
array[k] = 1;
}
k--;
res /= 2;
}
return array;
}
}
Is there anything to improve? It should print 1100 for input of 12.
Why not just use the toBinaryString method of the Integer class:
System.out.println(Integer.toBinaryString(12))
I assume you want to write your own code -- otherwise this is straightforward to do using methods from the standard Java library.
Some quick comments:
You can get rid of the res temp vars. Work directly on number (remember that Java passes parameters by value).
Shift is more efficient than division (number >>>= 1 instead of number /= 2), although the compiler should be able to optimize this anyway
You can avoid the modulus in decToBin if you just do array[k] = number & 1;
While you are at it, why not call getBinArray from decToBin directly? Then you can call decToBin with only one arg -- the value to convert.
Here is a slightly optimized version of your code:
public static int[] getBinArray(int number) {
int length = 0;
while (number != 0) {
number >>>= 1;
length++;
}
return new int[length];
}
public static int[] decToBin(int number) {
int[] array = getBinArray(number);
int k = array.length-1;
while (number != 0)
{
array[k--] = number & 1;
number >>>= 1;
}
return array;
}
If this isn't homework, no need to do it yourself. The following code should work:
BigInteger bigInt = new BigInteger(number);
String asString = bigInt.toString(2);
There might be more efficient ways, but this is certainly very readable and maintainable.
There are some small things that you can improve:
You should define a "high-level" method that converts an int to an int[]. In the current code you have to mention the 12 two times, which is bad.
You should use a do { ... } while (number != 0) loop. Otherwise the number 0 will be represented by an empty array.
You should use x >>> 1 instead of x / 2, since that handles negative numbers correctly.
If you want to check that your code is correct, write another method that converts back from binary to int. Then you can check that binToDec(decToBin(12, ...)) == 12.
The method getBinArray should not be public, since it is only a helper method. You can either replace the public with private or just remove the public.