指针返回

时间:2017-01-14 02:50:11

标签: c++ linked-list

我正在解决编码挑战。在这个挑战中,我们将给出两个链表(2 - > 4 - > 3)和(5 - > - > - > 4)并且我们必须返回它们的添加结果(7 - > 0 - > 8)。

虽然我确实解决了这个问题,但我在Google上发现了一个更好的版本:

ListNode *addTwoNumbers(ListNode *l1, ListNode *l2) {
    ListNode preHead(0), *p = &preHead;
    int extra = 0;
    while (l1 || l2 || extra) {
        int sum = (l1 ? l1->val : 0) + (l2 ? l2->val : 0) + extra;
        extra = sum / 10;
        p->next = new ListNode(sum % 10);
        p = p->next;
        l1 = l1 ? l1->next : l1;
        l2 = l2 ? l2->next : l2;
    }
    return preHead.next;
}

但是,我不理解步骤ListNode preHead(0), *p = &preHead;preHead的地址存储在指针变量p中。换句话说,p指向preHead。那么,为什么preHead.next最终会被退回?请注意,此代码会编译并返回预期的输出。

感谢您的帮助!

3 个答案:

答案 0 :(得分:1)

我喜欢称它为虚拟节点模式。用户将构建一个未使用的节点,以便更容易实现插入和查找。正如您在函数中看到的那样,p已经指向一个有效的节点,因此无需检查p是否为NULL并将其设置为此节点是的,我们只是使用p->next附加一个节点。这是p的起始值为NULL的替代代码:

ListNode* p = nullptr;
ListNode* tail;
while (l1 || l2 || extra) {
    //int sum = (l1 ? l1->val : 0) + (l2 ? l2->val : 0) + extra;
    //extra = sum / 10;
    if (p != nullptr) {
        tail->next = new ListNode(sum % 10);
        tail = tail->next;
    } else {
        tail = p = new ListNode(sum % 10);
    }
    //l1 = l1 ? l1->next : l1;
    //l2 = l2 ? l2->next : l2;
}
return p;

我们必须保留一个指向列表末尾的额外指针,以便我们知道在每次迭代时插入的位置。我们必须确保p在第一次插入的情况下不是空指针。

返回preHead.next的原因是因为preHead.next是插入开始的位置(它是我们想要返回的实际链接列表的头部)。

答案 1 :(得分:0)

以下一行:

p->next =new ListNode(sum % 10);

分配返回的新节点。

在循环的第一次迭代中,*ppreHead相同。稍后的迭代移动p,但不要使preHead无效,并且指向添加的第一个新元素。

答案 2 :(得分:0)

  

那么,为什么最后会返回preHead.next

因为addTwoNumbers返回指针但preHead是堆栈变量(即临时);返回临时引用作为稍后要引用的指针是未定义的行为。

但是,preHead.next是堆分配的变量,然后可以在需要时正确地解除引用。