这有点令人难以置信
我会试着解释我的怀疑。
检查此功能,例如:
void snoc(Lint *l, int val){
Lint i, new;
new = (Lint) malloc(sizeof(Nodo));
new->value = val;
new->next = NULL;
i=(*l);
while(i->next!=NULL){
i=i->next;
}
i->next = new;
}
我理解背后的概念,我在使用列表时没有遇到任何问题,考虑到我无法使用列表初始指针本身迭代列表(如果我这样做,我会丢失初始指针)< / p>
问题是,i=(*l)
然后使用i = i-&gt;继续遍历列表,使i变量不断变化。
在这个特定的例子中,原始列表不会改变,直到我找到链接列表的结尾,然后我做出归属和vo!我在最后插入一个元素。
我的疑问是,如果通过更改i
,并在最后制作i->next = new
,这并不意味着每次我制作i=i->next
时,都要更改原始节点中的所有节点列出?
另一个例子是init:
void init (Lint *l){
Lint i, prev;
i=(*l);
prev=NULL;
while(i!=NULL){
if( (i->next)->next==NULL){
i->next = NULL;
}
i=i->next;
}
}
如果我这样做,通过在适当的时候将i->next
更改为NULL,将删除最后一个元素。但在此之前,我已经通过告诉i
i=i->next
本身进行了更改
如果我要对(*l)
本身进行此更改(通过执行(*l)=(*l)->next
),我将破坏原始列表。
我真的希望你们能理解我的怀疑。
答案 0 :(得分:2)
是的,我们确实理解您的困惑,而且它来自于没有在那张纸上编制列表指针,因此您可以想象正在发生的事情。在处理node
链接问题时始终使用图表。例如,对于您的单链接列表,当前节点名为i
(可疑的名称选择)和您的新节点new
一个有用的图表将是:
Singly Linked-List (non-circular)
Tail Current Head
(list start) i new
+------------+ +------------+ +------------+
| Payload | | Payload | | Payload |
+------------+ +------------+ +------------+
| Next |------->| Next |------->| Next |--->NULL
+------------+ +------------+ +------------+
现在,我打赌你可以告诉我们:
更改
i
,并在结尾处制作i->next = new
会这样做。这不是一个挖掘或意味着居高临下,它实际上是您需要解决链接列表问题的方式,直到您完成它足以可视化您脑中的指针布线。当您进行循环或双向链接列表插入和删除时,这一点更为重要。无论出现什么问题,如果你只是把它写下来并标记所有正在建立或断开的连接,你就可以在编辑器中干净地编码。
答案 1 :(得分:1)
对一些未成年人进行修改,您的代码就像这样
void snoc(Lint *l, int val)
{
Lint i, new;
new = (Lint) malloc(sizeof(Nodo));
new->value = val;
new->next = NULL;
i = *l;
if(!(*l))
{
*l = new;
return;
}
while(i->next) i = i->next; // (1)
i->next = new; // (2)
}
,这就是它的解释:
在(1)中,我们遍历链表直到结束。我们知道我们已经结束了,因为i->next
(在每个循环步骤之后指向下一个nodo项目)是null,所以在这种情况下,我们使i->next
指向新创建的nodo项目(2 )。但是l
在函数期间从未改变,l
总是指向链表的开头,所以这个函数的目的是在最后添加一个新元素而不改变{{1}的值}}。
但我们也可以使用此功能初始化链接列表...例如:
l
(0)检查 Lint l = NULL;
snoc(&l, 10); // l will be initialized with a new nodo item with 10 as the value its value member
是否为空,在这种情况下,我们使l
指向新分配的nodo项并返回...所以初始化完成。
我为上面的代码添加了另一种方法
*l
答案 2 :(得分:0)
我不确定我理解你的问题,但为什么不简单地复制指针呢?您可以保留指向初始元素的指针,并使用第二个元素遍历它。