更改链表中的节点

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;
}