【发布时间】:2017-09-27 10:14:10
【问题描述】:
我想将已排序的列表合并为一个列表。这个解决方案如何?我相信它在 O(n) 时间内运行。有任何明显的缺陷、效率低下或风格问题吗?
我不太喜欢为“这是第一次迭代”设置标志并使用它来确保“最低”具有默认值的习惯用法。有没有更好的解决方法?
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;
}
注意:这不是家庭作业,但也不适用于生产代码。
【问题讨论】:
-
我认为您的实现很好,但请注意算法复杂性:假设输入列表数量恒定,则为 O(n)。但是由于您的方法可以处理任意数量的输入列表,因此运行时间为 O(Mn) - 您必须考虑可变数量的列表。如果 M > log2(n)+1(我认为),那么简单地连接所有列表并对其进行归并排序实际上会更快,这需要 O(nlog2(n))。这种情况不太可能经常发生,但值得注意。
-
这是标准的合并排序代码。您可能可以在 google.com/codesearch#search/&q=merge%5C%20sort&type=cs 找到优化循环的方法的灵感。你不应该需要那个“第一个”布尔值。
-
@Rosarch:我建议不要删除任何东西——正如已经说过的那样,
remove(0)对ArrayList来说是一场灾难,但对于任何List来说,它都需要不必要的时间。维护Set<Iterator>(或一组索引以获得最大速度)应该会更好。既然 Java 有 TimSort,那么简单地连接列表并调用排序可能会更好。 -
破坏性输入。
-
这个问题似乎跑题了,因为它要求进行代码审查,应该在Code Review