回文检查抛出无限循环使用迭代器和链表集合

问题描述

我正在尝试编写一种方法来确定字符串类型的单向链表是否为回文。

想法是将后半部分复制到堆栈中,然后使用迭代器弹出堆栈中的元素并检查它们是否与从 0 到单向链表的一半左右的元素相同。

但是我的迭代器方法抛出了一个无限循环:

public static boolean ispalindrome(LinkedList<String> list,Stack<String> stack ) {
    int halfList = (int) Math.ceil(list.size()/2);   // we get half the list size,then round up in case it´s odd
    // testing: System.out.println("half of size is " + halfList);`
    
    // copy elements of sll into the stack (push them in) after reaching the midpoint
    int count = 0;
    boolean isIt = true;
    
    Iterator<String> itr = list.iterator();  
    Iterator<String> itr2 = list.iterator();  
    
    System.out.println("\n i print too! ");
    
    // CHECK!! Node head = list.element();
    
    // LOOP: traverse through sll and add the second half to the stack (push)
    // if even # of elements
    if ( list.size() % 1 == 0 ) {
        System.out.println("\n me too! ");
        while ( itr.hasNext() ) {
            String currentString = itr.next();      // this throws an exception in thread empty stack exception
            count ++;
            if ( count == halfList ) stack.push(list.element());
            // THIS IS THE INFINITE LOOP
            System.out.println("\n me three! ");
        }
    }
    
    // else,if odd # of elements
    else {
        while ( itr.hasNext() ) {
            count ++;
            if ( count == halfList -1 ) stack.push(list.element());
        }
    }
    
    // Now we compare the first half of the sll to the stack (pop off elements)
    // even
    if ( list.size() % 1 == 0 ) {       
        while ( itr2.hasNext() ) {
            count ++;
            if ( count == halfList +1 ) break;
            int compared = stack.pop().compareto(list.element());
            if ( compared != 0) isIt = false;     // if when comparing the two elements,they aren´t similar,palindrome is false
        }
    }   
    // odd
    else {
        while ( itr2.hasNext() ) {
            count ++;
            if ( count == halfList ) break;
            int compared = stack.pop().compareto(list.element());
            if ( compared != 0) isIt = false;
        }
    }

    return isIt;
}

我做错了什么?

解决方法

有很多问题:

  • list.size() % 1 == 0 不检查大小是否偶数。正确的检查是 % 2
  • 堆栈异常不能出现在您放置该注释的行上。它发生在您拥有 stack.pop() 的代码下方。出现此异常的原因是您尝试从没有更多元素的堆栈中弹出一个元素。
  • 在您放置该评论的地方不会发生无限循环。它发生在您在代码中的任何其他循环中:在那里您永远不会调用 itr.next()itr2.next(),因此您将无限循环到达那里。
  • 堆栈永远不会被压入超过 1 个值。这是因为您有一个严格的相等条件,该条件在迭代期间只为真一次。这不是您想要的:您希望列表的一半最终出现在堆栈中。这也是您收到堆栈错误的原因:您的代码的后半部分期望堆栈上有足够的项目。
  • push(list.element()) 总是将 第一个 列表值推入堆栈,而不是当前迭代的值。这应该是 push(currentString)
  • count ++; 被放置在循环中一个不直观的地方。如果将该行移动为循环中的最后一条语句,则更有意义。
  • if ( count 语句都是错误的。如果您将 count ++ 移至最后一个语句,则此 if 应为偶数情况为 if ( count >= halfList ),而为奇数情况为 if ( count > halfList )。当然,如果调整 halfList 会更容易,这样您就可以平等地处理奇数和偶数情况。
  • 您的代码的第二部分没有重置计数器,而是继续使用 count ++。这将使 if ( count == halfList ) 永远不会为真,因此这也是 stack.pop() 最终会引发异常的另一个原因。要么您应该在开始第二部分之前重置计数器(使用 count = 0;),或者更好的是,您应该检查堆栈是否为空,然后退出循环。
  • 您的代码的后半部分不需要区分奇数或偶数。
  • 与其将 isIt 设置为 false,不如立即使用 return false 退出 函数,因为继续迭代没有进一步的好处。立>
  • 该函数不应将堆栈作为参数:您总是希望从一个空堆栈开始,因此这应该是一个局部变量,而不是一个参数。
  • 对已经是 Math.ceil 的结果执行 int 是没有用的。当两个参数都是 int 时,除法会产生 int。所以要向上舍入,在除法之前加 1:(list.size()+1) / 2
  • 避免代码重复

当您调试代码时,这些问题中的大多数都很明显。将打印行与“我在这里”放在一起并没有太大帮助。更好的是打印变量的值,或者在检查变量的同时使用良好的调试器单步调试代码。如果您这样做了,您就会发现上面列出的许多问题。

以下是已解决上述问题的代码版本:

public static boolean isPalindrome(LinkedList<String> list) {
    Stack<String> stack = new Stack<String>(); 
    int halfList = (list.size()+1) / 2; // round upwards
    Iterator<String> itr = list.iterator(); 
    
    while (halfList-- > 0) itr.next(); // skip first half of list
    while ( itr.hasNext() ) stack.push(itr.next()); // flush rest unto stack

    Iterator<String> itr2 = list.iterator();  
    while ( itr2.hasNext() && !stack.empty()) { // check that stack is not empty
        if (stack.pop().compareTo(itr2.next()) != 0) return false; // no need to continue
    }
    
    return true;
}