I want to merge two sorted lists of Integers but this is not the general mergesort case because the same number may appear in both lists. (However, each number can only appear once in a particular list.)
The easiest way I've found to do that is (mergeWithSet method):
- Add all numbers from list one to a treeSet
- Add all numbers from list two to the treeSet
- Create a new List from the treeSet
It works but I think the efficiency would be around O(n+m+(n+m)log(n+m)), i.e. O(Nlog(N)) and I think the this problem can be solved in O(n+m) taking advantage of the fact that both lists are already sorted. A quick change in the general case of merge works (mergeWithGet method) but in order to practice Iterators' use, I've written a mergeWithIterator method that only uses Iterators.
The question is:
- mergeWithGet is a neat method. Why is mergeWithIterator so complicated? Am I missing something?
- Should I see a big difference in efficiency for huge lists or in this scenario the three algorithms behave more or less the same?
- Any Java 8 stream solution? Just to check if parallelism works in this case
Thank in advance and any suggestion will be very welcome. The three methods work fine. The code:
import java.util.*;
public class MergeLists {
public static List<Integer> mergeWithIterator(List<Integer> list1, List<Integer> list2) {
List<Integer> sorted = new ArrayList<>();
Iterator<Integer> itList1 = list1.iterator();
Iterator<Integer> itList2 = list2.iterator();
Integer currentList1 = itList1.next();
Integer currentList2 = itList2.next();
while (itList1.hasNext() && itList2.hasNext()) {
if (currentList1 > currentList2) {
sorted.add(currentList2);
currentList2 = itList2.next();
} else if (currentList1 < currentList2) {
sorted.add(currentList1);
currentList1 = itList1.next();
} else {
sorted.add(currentList1);
currentList1 = itList1.next();
currentList2 = itList2.next();
}
}
//one (or both) of the currents have the last number of their list
//Special Case: Both lists have the same size
if (!itList1.hasNext() && !itList2.hasNext()) {
if (currentList1 > currentList2) {
sorted.add(currentList2);
sorted.add(currentList1);
} else if (currentList1 < currentList2) {
sorted.add(currentList1);
sorted.add(currentList2);
} else {
sorted.add(currentList1);
}
return sorted;
}
//General case:One list is longer than the other: we add from the longer till the number is
//greater than the one that is last in the other list, then the last and the rest of the longer list
Iterator<Integer> itLongestList;
Integer lastFromShortest;
Integer lastFromLongest;
if (itList1.hasNext()) {
itLongestList = itList1;
lastFromShortest = currentList2;
lastFromLongest = currentList1;
} else {
itLongestList = itList2;
lastFromShortest = currentList1;
lastFromLongest = currentList2;
}
while (lastFromLongest < lastFromShortest && itLongestList.hasNext()) {
sorted.add(lastFromLongest);
lastFromLongest = itLongestList.next();
}
if (lastFromShortest < lastFromLongest) {
sorted.add(lastFromShortest);
sorted.add(lastFromLongest);
} else if (lastFromShortest > lastFromLongest) {
sorted.add(lastFromLongest);
sorted.add(lastFromShortest);
} else {
sorted.add(lastFromShortest);
}
while (itLongestList.hasNext()) {
sorted.add(itLongestList.next());
}
return sorted;
}
public static List<Integer> mergeWithGet(List<Integer> list1, List<Integer> list2) {
List<Integer> sorted = new ArrayList<>();
int i = 0;
int j = 0;
while (i < list1.size() && j < list2.size()) {
if (list1.get(i) < list2.get(j))
sorted.add(list1.get(i++));
else if (list1.get(i) > list2.get(j)) {
sorted.add(list2.get(j++));
} else {
sorted.add(list1.get(i));
i++;
j++;
}
}
// Store remaining elements of first list
while (i < list1.size())
sorted.add(list1.get(i++));
// Store remaining elements of second list
while (j < list2.size())
sorted.add(list2.get(j++));
return sorted;
}
public static List<Integer> mergeWithSet(List<Integer> list1, List<Integer> list2) {
Set<Integer> sortedSet = new TreeSet<>();
sortedSet.addAll(list1);
sortedSet.addAll(list2);
return new ArrayList<>(sortedSet);
}
public static void main(String[] args) {
List<Integer> list1 = Arrays.asList(-30, 0, 10, 20, 40, 50);
List<Integer> list2 = Arrays.asList(0, 5, 15, 20, 40);
//0, 20 and 40 should appear only once in the result
System.out.println(mergeWithGet(list1, list2));
System.out.println(mergeWithIterator(list1, list2));
System.out.println(mergeWithSet(list1, list2));
}
}
i
list1 = [1]
andlist2 = [1, 1]
. \$\endgroup\$Collection
. \$\endgroup\$