有人可以解释下面的代码:
void reverseList(node **href){
node *first;
node *rest;
if(*href == NULL){
return;
}
first = *href;
rest = first->next;
if(rest == NULL){
return;
}
reverseList(&rest);
first->next->next = first;
first->next = NULL;
*href = rest;
}
注意:href是链接列表的头部引用。
我不明白的是最后一句话=> *href = rest
因为这个步骤将在递归展开时发生,这不会使第二个节点从起始头ref开始,但我们希望最后一个节点作为我们的头部参考。
这将如何使最后一个节点成为head_ref?
答案 0 :(得分:2)
reverseList
将更新*href
,因此它指向其给出的列表的新头部;这是过去的节点。
我认为令人困惑的是,所有调用都会将*href
更新为相同的值;当递归调用返回时,它将指向输入的最后一个节点,这是结果的第一个节点
仅在递归终止时设置此值。
我要重命名first
和rest
,以澄清这一点。
第一个条件,
if(*href == NULL){
return;
}
当你从空列表开始时,可以处理这种情况。
以下处理公共基本情况,最终到达单元素列表:
old_head = *href;
/* "If the list has exactly one element, do nothing." */
if(old_head->next == NULL){
return;
}
然后,你递归(记住参数是" in"和" out"参数)
new_head = old_head->next;
reverseList(&new_head);
现在,通过递归的力量,new_head
指向反向"列表其余部分的头部"。
这也是我们的结果指针。
(尾部的最后一个节点也是整个列表的最后一个节点,对吗?)
我们现在需要的是设置新列表的结尾(在递归过程中它的初始部分已被反转)。
由于我们之前已保存old_head
,因此我们可以撤消过去跟随它的节点的next
指针:
old_head->next->next = old_head;
old_head->next = NULL;
就是这个
old_head new_head
| |
v v
+---+ +---+ +-----------------------------+
| ------>| | <----- | reversed |
| | | -----> | former continuation of list |
+---+ +---+ +-----------------------------+
变为此(old_head->next->next = old_head;
)
old_head new_head
| |
v v
+---+ +---+ +-----------------------------+
| ------>| | <----- | reversed |
| |<----- | | former continuation of list |
+---+ +---+ +-----------------------------+
然后(old_head->next = NULL;
)
old_head new_head
| |
v v
+---+ +---+ +-----------------------------+
| X | | | <----- | reversed |
| X |<----- | | former continuation of list |
+---+ +---+ +-----------------------------+
然后,我们更新参数,以便我们的调用者也获得指向新头的指针:
*href = new_head;