【问题标题】:Dummy Node in Linked List in C++C ++中链表中的虚拟节点
【发布时间】:2015-07-18 12:12:28
【问题描述】:

我正在尝试开发一种方法来解决链表问题,而不必以任何特殊方式关心头节点,即在链表问题中,我们通常在开始处理下一个节点之前单独处理头指针.

我找到了一种方法:使用一个虚拟节点,让实际的链表从 dummy.next 开始。

我正在尝试使用这种方式解决problem

 struct ListNode {
     int val;
     ListNode *next;
     ListNode(int x) : val(x), next(NULL) {}
 };

 ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {

        ListNode dummy = ListNode(0);
        ListNode * temp = dummy.next;
        int carry =0;

        while(l1!=NULL && l2!=NULL)
        {
            int x = (l1->val + l2->val + carry)%10;
            temp = new ListNode(x);
            carry = (l1->val + l2->val + carry)/10;
            temp = temp->next;
            l1 = l1->next;
            l2 = l2->next;
        }

        ListNode * p = (l1!=NULL)?l1:l2;

        while(p!=NULL)
        {
            int x = (p->val+carry)%10;
            temp = new ListNode(x);
            carry = (p->val+carry)/10;
            temp = temp->next;
            p = p->next;
        }

        if(carry==1) temp = new ListNode(1);

        return dummy.next;

    }

int main()
{
    ListNode * l1 = new ListNode(0), *l2 = new ListNode(0);
    ListNode * l3 = addTwoNumbers(l1,l2);

}

在这个问题中,我尝试不单独初始化头节点。显然,代码并没有按照我的意愿去做,但是我尝试了这种方式,现在,我不知道如何继续使用这种方法。

即使用dummy节点,这样就不需要单独处理新创建的链表的头节点了。

有什么方法可以使用这种方法来解决问题?

【问题讨论】:

  • 使用std::list,与链表问题告别。
  • @JonathanPotter thx 但不能这样做。必须解决这个问题:)。
  • 使用虚拟节点似乎不是一个合理的想法。它只是推动你试图进一步解决的问题。不管这个问题是什么。

标签: c++ algorithm pointers linked-list


【解决方案1】:

遵循这种方法

ListNode * addTwoLists(ListNode * first, ListNode * second) {
    ListNode * res = NULL, * temp, * prev = NULL;
    int carry = 0, sum;
    while (first != NULL || second != NULL) {
        sum = carry + (first ? first->val : 0) + (second ? second->val : 0);
        carry = (sum >= 10) ? 1 : 0;
        sum %= 10;
        temp = new ListNode(sum);
        if (res == NULL)
            res = temp;
        else
            prev->next = temp;
        prev = temp;
        if (first) first = first->next;
        if (second) second = second->next;
    }
    if (carry > 0)
        temp->next = new ListNode(carry);
    return res;
}

【讨论】:

  • 是的,我在看到您的方法后发现,我的代码现在只需进行一行更改即可工作。非常感谢:)。
  • @Shreevardhan 此代码只会出现段错误。我想你需要我在这里添加的elseif (res == NULL) res = temp; else prev->next = temp;
  • @adrian008 我会很惊讶地看到这一行发生了变化。我不认为改变必须是根本性的,但仍远不止一条线。
  • @JSF 好吧,它真的只是一行,*temp = & dummy 然后,我可以在我创建节点的两个地方使用 temp->next(而不是 temp)。所以,从技术上讲,它的三个变化线:),这仍然比更多:)。
  • @JSF 你是对的,错过了else。修正了错字。谢谢。
【解决方案2】:

这些部分是你的问题:

        temp = new ListNode(x);
        carry = (l1->val + l2->val + carry)/10;
        temp = temp->next;

您创建一个新的 ListNode,然后使用 temp = temp->next忘记它。 temp->next 那时是 NULL,你将失去任何访问之前创建的 ListNode 的能力,更不用说修改它的 next 指针了。

重新开始。这是被设计破坏的。

【讨论】:

  • 不,我的意思是我在每次迭代中都在更新 temp,temp temp->next 不会更新,所以它忘记在哪里了?
  • 不,你没有,你给temp分配了temp->next的值,因此只是把我们唯一的指针放到你新创建的ListNode上。
  • 是的,我实际上已经修复了它。谢谢。
  • 基本模式 temp=new ListNode(x); ... temp=temp-next; 已损坏,如 Felix 所示。但是“重新开始”有点过分。正如您在我的回答中看到的那样,您可以使用temp=temp->next=new ListNode(x) 作为您的基本模式,并结合从&dummy 而不是dummy->next 开始。我的版本和原始版本之间的其余差异只是为了减少重复工作而进行的清理,而不是根本的更正。
【解决方案3】:

无论有没有虚拟节点,构建新列表的关键部分是在逻辑上落后一个节点。我更喜欢在没有虚拟节点的情况下这样做,因此用于当前位置的指针是ListNode** temp,您使用(*temp)=new ListNode(x) 分配新节点并使用temp=&(*temp)->next 前进到下一个(前任)位置。如果您更喜欢使用虚拟节点,则使用ListNode* temp=&dummy; 并使用temp->next=new ListNode(x) 分配新节点,并仅在您的逻辑位置超出该位置后使用temp=temp->next 前进。

根据您的评论进行编辑。如果你想避免双指针的语法(不是现实):

ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {

        ListNode dummy = ListNode(0);
        ListNode * temp = &dummy;
        int carry =0;

        while(l1!=NULL || l2!=NULL)
        {
            if (l1!=NULL)
            {
                 carry += l1->val;
                 l1 = l1->next;
            }
            if (l2!=NULL)
            {
                 carry += l2->val;
                 l2 = l2->next;
            }

            temp = temp->next = new ListNode(carry%10);
            carry /= 10;
        }

        if(carry==1) temp->next = new ListNode(1);

        return dummy.next;

    }

【讨论】:

  • 我可以那样做,我不想用(*temp),我不想用双指针。
  • 你必须使用双指针,不管你想不想。虚拟节点可用于在语法上掩盖您正在使用双指针的事实。如果双指针的语法让您感到困扰,那很好。但是双指针的真实性必须仍然存在,即使在语法上是隐藏的。您尝试使用虚拟节点来删除双指针的现实(而不仅仅是语法)根本行不通。
  • 谢谢,我曾经看到 Sreevardhan 的回答的方法,我没有运行它。他所做的是他使用三个指针来跟踪,使用虚拟节点我只需要一个临时指针来实现他所做的。感谢您的帮助。
猜你喜欢
  • 2019-08-28
  • 1970-01-01
  • 1970-01-01
  • 2020-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多