简体   繁体   English

Java 反转链表时出现奇怪的 NullPointerException

[英]Java Weird NullPointerException When Reversing a Linked List

I'm working on a LeetCode problem called " Palindrome Linked List ", where a singly linked list is given, determine if it is a palindrome.我正在研究一个名为“ Palindrome Linked List ”的 LeetCode 问题,其中给出了一个单链表,确定它是否是回文。 For example, if the input is 1->2->2->1, it should output true.例如,如果输入为 1->2->2->1,则应为 output 为真。

I solved it by using extra space (converting the list into an ArrayList), and now I'm trying to solve it by another approach, reversing the 2nd half of list and then compare the two halves .我通过使用额外的空间(将列表转换为 ArrayList)解决了它,现在我试图通过另一种方法来解决它,反转列表的第二半,然后比较两半 Although I might have not implemented the idea in the best way, I expected the code to either work or output a wrong answer (then I could improve the code).虽然我可能没有以最好的方式实现这个想法,但我希望代码能够正常工作,或者 output 是错误的答案(然后我可以改进代码)。 However, a weird NullPointerException happened, and I couldn't figure out why.然而,一个奇怪的 NullPointerException 发生了,我不知道为什么。

My code is shown below, and the input list for testing is 1->2->3 .我的代码如下所示,测试的输入列表是 1->2->3 I also added some prints to help debug.我还添加了一些打印来帮助调试。

// reverse the 2nd half of list and then compare the two halves

class Solution {
    public boolean isPalindrome(ListNode head) {
        int n = 0; // list length
        ListNode p = head;
        while (p != null) { // obtain list length n 
            n++;
            p = p.next;
        }
        p = head;


        int m = 0;
        ListNode prev = null, curr = null, temp = null;
        while (p != null) { // reverse the 2nd half of list
            m++;
            if (m == n/2 + 1) {
                prev = p;
                curr = p.next;
                p = p.next;

                System.out.println(curr.val);
                System.out.println(curr);
                //System.out.println(p);
            }
            else if (m > n/2 + 1) {
                //System.out.println(p);
                System.out.println(curr);
                //System.out.println(curr.val);

                temp = curr.next;
                curr.next = prev;
                prev = curr;
                curr = temp;
                p = p.next;
            }
            else 
                p = p.next;
        }


        int k = 1;
        while (k < n/2 + 1) { // compare the two halves, prev points at the last node
            if (head.val != prev.val)
                return false;
            head = head.next;
            prev = prev.next;
            k++;
        }
        return true;
    }    
}

The output (when input 1->2->3, plus some print statements) is: output (输入1->2->3时,加上一些打印语句)为:

NullPointerException thrown at the line: temp = curr.next; (which is inside the else if)

the code also prints:
3
ListNode@77a567e1
ListNode@77a567e1
null 

curr is referring to the last node, so curr.val is 3. What I don't understand is why the two System.out.println(curr) give different outputs. curr 是指最后一个节点,所以 curr.val 是 3。我不明白为什么两个 System.out.println(curr)给出不同的输出。 Shouldn't curr be referring to the last node? curr 不应该指的是最后一个节点吗? Where does the null in the output come from? output中的null是哪里来的? I think that is the key for why NullPointerException happened there.我认为这是 NullPointerException 发生在那里的关键。

I'm very confused right now, if someone could help me understand what went wrong, I'd really appreciate it.我现在很困惑,如果有人可以帮助我理解出了什么问题,我将非常感激。 Thanks.谢谢。

Edit: Since this is a LeetCode question, the ListNode class is predefined, I don't need to write it myself.编辑:由于这是一个 LeetCode 问题,所以 ListNode class 是预定义的,我不需要自己编写。

Perhaps, you should have implemented your isPalindrome method using LinkedList from Java common Collections using iterator and descendingIterator :也许,您应该使用iteratordescendingIterator使用 Java common Collections 中的LinkedList实现您的isPalindrome方法:

LinkedList<Integer> list = new LinkedList<>(Arrays.asList(1, 2, 3));
System.out.printf("list: %s palindrome: %s%n", list,  isPalindrome(list));
// ...

  public boolean isPalindrome(LinkedList<Integer> list) {
    Iterator<Integer> directIterator = list.iterator();
    Iterator<Integer> reverseIterator = list.descendingIterator();
    int count = list.size() / 2;
    while (directIterator.hasNext() && reverseIterator.hasNext() && count-- > 0) {
      if (directIterator.next().intValue() != reverseIterator.next().intValue()) {
        return false;
      }
    }
    return true;
  }

Update: a solution for the requested single-linked list using a reversed list:更新:使用反向列表的请求单链表的解决方案:

    public boolean isPalindrome(ListNode head) {
        // empty and single element list is palindrome
        if (null == head || null == head.next) {
            return true;
        }
        // build reverse linked list
        ListNode curr = head;
        ListNode tail = new ListNode(curr.val);
        tail.next = null;
        ListNode prev = null;
        int size = 1;
        while (null != curr.next) {
            prev = tail;
            curr = curr.next;
            tail = new ListNode(curr.val);
            tail.next = prev;
            size++;
        }
        // move both from head and from tail to the middle element
        int half = size / 2;
        curr = head;
        prev = tail;
        while (null != curr && null != prev && half-- > 0) {
            if (curr.val != prev.val) {
                return false;
            }
            curr = curr.next;
            prev = prev.next;
        }
        return true;
    }

Your given input is 1->2->3 so your n is 3.你给定的输入是 1->2->3 所以你的 n 是 3。

Before Entering the while loop you have initialized在进入你已经初始化的while循环之前

curr = null;当前= null;

Your program enters while loop你的程序进入while循环

First Iteration第一次迭代

  • m++;米++; value of m=1 m=1 的值

  • 1 == 3/2+1 false so enter else if again false so it goes to else 1 == 3/2+1 false 所以输入 else if 再次为 false 所以转到 else

values after 1st iteration第一次迭代后的值

m = 1;米 = 1; curr=null prev=null and p=2(points to node value 2) curr=null prev=null 和 p=2(指向节点值 2)

Second iteration第二次迭代

  • m=2 m=2

  • 2 == 3/2+1 true goes inside if 2 == 3/2+1 true 进入 if

  • prev = 1, curr & p = 3(node with value 3) prev = 1, curr & p = 3(值为 3 的节点)

  • Print curr.val which is 3 and curr which prints "ListNode@77a567e1"打印 curr.val 为 3 和 curr 打印“ListNode@77a567e1”

Values after 2nd iteration第二次迭代后的值

m = 2;米 = 2; prev=2, curr & p=3(node with value 3) prev=2, curr & p=3(值为 3 的节点)

Third Iteration第三次迭代

  • m=3米=3

  • 3>3/2+1 true so enters else if 3>3/2+1 true 所以进入 else if

  • Print curr prints "ListNode@77a567e1"打印当前打印“ListNode@77a567e1”

  • temp = curr.next as curr is 3 its next is null temp = curr.next 因为 curr 是 3 它的下一个是 null

  • curr = temp;当前=温度; as temp = null curr is null因为 temp = null curr 是 null

Forth Iteration第四次迭代

so as curr is null on forth iteration it prints null and throws null pointer exception.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM