更改链表中的节点
Changing nodes in linked list
这有点令人难以置信
我会尽力解释我的疑问。
例如检查这个函数:
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;
}
我理解背后的概念并且我使用列表没有问题,考虑到我不能使用列表初始指针本身遍历列表(如果我这样做,我会失去初始指针的权利)
问题是,i=(*l)
然后使用 i=i->next 遍历列表,使 i 变量不断变化。
在这个特定的例子中,直到我找到链表的末尾,原始列表才会改变,然后我做一个归因,瞧!我在最后插入一个元素。
我的疑问是,如果通过更改 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->next
再次对 i
本身进行更改
如果我要对 (*l)
本身进行此更改(通过 (*l)=(*l)->next
),我会破坏原始列表。
真心希望大家能理解我的疑惑。
我不确定我理解你的问题,但你为什么不简单地复制指针?您可以保留一个指向初始元素的指针,并使用第二个指针遍历它。
是的,我们确实理解您的困惑,它来自于没有在一张纸上计算出列表指针,这样您就可以直观地看到正在发生的事情。在处理 node
link 问题时始终使用图表。例如,在您的情况下,您的单个 linked-list,当前节点称为 i
(名称的可疑选择)和您的新节点称为 new
一个有用的图表是:
Singly Linked-List (non-circular)
Tail Current Head
(list start) i new
+------------+ +------------+ +------------+
| Payload | | Payload | | Payload |
+------------+ +------------+ +------------+
| Next |------->| Next |------->| Next |--->NULL
+------------+ +------------+ +------------+
现在,我打赌你能说出什么:
changing i
, and making i->next = new
at the end
可以。这不是挖苦或居高临下的意思,这确实是您解决 linked-list 问题所需的方法,直到您完成足够的工作,您可以在脑海中想象指针接线。当您进行循环或双重 linked 列表插入和删除时,这一点更为重要。不管是什么问题,如果你只是把它写下来并标记所有正在建立或断开的连接,你就可以在你的编辑器中干净地编码它。
经过一些未成年人的修改,您的代码如下所示
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 项)为空,所以在这种情况下,我们使 i->next
指向新创建的 nodo 项(2 ).但是 l
在函数执行过程中没有改变, l
总是指向我们链表的开头所以这个函数的目的是在不改变 [=15 的值的情况下在末尾添加一个新元素=].
但我们也可以用这个函数初始化我们的链表...例如:
Lint l = NULL;
snoc(&l, 10); // l will be initialized with a new nodo item with 10 as the value its value member
(0) 检查 l
是否为 null 在这种情况下我们使 *l
指向新分配的 nodo 项目并且 return...所以初始化完成。
我为上面的代码添加另一种方式
void snoc(Lint *l, int val)
{
Lint now, new, previous;
new = (Lint) malloc(sizeof(Nodo));
new->value = val;
new->next = NULL;
if(!(*l)) // (0)
{
*l = new;
return;
}
for(now = *l; now; now = now->next)previous = now;
previous->next = new;
}
这有点令人难以置信
我会尽力解释我的疑问。
例如检查这个函数:
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;
}
我理解背后的概念并且我使用列表没有问题,考虑到我不能使用列表初始指针本身遍历列表(如果我这样做,我会失去初始指针的权利)
问题是,i=(*l)
然后使用 i=i->next 遍历列表,使 i 变量不断变化。
在这个特定的例子中,直到我找到链表的末尾,原始列表才会改变,然后我做一个归因,瞧!我在最后插入一个元素。
我的疑问是,如果通过更改 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->next
i
本身进行更改
如果我要对 (*l)
本身进行此更改(通过 (*l)=(*l)->next
),我会破坏原始列表。
真心希望大家能理解我的疑惑。
我不确定我理解你的问题,但你为什么不简单地复制指针?您可以保留一个指向初始元素的指针,并使用第二个指针遍历它。
是的,我们确实理解您的困惑,它来自于没有在一张纸上计算出列表指针,这样您就可以直观地看到正在发生的事情。在处理 node
link 问题时始终使用图表。例如,在您的情况下,您的单个 linked-list,当前节点称为 i
(名称的可疑选择)和您的新节点称为 new
一个有用的图表是:
Singly Linked-List (non-circular)
Tail Current Head
(list start) i new
+------------+ +------------+ +------------+
| Payload | | Payload | | Payload |
+------------+ +------------+ +------------+
| Next |------->| Next |------->| Next |--->NULL
+------------+ +------------+ +------------+
现在,我打赌你能说出什么:
changing
i
, and makingi->next = new
at the end
可以。这不是挖苦或居高临下的意思,这确实是您解决 linked-list 问题所需的方法,直到您完成足够的工作,您可以在脑海中想象指针接线。当您进行循环或双重 linked 列表插入和删除时,这一点更为重要。不管是什么问题,如果你只是把它写下来并标记所有正在建立或断开的连接,你就可以在你的编辑器中干净地编码它。
经过一些未成年人的修改,您的代码如下所示
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 项)为空,所以在这种情况下,我们使 i->next
指向新创建的 nodo 项(2 ).但是 l
在函数执行过程中没有改变, l
总是指向我们链表的开头所以这个函数的目的是在不改变 [=15 的值的情况下在末尾添加一个新元素=].
但我们也可以用这个函数初始化我们的链表...例如:
Lint l = NULL;
snoc(&l, 10); // l will be initialized with a new nodo item with 10 as the value its value member
(0) 检查 l
是否为 null 在这种情况下我们使 *l
指向新分配的 nodo 项目并且 return...所以初始化完成。
我为上面的代码添加另一种方式
void snoc(Lint *l, int val)
{
Lint now, new, previous;
new = (Lint) malloc(sizeof(Nodo));
new->value = val;
new->next = NULL;
if(!(*l)) // (0)
{
*l = new;
return;
}
for(now = *l; now; now = now->next)previous = now;
previous->next = new;
}