如何解决在链表中使用节点指针如何改变递归?
我使用了临时节点'nextnode'指向head
或cur
的下一个节点:
SinglyLinkedListNode* removeDuplicates(SinglyLinkedListNode* head) {
if ( head == NULL ) return NULL;
SinglyLinkedListNode *nextnode = head->next;
while ( nextnode != NULL && head->data == nextnode->data ) {
nextnode = nextnode->next;
}
head->next = removeDuplicates( nextnode );
return head;
}
此代码可以正常工作...但是如果我更改
head->next = removeDuplicates( nextnode );
到
head->next = removeDuplicates( head->next);
但是,如果我在所有位置删除nextnode
并使用head->next
代替nextnode
,则代码可以正常工作!
实际上发生了什么,这使它起作用了?我想念什么?
使用head->next
和nextnode
时此代码会发生什么?我只想了解它在内存分配中的工作原理,以便更好地了解递归。
解决方法
以该列表为例:
head
↓
1 → 2 → 2 → 3 → 3 → 3 → 4
在函数的第一次调用中,nextnode
将指向[2],并且由于数据不同(1!= 2),while
条件将立即为false。所以我们有:
head nextnode
↓ ↓
1 → 2 → 2 → 3 → 3 → 3 → 4
然后进行第一个递归调用,在该执行上下文中,还有另一个head
变量,该变量设置为调用者的nextnode
的值。为了更好地跟踪此head
变量,我将其称为head2
,并在原始调用中谈到变量时将继续引用head
:
head head2
↓ ↓
1 → 2 → 2 → 3 → 3 → 3 → 4
创建了一个新的nextnode
变量,这一次while
循环将进行一次迭代,因为存在重复值(2)。当nextnode
指向3:
head head2 nextnode
↓ ↓ ↓
1 → 2 → 2 → 3 → 3 → 3 → 4
进行另一个递归调用。再次,我们得到一个新的head
变量,我将其称为head3
:
head head2 head3
↓ ↓ ↓
1 → 2 → 2 → 3 → 3 → 3 → 4
同样,将创建一个新的nextnode
。这次它最终指向带有4的节点:
head head2 head3 nextnode
↓ ↓ ↓ ↓
1 → 2 → 2 → 3 → 3 → 3 → 4
进行了更深层次的递归调用:
head head2 head3 head4
↓ ↓ ↓ ↓
1 → 2 → 2 → 3 → 3 → 3 → 4
这次,新的nextnode
变量将变为NULL
,因此我们使用参数NULL
进行了递归调用。我们到了递归的结尾,因为最深的调用将立即返回NULL
。我们返回到进行呼叫的地方,看到已为head4->next
分配了NULL
。在这种情况下,此分配没有任何区别,因为head4->next
已经是NULL
。
我们回溯到递归树中的上一级:返回head4
。在那里,我们确实看到了修改。此返回的head4
被分配给head3->next
,因此,仅通过一次分配就将值3的第二个和第三个节点踢出了列表:
head head2 head3 head4
↓ ↓ ↓ ↓
1 → 2 → 2 → 3 → 4
我们又回退了一步,这次head3
返回并分配给head2->next
。现在将值2的第二个节点踢出:
head head2 head3 head4
↓ ↓ ↓ ↓
1 → 2 → 3 → 4
又回溯了一次:head2
返回到分配给head->next
。由于head->next
已指向head2
,因此没有区别。顶层函数调用返回head
,我们完成了。
使用head->next = removeDuplicates( head->next);
此更改确实会破坏算法。它使nextnode
的值无关紧要。 while
循环现在什么也不做,因为代码没有使用nextnode
的新值。您也可以删除该循环和变量nextnode
,然后很明显,从未删除任何节点。
一个关键的观察结果是removeDuplicates
总是返回您传递给它的节点作为参数,因此更改后的语句确实在做:
head->next = head->next
...什么都不做,这是列表链被更改的代码中的 only 位置。 next
属性在其他任何地方都没有更改。
如果我在所有位置都删除了
nextnode
,并用head->next
代替了nextnode
,则代码运行正常!
的确。在那种情况下,该函数不需要返回任何内容,因为重复删除永远不需要更改列表的head
。因此,代码如下所示:
void removeDuplicates(SinglyLinkedListNode* head) {
if ( head == NULL ) return;
while ( head->next != NULL && head->data == head->next->data ) {
head->next = head->next->next;
}
removeDuplicates( head->next );
}
对于示例列表,我们可以再次进行与该答案顶部相同的分析(请在纸上进行),您将得出结论,这也将有效地删除重复项。区别在于,此处的实际删除操作是在while
循环中一次出现一个节点(每个迭代恰好删除了一个节点),而在原始代码中,它是在回溯期间发生的,它实际上可以删除多个节点。一口气(就像我们在一次分配中将3 → 3 → 3 → 4
变成3 → 4
的情况一样),因此通常来说,原始代码有时可以用更少的分配量完成工作,当然当重复很多列表中的值。
原始代码中的->next
引用也较少。
由于这些差异,理论上原始代码将运行得更快。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。