-2

I wrote a code in java for school to compute the median of an array. We have some test cases for this. The first column is the input, the second the expected and the third the actual output. Is anything special on the case that does not work? I've worked so long on this code now and slowly but surely i am getting frustrated. I really don't know where or why my code does not work in this specific scenario. the code is the following:

/**
 * This class calculates the median of a list to use it in quicksort for a runtime of O(log(n));
 * @author Niklas
 *
 */
public class Median {

    /**
     * The position i.
     */
    private static int positionI = -1;

    /**
     * a help array for the quicksort algorithm.
     */
    private static int[] quicksortArray;

    /**
     * Computes and retrieves the lower median of the given array of numbers using
     * the Median algorithm presented in the lecture.
     *
     * @param input numbers.
     * @return the lower median.
     * @throw IllegalArgumentException if the array is {@code null} or empty.
     */
    public static int lowerMedian(int[] numbers) {

        if (numbers.length == 0 || numbers == null) {
            throw new IllegalArgumentException("Array must contain values");
        }
        // avoiding that positionI is part of the recursion
        if (positionI == -1) {
            positionI = (int) Math.floor((double) ((numbers.length + 1) / 2));
        }

        // Step 1: dividing the list into groups.

        int[] medians = new int[(int) Math.ceil((float) numbers.length / 5)];
        int[] subArray = new int[5];
        int positionForMedianArray = 0;

        // the end case that the array is < 5.
        if (numbers.length <= 5) {
            sortArray(numbers);
            if (positionI <= numbers.length) {
                return numbers[positionI - 1];
            }
            return numbers.length % 2 == 0 ? numbers[(numbers.length / 2) - 1] : numbers[numbers.length / 2];
        }

        for (int i = 0; i < numbers.length; i += 5) {
            if (numbers.length < i + 5) {
                subArray = Arrays.copyOfRange(numbers, i, numbers.length);
            } else {
                subArray = Arrays.copyOfRange(numbers, i, i + 5);
            }
            // Step 2: calculate the median of each subArray.
            sortArray(subArray);
            medians[positionForMedianArray] = subArray.length % 2 == 0 ? subArray[subArray.length / 2 - 1]
                    : subArray[subArray.length / 2];
            positionForMedianArray += 1;

        }

        // Step 3: calculate x recursively
        int x = lowerMedian(medians);

        // Step 4: partioniate the lists.

        // computing how big the arrays have to be because arraylists doesnt work as
        // good in this code.
        int countS = 0;
        int countG = 0;
        for (int i = 0; i < numbers.length; i++) {
            if (numbers[i] < x) {
                countS += 1;
            } else if (numbers[i] > x) {
                countG += 1;
            }
        }

        // creating the arrays with the right size.
        int[] smaller = new int[countS];
        int[] greater = new int[countG];

        countS = 0;
        countG = 0;

        // filling the Arrays (L1 and L2).
        for (int i = 0; i < numbers.length; i++) {
            if (numbers[i] < x) {
                smaller[countS] = numbers[i];
                countS += 1;
            } else if (numbers[i] > x) {
                greater[countG] = numbers[i];
                countG += 1;
            }
        }

        int k = smaller.length + 1;

        // for testing
//      System.out.println("\nnumbers: " + Arrays.toString(numbers));
//      System.out.println("position i: " + positionI);
//      System.out.println("SubArray " + (positionForMedianArray) + ": " + Arrays.toString(subArray));
//      System.out.println("Median Array im Durchlauf " + (positionForMedianArray) + ": " + Arrays.toString(medians));
//      System.out.println("x: " + x);
//      System.out.println("L1: " + Arrays.toString(smaller));
//      System.out.println("L2: " + Arrays.toString(greater));
//      System.out.println("Position k: " + k);

        if (positionI < k) {
            return lowerMedian(smaller);
        } else if (positionI > k) {
            positionI -= k;
            return lowerMedian(greater);
        }
        return x;

    }
    /**
     * Sorts the given array in an inefficent way.
     * 
     * @param numbers the array to sort.
     */
    private static void sortArray(int[] numbers) {
        for (int i = 0; i < numbers.length; i++) {
            for (int j = 0; j < numbers.length; j++) {
                if (numbers[i] < numbers[j]) {
                    int tempVar = numbers[j];
                    numbers[j] = numbers[i];
                    numbers[i] = tempVar;

                }

            }
        }
    }

I would appreciate any kind of help!

Boorow
  • 1
  • 1
    The best thing you can do is to step through the code with a debugger or add `System.out.println(...);` statements throughout your code (inside the loops, before and after each loop etc) so you can see exactly where the breakdown occurs, and why you get the incorrect result. – sorifiend May 25 '22 at 00:38
  • @sorifiend i tried this, you even see in the prints in the code^^ but it doesn't really helps me. – Boorow May 25 '22 at 00:44
  • @ScaryWombat What do you mean there? those are all the numbers which are greater than x, if zero is greater it should also be added. – Boorow May 25 '22 at 00:45
  • Please provide some more details. What is the actual task? Do you need to use recursion for this? Why does the `subArray` have a size of 5, and why is `medians` size `numbers.length / 5`? What is the deal with the fixed size of 5 in your code, what does this achieve? By only processing small parts at a time in limited sizes you will struggle to ever get the real medium number. The normal way to do this is to first sort the array however you wish `Arrays.sort(yourArray);`, then simply return the middle number rounded down in your case `return yourArray[Math.floor(yourArray.length/2)];` – sorifiend May 25 '22 at 01:49
  • Your code returns a different result if the same array is passed to it but in a different order, this highlights the point that you need to first sort the array before you attempt to find the median. – sorifiend May 25 '22 at 01:56

1 Answers1

1

I'm not sure why your approach for calculating low median is so complicated. All you need to do is sort the list of number and if the list has odd number of values then just return value at <array length> / 2 and if the list has even number of values then return value at (<array_length> / 2) - 1. Regarding the sorting the input list, you can either implement your own quicksort algorithm or use Arrays.sort. Below is a potential approach to calculate lower median using Java built-in sort method.

    public static int lowerMedian(int[] numbers) {
        Arrays.sort(numbers, 0, numbers.length);
        int length = numbers.length;
        if (length == 0) {
            return 0;
        } else if (length % 2 == 0) {
            return numbers[(length / 2) - 1];
        } else {
            return numbers[length / 2];
        }
    }
tax evader
  • 2,082
  • 1
  • 7
  • 9