Java Code Review: merge sorted lists into one sorted list

I want to combine sorted lists into one list. How is that decision? I believe that it works in O (n) time. Any obvious flaws, inefficiencies or stylistic issues?

I don't really like the idiom of setting a flag for “this is the first iteration” and using it to make sure “lower” is the default. Is there a better way around this?

public static <T extends Comparable<? super T>> List<T> merge(Set<List<T>> lists) {
    List<T> result = new ArrayList<T>();

    int totalSize = 0; // every element in the set
    for (List<T> l : lists) {
        totalSize += l.size();
    }

    boolean first; //awkward
    List<T> lowest = lists.iterator().next(); // the list with the lowest item to add

    while (result.size() < totalSize) { // while we still have something to add
        first = true;

        for (List<T> l : lists) {
            if (! l.isEmpty()) {
                if (first) {
                    lowest = l;
                    first = false;
                }
                else if (l.get(0).compareTo(lowest.get(0)) <= 0) {
                    lowest = l;
                }
            }
        }
        result.add(lowest.get(0));
        lowest.remove(0);
    }
    return result;
}

Note: this is not homework, but it is also not for production code.

+5
source share
5 answers

, , . SortedLists log (n), M log (M) ( M - ).

, , - M log (M).

- M.

, .

public static <T extends Comparable<? super T>> List<T> merge(Set<List<T>> lists) {
    int totalSize = 0; // every element in the set
    for (List<T> l : lists) {
        totalSize += l.size();
    }

    List<T> result = new ArrayList<T>(totalSize);

    List<T> lowest;

    while (result.size() < totalSize) { // while we still have something to add
        lowest = null;

        for (List<T> l : lists) {
            if (! l.isEmpty()) {
                if (lowest == null) {
                    lowest = l;
                } else if (l.get(0).compareTo(lowest.get(0)) <= 0) {
                    lowest = l;
                }
            }
        }

        result.add(lowest.get(0));
        lowest.remove(0);
    }

    return result;
}

, List , lists.get(0), .

+4

, lists ArrayList, lowest.remove(0) , O (n ^ 2).

:

List<T> result = new ArrayList<T>();
for (List<T> list : lists) {
    result.addAll(list);
}
Collections.sort(result);

O (n log n), , .

+8

:

whch , , .

Java PriorityQueue .

+5

, - , , .

- . , . , , @Dathan , O (m n) m n . O (n log (m)), , . -, . , , , . , , , null, .

public static <E extends Comparable<? super E>> List<E> merge(Collection<? extends List<? extends E>> lists) {
    PriorityQueue<CompIterator<E>> queue = new PriorityQueue<CompIterator<E>>();
    for (List<? extends E> list : lists)
        if (!list.isEmpty())
            queue.add(new CompIterator<E>(list.iterator()));

    List<E> merged = new ArrayList<E>();
    while (!queue.isEmpty()) {
        CompIterator<E> next = queue.remove();
        merged.add(next.next());
        if (next.hasNext())
            queue.add(next);
    }
    return merged;
}

private static class CompIterator<E extends Comparable<? super E>> implements Iterator<E>, Comparable<CompIterator<E>> {
    E peekElem;
    Iterator<? extends E> it;

    public CompIterator(Iterator<? extends E> it) {
        this.it = it;
        if (it.hasNext()) peekElem = it.next();
        else peekElem = null;
    }

    @Override
    public boolean hasNext() {
        return peekElem != null;
    }

    @Override
    public E next() {
        E ret = peekElem;
        if (it.hasNext()) peekElem = it.next();
        else peekElem = null;
        return ret;
    }

    @Override
    public void remove() {
        throw new UnsupportedOperationException();
    }

    @Override
    public int compareTo(CompIterator<E> o) {
        if (peekElem == null) return 1;
        else return peekElem.compareTo(o.peekElem);
    }

}

O (log (m)), . O (n log (m) + m) n m . , .

+3

Balus meriton , "" .

There are certain other approaches (for example, setting the minimum value to “magic”), but it seems to me that the “first” (to which I probably give a longer name, but this is pedantic) is the best, because it is very clear. Having a boolean type like “first” is a clear signal that your loop will do something special for the first time. This helps the reader.

Of course, you do not need this if you take the Balus / meriton approach, but this is the situation that arises.

0
source

All Articles