struct Node
{
int data;
struct Node *next;
}
我应该反转一个链表。和hackerrank一样,这段代码运行正常。
代码A
void rev(Node* head){
if(head==NULL) return;
rev(head->next);
cout<<head->data<<endl;
}
输入: 2 1 4 5 输出 5 4 1 2
但是,如果我做了一个小的改变,它会中断,即我得到分段错误!
代码B
void rev(Node* head){
if(head==NULL) return;
head=head->next;
rev(head);
cout<<head->data<<endl;
}
输入: 2 1 4 5 输出:分段错误
但如果我做了以下更改,它会以某种方式工作,但不会显示第一个数字。
CODE C
void rev(Node* head){
if(head->next==NULL) return;
head=head->next;
rev(head);
cout<<head->data<<endl;
}
输入: 2 1 4 5 输出: 5 4 1
问题:代码A和代码B大致相似。什么打破了代码B?
答案 0 :(得分:1)
在你的代码中 在案例B中:
void rev(Node* head){
if(head==NULL) return;
head=head->next;
rev(head);
cout<<head->data<<endl;}
让我们看一下Stack Segment的递归。
让NODE1 -> NODE2->NULL
NODE1 and NODE2
为结构对象。
你的功能是:
rev(NODE1)
指向next NODE i.e. NODE2
致电rev(NODE2)
指向next NODE i.e. NULL
致电rev(NULL)
head = NULL
和
这是错误,即您正在访问head->data
以获取NULL值。
希望这会帮助你。
答案 1 :(得分:0)
当然,如果 B ,您无法访问内存。您的指针指向您未分配的地址(NULL)。 顺便说一句,我建议制作双链表。更方便。
如果 C ,您为函数void rev (Node* head)
指定一个指向列表的指针,并跳过第二行head=head->next;
,这是您的第一个元素。因此,它不会显示在std::cout
的输出中。
使用案例A,你很好。
答案 2 :(得分:0)
链接列表迭代器只能继续到链表的末尾。
所有链接列表迭代器代码必须包含循环不变量 - 测试确保如果它接下来取消引用,则下一个有效。如果不是,它就会停止。这通常采用以下形式:
if(head==NULL) return;
或
while(head!=NULL)
或
if(head->next != NULL) recurse(head->next)
如果 NULL
,那么head->next
(或head->data
或head->anything
)
更改的效果是绕过循环不变量,并查看head->next
内部,而不检查它是否为NULL
。
具体来说,您在检查head->data
是否为空之前访问head
,以及 BOOM!。
看起来你在/'我应该切断蓝线还是黄线'/领域。玩得开心。
虽然你没有使用循环,但递归也是一种迭代形式。
答案 3 :(得分:0)
让我为您重写代码A :
void rev(Node* head){
if(head!=NULL)
{
rev(head->next); //recursive call with pointer to next!
cout<<head->data<<endl; //write after recursive call (reversed)
}
}
代码B 可以用同样的方式重写:
void rev(Node* head){
if(head!=NULL)
{
head=head->next;
//head becomes next, but what if next is null,
//you try to read next, which is a null pointer here == segmentation fault
rev(head);
cout<<head->data<<endl;
}
}
所以基本上代码A 不会读取空指针,但在代码B 中,您指定了一个指向head
的空指针,因此您必须阅读用于执行此赋值的null指针。
在代码C 中,if (head->next==NULL) return;
行阻止您使用该行下方的代码,以防下一个元素为空,因此不会打印当前头部。
答案 4 :(得分:0)
您的链表结构是2-> 1-> 4-> 5-> NULL
代码B:
在递归时,当head具有data = 5时,head = head-&gt; next使head = NULL,所以下一次调用rev()会立即返回head = NULL,现在你尝试访问head-&gt ;与NULL->数据相同的数据,结果是分段错误。
答案 5 :(得分:0)
不是你问题的直接答案,但是你是否有单向或双向链表,如果你想反转该列表,那么建议同时保持Head指针和Tail指针:
要撤消单向链接列表,请致电Reverse()
:
void Swap(Node* pCurr,Node* pNext)
{
if (pNext != NULL)
{
Swap(pNext,pNext->pNext);
pNext->pNext = pCurr;
}
}
void Reverse()
{
if (pHead != NULL)
{
Swap(pHead,pHead->pNext);
pHead->pNext = NULL;
}
Node* pTemp = pHead;
pHead = pTail;
pTail = pTemp;
}
要撤消双向链表,请致电Reverse()
:
void Swap(Node* pCurr)
{
if (pCurr->pNext != NULL)
{
Swap(pCurr->pNext);
pCurr->pNext->pNext = pCurr;
}
pCurr->pPrev = pCurr->pNext;
}
void Reverse()
{
if (pHead != NULL)
{
Swap(pHead);
pHead->pNext = NULL;
}
Node* pTemp = pHead;
pHead = pTail;
pTail = pTemp;
}
答案 6 :(得分:0)
代码A和代码B不相似。在代码A中,您将head->next
作为rev
的参数传递而不更改指针head
,但在代码B中,您更改了指针head
。因此,调用cout<<head->data
您的链表样本可以显示为:2-&gt; 1-&gt; 4-&gt; 5-&gt; NULL
你的遗嘱将被评估为(相同范围的相同身份):
在代码A中:
head: 2, call rev(head) //your initial call
head: 2, check head==NULL false
head: 2, call rev(head->next)
head: 1, check head==NULL false
head: 1, call rev(head->next)
head: 4, check head==NULL false
head: 4, call rev(head->next)
head: 5, check head==NULL false
head: 5, call rev(head->next)
head==NULL, check head==NULL true
return
head: 5, call cout<<head->data<<endl;
head: 4, call cout<<head->data<<endl;
head: 1, call cout<<head->data<<endl;
head: 2, call cout<<head->data<<endl;
return
但在代码B中:
head: 2, call rev(head) //your initial call
head: 2, check head==NULL false
head: 2, head = head->next
head: 1, call rev(head)
head: 1, check head==NULL false
head: 1, head = head->next
head: 4, call rev(head)
head: 4, check head==NULL false
head: 5, head = head->next
head: 5, call rev(head)
head: 5, check head==NULL false
head: 5, head = head->next
head==NULL, call rev(head)
head==NULL, check head==NULL true
return
head: NULL, call cout<<head->data<<endl; //segmentation fault here
否则,在代码C中:
head: 2, call rev(head) //your initial call
head: 2, check head->next==NULL false
head: 2, head = head->next
head: 1, call rev(head)
head: 1, check head->next==NULL false
head: 1, head = head->next
head: 4, call rev(head)
head: 4, check head->next==NULL false
head: 5, head = head->next
head: 5, call rev(head)
head: 5, check head->next==NULL true
return
head: 5, call cout<<head->data<<endl;
head: 4, call cout<<head->data<<endl;
head: 1, call cout<<head->data<<endl;
return
看到有cout
的三次调用,因此只打印了三个元素。