我需要在java中合并两个字符串列表,我不太确定最好的方法。我必须使用迭代器和compareTo()方法。例如......
示例:L1:A,B,C,D L2:B,D,F,G结果:A,B,B,C,D,D,F,G
我可以假设输入列表已经排序,我不能使用contains()方法。我有一些初步检查但是while循环是我坚持的。
public static ListADT<String> merge(ListADT<String> L1,ListADT<String> L2) throws BadListException {
ListADT<String> L3 = new ArrayList<String>;
if(L1 == null || L2 == null) {
throw new BadListException();
}
Iterator<String> itr1 = new L1.iterator();
Iterator<String> itr2 = new L2.iterator();
if(L1.size() == 0 && L2.size() == 0) {
return L3;
}
if(L1.size() == 0 && L2.size() != 0) {
for(int i = 0; i < L2.size(); i++) {
return L3.add(L2.get(i));
}
}
if(L2.size() == 0 && L1.size() != 0) {
for(int i = 0; i < L1.size(); i++) {
return L3.add(L1.get(i));
}
}
while(itr1.hasNext() || irt2.hasNext()) {
//merge the lists here?
}
}
任何帮助都将不胜感激。
答案 0 :(得分:4)
如果你只是使用变量来保存每个迭代器的当前值,这是相当简单的。此解决方案假设您的列表不包含null
,但由于列表已排序,因此添加空值处理并不困难。
package com.example;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
public class IteratorMerge {
/**
* @param args
*/
public static void main(String[] args) {
List<String> list1 = Arrays.asList(new String[]{"A", "B", "C", "D"});
List<String> list2 = Arrays.asList(new String[]{"B", "D", "F", "G"});
System.out.println(merge(list1, list2));
}
public static List<String> merge(List<String> L1,List<String> L2) {
List<String> L3 = new ArrayList<String>();
Iterator<String> it1 = L1.iterator();
Iterator<String> it2 = L2.iterator();
String s1 = it1.hasNext() ? it1.next() : null;
String s2 = it2.hasNext() ? it2.next() : null;
while (s1 != null && s2 != null) {
if (s1.compareTo(s2) < 0) { // s1 comes before s2
L3.add(s1);
s1 = it1.hasNext() ? it1.next() : null;
}
else { // s1 and s2 are equal, or s2 comes before s1
L3.add(s2);
s2 = it2.hasNext() ? it2.next() : null;
}
}
// There is still at least one element from one of the lists which has not been added
if (s1 != null) {
L3.add(s1);
while (it1.hasNext()) {
L3.add(it1.next());
}
}
else if (s2 != null) {
L3.add(s2);
while (it2.hasNext()) {
L3.add(it2.next());
}
}
return L3;
}
}
答案 1 :(得分:2)
这是基本算法的一些伪代码:
while(itr1 && itr2)
{
if(itr1 value < it2 value)
add itr1 to list
increment itr1
else
add itr2 to list
increment itr2
}
check if itr1 or itr2 still have more elements
while itr1 or itr2 has more elements, add those elements to the list
我们知道列表是排序的,因此在每个阶段,我们只需从每个列表中获取最小元素并将其添加到合并列表中。如果最后一个迭代器耗尽而另一个迭代器耗尽,那么我们可以简单地遍历仍然具有元素的迭代器,将每个元素依次附加到合并列表。
正如您所见,使用Java中的迭代器执行此操作有点痛苦,因为next()
删除了元素。解决此问题的一种方法是使用两个Queue
s,每个迭代器一个,用于存储调用next()
的值。然后,您需要比较每个队列的头部,将最小值添加到合并列表,然后将其从相应的Queue
中删除。
答案 2 :(得分:2)
正如您所发现的,使用迭代器进行合并有点痛苦。让我们明确说明原因:
Iterator#next()
将这些 inspect 和 advance 操作捆绑到一个操作中,因此如果不同时检查这两个序列的头部,则无法进行检查。< / LI>
你需要的是一种在Iterator
中第一个元素偷看而不推进它的方法。如果你有这种能力,那么合并将类似于:
public <T extends Comparable<T>> List<T> merge(Iterator<T> it1, Iterator<T> it2) {
PeekableIterator<T> seq1 = new PeekableIterator<T>(it1);
PeekableIterator<T> seq2 = new PeekableIterator<T>(it2);
List<T> merged = new ArrayList<T>();
while (seq1.hasNext() && seq2.hasNext()) {
if (seq1.peekNext().compareTo(seq2.peekNext()) < 0) {
merged.add(seq1.next());
} else {
merged.add(seq2.next());
}
}
while (seq1.hasNext()) {
merged.add(seq1.next());
}
while (seq2.hasNext()) {
merged.add(seq2.next());
}
return merged;
}
事实证明,创建此PeekableIterator
并不困难!你只需要跟踪你当前是否有一个偷看的元素,以及那个元素是什么。
public class PeekableIterator<T> implements Iterator<T> {
private final Iterator<T> backing;
private boolean havePeek = false;
private T peek;
public PeekableIterator(Iterator<T> backing) {
this.backing = backing;
}
@Override
public boolean hasNext() {
return havePeek || backing.hasNext();
}
@Override
public T next() {
if (havePeek) {
havePeek = false;
return peek;
} else {
return backing.next();
}
}
public T peekNext() {
if (!havePeek) {
peek = backing.next();
havePeek = true;
}
return peek;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
修改强>
我没有注意到上面的评论引用了Google的Guava库中的PeekingIterator
,这与此处的PeekableIterator
大致相同。如果您可以访问第三方库,这肯定比滚动自己更好。
答案 3 :(得分:0)
不要尝试管理空列表与非空列表的合并作为特殊情况,只需循环直到至少有一个迭代器有效并直接在那里工作:
public static ListADT<String> merge(ListADT<String> L1,ListADT<String> L2) throws BadListException {
ListADT<String> L3 = new ArrayList<String>;
Iterator<String> itr1 = new L1.iterator(), itr2 = new L2.iterator();
while (itr1.hasNext() || itr2.hasNext()) {
if (!itr1.hasNext())
L3.add(itr2.next());
else if (!itr2.hasNext())
L3.add(itr1.next());
else {
String s1 = peek from itr1
String s2 = peek from itr2;
if (s1.compareTo(s2) < 0) {
L3.add(itr1.next());
L3.add(itr2.next());
}
else {
L3.add(itr2.next());
L3.add(itr1.next())
}
}
}
}
答案 4 :(得分:0)
公共类MergeIterator {
public static void main(String[] args) {
List<String> s1 = new ArrayList<String>();
s1.add("a");
s1.add("z");
s1.add("b");
s1.add("k");
s1.add("c");
Collections.sort(s1);
List<String> s2 = new ArrayList<String>();
s2.add("p");
s2.add("a");
s2.add("d");
s2.add("n");
s2.add("m");
Collections.sort(s2);
Iterator<String> it1 = s1.iterator();
// sortIterator(it1);
Iterator<String> it2 = s2.iterator();
System.out.println();
combine(it1, it2);
}
private static Iterator<String> combine(Iterator<String> it1,
Iterator<String> it2) {
Iterator<String> it3 = null;
List<String> l1 = new ArrayList<>();
String s1 = null, s2 = null;
while (it1.hasNext() || it2.hasNext()) { //line 1
s1 = (s1 == null ? (it1.hasNext() ? it1.next() : null) : s1); //line 2
s2 = (s2 == null ? (it2.hasNext() ? it2.next() : null) : s2); // line 3
if (s1 != null && s1.compareTo(s2) < 0) { // line 4
l1.add(s1);
s1 = null;
} else {
l1.add(s2);
s2 = null;
}
}
it3 = l1.iterator();
return it3;
}
}