简体   繁体   中英

java method returns null but should not

I've a problem with the following java Class. The sorting algorithm works, but it returns everytime an empty array on the end (the return in the "merge" method). I tried to check the algorithm with a lot of System.out.println() outputs to find the error, but it looks like the algorithm works. Only the last return clears the sorted array and returns an empty array. I don't know why and have no idea how to fix that. Would be nice, if anybody could take a look and give a hint. :)

public final class TestClass {

    private TestClass() {
        System.exit(-1); // not used
    }

    public static <T> T[] mergeSort(final T[] q, final Comparator<T> c) {
        if (size(q) > 1) {
            @SuppressWarnings("unchecked")
            T[] q2 = (T[]) new Object[size(q)];
            split(q, q2);
            T[] left = mergeSort(q, c);
            T[] right = mergeSort(q2, c);
            return merge(left, right, c);
        } else {
            return q;
        }
    }

    private static <T> T[] merge(final T[] q1, final T[] q2, final Comparator<T> c) {
        @SuppressWarnings("unchecked")
        T[] q = (T[]) new Object[size(q1) + size(q2)];

        while (size(q1) > 0 || size(q2) > 0) {
            if (size(q2) == 0 || size(q1) > 0 && c.compare(getElement(q1), getElement(q2)) <= 0) {
                add(q, getElement(q1));
                remove(q1, getElement(q1));
            } else {
                add(q, getElement(q2));
                remove(q2, getElement(q2));
            }
        }
        return q; //returns an empty array on last run?!
    }

    private static <T> void split(T[] q1, T[] q2) {
        while (size(q1) > size(q2)) {
            add(q2, getElement(q1));
            remove(q1, getElement(q1));
        }
    }

    // add element
    private static <T> void add(final T[] q1, T pElement) {
        if (!isFull(q1)) {
            for (int i = 0; i < q1.length; i++) {
                if (q1[i] == null) {
                    q1[i] = pElement;
                    break;
                }
            }
        }
    }

    // remove element
    private static <T> void remove(final T[] q1, T pElement) {
        for (int i = 0; i < q1.length; i++) {
            if (q1[i] == pElement) {
                q1[i] = null;
                break;
            }
        }
    }

    // is full?
    private static <T> boolean isFull(final T[] q1) {
        for (T element : q1) {
            if (element == null) {
                return false;
            }
        }
        return true;
    }

    // is empty?
    private static <T> boolean isEmpty(final T[] q1) {
        for (T element : q1) {
            if (element != null) {
                return false;
            }
        }
        return true;
    }

    // size
    private static <T> int size(final T[] q1) {
        int counter = 0;
        for (T element : q1) {
            if (element != null) {
                counter++;
            }
        }
        return counter;
    }

    // get first element of array
    private static <T> T getElement(final T[] q1) {
        if (!isEmpty(q1)) {
            for (int i = 0; i < q1.length; i++) {
                if (q1[i] != null) {
                    return q1[i];
                }
            }
        }
        return null;
    }
}

There is a junit test, but I get everytime an error because the result is an empty array.

public class Test {

    @Test
    public void testSorting() {
    final Integer[] list = {5, 1, 3, 2, 8, 1, 3, 9, 5, 0};
        TestClass.mergeSort(list, (i, j) -> i - j); 
        assertArrayEquals(new Integer[] {0, 1, 1, 2, 3, 3, 5, 5, 8, 9}, list);
    }
}

Your sorting algorithm works fine, and both merge and mergeSort return the correct results. But neither of them is in-place ! They create new arrays and "empty" the source arrays, setting their elements to null . Thus, your original list contains only null at the end, and the sorted array is in the result of the call to mergeSort , which you never use.

Thus, you just have to re-assign the result of mergeSort back to some variable:

final Integer[] list = {5, 1, 3, 2, 8, 1, 3, 9, 5, 0};
Integer[] res = mergeSort(list, (i, j) -> i - j);
System.out.println(Arrays.asList(list));
// [null, null, null, null, null, null, null, null, null, null]
System.out.println(Arrays.asList(res));
// [0, 1, 1, 2, 3, 3, 5, 5, 8, 9]

If you want to make this in-place , this would be a major re-write. I suggest you start with removing all the new Object[] lines and adding parameters int from, int to to both the sort and merge methods and see where you get from there.

In fact, on closer inspection , Merge Sort seems not to be very in-place friendly, since it is difficult to merge in-place , since the sub-arrays have to remain sorted. If you want to sort in-place, I suggest using Quick Sort .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM