【问题标题】:Java ArrayList Iterator next() not working as intendedJava ArrayList Iterator next() 未按预期工作
【发布时间】:2014-05-18 00:55:16
【问题描述】:

我正在尝试创建一种算法来确定一个数组列表 (s1) 是否是另一个数组列表 (s2) 的子序列。第一个列表中的元素都需要在第二个列表中,并且顺序必须相同。所以 s1 是 s2 的子序列,但 s1 不是 s2 的子序列。我需要使用迭代器来遍历每个列表,并且我应该只遍历每个列表一次(因为它必须按照相同的顺序)。我似乎对 next() 变得无效有疑问?什么会导致这个/我该如何解决这个问题? 我目前拥有的代码似乎可以正常工作,但不会转到第一个数组列表中的下一个元素。

import dataStructures.*;

public class Subsequence2
{
    public static void main(String[] args)
   {
       ArrayList<Character> s1 = new ArrayList<Character>();
       s1.add('n');
       s1.add('p');
       s1.add('a');

       ArrayList<Character> s2 = new ArrayList<Character>();
       s2.add('a');
       s2.add('n');
       s2.add('b');
       s2.add('p');
       s2.add('c');
       s2.add('a');

       Subsequence2 one = new Subsequence2();
       System.out.print("S1 is a subsequence of S2 is a ");      
       System.out.print(one.subSequence(s1, s2));
       System.out.print(" statment.");
} //end main

public static <T> boolean subSequence(ArrayList<T> s1, ArrayList<T> s2) 
{
 //if s1 is empty or if s1 and s2 are empty it is a subsequence
    if(s1.isEmpty() || (s1.isEmpty() && s2.isEmpty())) 
    {
        return true;
    }   
  //if s2 is empty and s1 is not is is not a subsequence.
    else if(s2.isEmpty())
    {
       return false;
    }   
    else
    {
        int s1Count = 0; //count items matched
        Iterator<T> itr1 = s1.iterator();
        Iterator<T> itr2 = s2.iterator();
        while(itr1.hasNext())
     //for(Iterator<T> itr1 = s1.iterator(); itr1.hasNext();) //traverse s1
        {
            T c1 = itr1.getCurrent();
            itr1.next(); //go to next element of s1
            while(itr2.hasNext()) //traverse s2
            {
                T c2 = itr2.getCurrent();
//if items are equal check the next item and add 1 to count of items matched
               if(c1.equals(c2))
               {
                  itr2.next();
                  ++s1Count;
                  //used for testing- just want to see what index it is pulling
                  System.out.print("s1 index " + s1.indexOf(c1) + " s2 index " + s2.indexOf(c2) + " \n" + c1 + " "  + c2 + "\n");
               }
    //if it didn't match, check next element            
               else
               {
                   itr2.next();
               }
               if(s1Count == s1.size()) //if match count is == to s1 size, it is a subsequence
               {
                  return true;
               }
            } // end itr2 while
         } //end for itr1
      } //end else not empty
      return false; 
   } //end subSequence method
 }//end class

【问题讨论】:

  • 我认为您使用 while(itr2.hasNext()) 的方式有误。这个循环将一直持续到结束,而外循环不会进入下一次迭代。
  • 我还没有仔细看,但请注意if(s1.isEmpty() || (s1.isEmpty() &amp;&amp; s2.isEmpty()) 仅相当于if(s1.isEmpty())。如果s1 为空,则整个条件短路到true(甚至没有评估|| (s1.isEmpty() &amp; s2.isEmpty()) 位)。如果s1 不为空,则将评估第二部分,但始终评估为false,因为它本质上是(false &amp;&amp; s2.isEmpty())(因为我们知道s1.isEmpty() 是假的)。
  • "所以 s1 是 s2 的子序列,但 s1 不是 s2 的子序列。" ?我没有得到这个......是我还是它自相矛盾?
  • @yshavit - 为什么我需要重新打开 s1 迭代器才能从头开始比较?我不想重复一遍
  • @yshavit - 这绝对是一个子序列。 Karen 真的不想打开一个新的 s1 迭代器。

标签: java algorithm arraylist iterator


【解决方案1】:

内循环的条件不应该只是itr2.hasNext()。只要itr2.hasNext() 并且下一项与itr1 的当前项不同,您就希望内部循环进行迭代。一旦找到(在itr2 内)itr1 的当前项,您就想停止迭代内部循环,并返回itr1 中的下一项。

public static <T> boolean subSequence(ArrayList<T> s1, ArrayList<T> s2) {
    Iterator<T> itr1 = s1.iterator();
    Iterator<T> itr2 = s2.iterator();

    while (itr1.hasNext()) {
        T itemFrom1 = itr1.next();
        T itemFrom2;
        do {
            if( ! itr2.hasNext()){
                return false;
            }
            itemFrom2 = itr2.next();
        } while( ! itemFrom1.equals(itemFrom2));
    }
    return true;    
}

基本上这里发生的情况是,虽然我们仍在迭代 itr1,但如果我们用完了 itr2 中的元素,那么我们仍然有 itr1 中的东西要匹配,所以它不是子序列.但只要我们继续在itr2 中找到东西,我们就会继续前进。每当我们在 itr2 中找到与我们在 itr1 中寻找的内容相匹配的内容时,就该进入外循环中的下一步了。

【讨论】:

  • 这就是我想要做的......显然这不是我正在做的。这是我第一次使用迭代器和列表,请原谅我的无知。你如何建议我可以修复它来做到这一点?我尝试将while itr2.hasNext() 放在不同的地方,但最终都回到 next() 似乎不起作用(我认为它应该)。
  • 好的,我会在我的答案中添加一些代码。给我20分钟左右。
  • 我现在感觉好傻。经过几个小时的工作然后来到你们这里,我才意识到我正在使用的迭代器的 next 是 void-public void next(); 这就是为什么我尝试 next() 的任何东西都是 void 类型。
  • 在使用我最初发布的列表进行测试时,似乎每次都从 s2 的开头开始。虽然它按预期工作,但如果您要求它获取 indexOf() c1 和 c2,它会说 indexOf(c1) 中匹配的“a”为 2,而 indexOf(c2) 为 0 -应该是 index 6. 有趣的是,如果你去掉最后一个“a”,它仍然是假的(应该如此)。为什么它会拉索引 0 呢?
  • 对不起,我不明白你在问什么。您是说它在做正确的事情,但不是按照您期望的方式?大概您正在使用调试器逐步执行此操作来告诉您?它实际上会拉出s2 的每个元素,直到找到s2 的最后一个字符——它只会将它们与内部循环底部的s1 进行比较。
【解决方案2】:

您也可以使用Collections.indexOfSubList(List&lt;?&gt; source, List&lt;?&gt; target)java docs

【讨论】:

  • 虽然这看起来确实更有效率,但我不能使用集合。我需要使用 2 个 ArrayList 和迭代器。
  • 这将寻找一个子字符串,而不是通常的子序列——所以这不是 OP 所要求的。 (我在上面的 cmets 中犯了同样的错误。:))
猜你喜欢
  • 2021-10-31
  • 2018-08-26
  • 1970-01-01
  • 2019-05-25
  • 2011-02-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多