【问题标题】:Adding items to a linked list将项目添加到链接列表
【发布时间】:2021-12-23 06:44:58
【问题描述】:

我想将一个元素添加到元素列表中。我的列表是一个结构,包含一个双精度、一个整数和一个指向下一个元素的指针。有人可以告诉我如何执行添加功能

#include <stdio.h>
#include <stdlib.h>

typedef struct Liste Liste;
struct Liste{
    double c;
    int n;
    Liste* next; // pointe sur l'élément suivant
};

void Add(Liste array, Liste item) {
    Liste* last = array.next;
    while (last != NULL) {
        last = last->next;
    }
    array.next = &item;
    printf("%p\n", array.next);
}

int main(){
    Liste array = {12.4, 4, NULL};
    printf("%f\n", array.c);
    Liste item = {15.4, 7, NULL};
    Add(array, item);
    printf("%p\n", array.next);
    return 0;
}

【问题讨论】:

    标签: c linked-list


    【解决方案1】:

    处理列表时的关键元素是指针 并使用内存分配。

    如果我们无视您的添加功能而只做一个简单的 例如,您可能会明白它的精髓。

    首先给你分配这样的起始名单

    Liste* array = malloc(sizeof(Liste)); 
    

    现在你有一个未初始化的内存块 array 指向。然后你需要初始化 它。

    array->c = 12.4;
    array->n = 4;
    array->next = NULL;  
    

    为了在您的列表中添加新条目,您 需要再次为下一个节点分配内存并且 初始化它并设置前一个节点下一个指针 指向它,即array-&gt;next

    Liste* item = malloc(sizeof(Liste));
    item->c = 15.4;
    item->n = 7;
    item->next = NULL;
    array->next = item;    
    

    现在你有一个数组指向的两个元素的列表 到第一个

    打印你的短名单

    Liste* p = array;
    while (p != NULL)
    {
      printf("%lf %d %p\n", p->c, p->n, p->next);
      p = p->next;
    }
    

    所以您的 Add 函数不会分配内存和副本 参数,所以这不起作用。

    您的 Add 函数应该有一个指向列表中第一项或最后一项的指针,例如

    void Add(Liste* start, double c, int n)
    

    然后你按照我上面展示的那样做,创建一个新节点并分配值

    如果您希望能够将空列表传递给 Add,那么您需要做不同的事情,因为 start 被复制它无法更改,您需要传递指针的地址

    void Add(List** start, double c, int n)
    {
      Liste* node = malloc(sizeof(Liste));
      ...
      (* put node in the list *)
      if (*start == NULL)
      {
        *start = node; // first
      }
      else
      {
        (* find last node, see print loop *)
        (* once you have last item, set it to point to node)
      }
      ...
    }
    
    int main()
    {
      Liste* start = NULL;
      Add(&start, 12.4, 4);
      Add(&start, 15.4, 7);
      ...
    

    【讨论】:

      【解决方案2】:

      像链表这样的指针结构是应用广泛的强大工具。 但首先你必须了解指针。

      指针是包含数据结构地址的数据结构。

      每当您调用一个函数时,它的参数都会被复制(推送)到堆栈中。

      如果参数需要大量存储空间,请改用指针。

      下面的代码使用指针创建链表

      #include "stdio.h"
      #include "stdlib.h"
      #include "stdbool.h"
      
      
      typedef struct List List;
      
      struct List{
        double c;
        int n;
        List *next; 
      };
      
      
      void AddItemEnd( List *RootItem, List *Item )
      {
        List *Last = RootItem;
        while( Last->next != NULL )
        {
          Last = Last->next;
        }
        Last->next = Item;
      }
      
      void AddItemAtPos( List *RootItem, List *Item, unsigned int Pos )
      {
        if( Pos == 0 )
        {
          Item->next = RootItem;
        }
        else
        {
          List *TempItem = RootItem;
          for( unsigned int i = 1; i < Pos && TempItem->next != NULL; ++i  )
          {
            TempItem = TempItem->next;
          }
      
          Item->next = TempItem->next;
          TempItem->next = Item;
        }
      }
      
      
      void RemoveItemAtPos( List *RootItem, unsigned int Pos )
      {
        if( Pos == 0 )
        {
          free( (void*) RootItem );
        }
        else
        {
          List *TempItem = RootItem;
      
          for( unsigned int i = 1; i < Pos && TempItem->next != NULL; ++i  )
          {
            TempItem = TempItem->next;
          }
      
          if( TempItem->next == NULL )
          {
            return;
      
          }else if( TempItem->next->next != NULL )
          {
            List *ItemToDelete = TempItem->next;
            TempItem->next = TempItem->next->next;
            free( (void*) ItemToDelete );
          
          }else
          {
            free( (void*) TempItem->next );
            TempItem->next =NULL;
          }
        }
      }
      
      
      
      int main(void) {
        List *RootItem = malloc( sizeof( List )); 
        RootItem->c = 12.4;
        RootItem->n =  4;
        RootItem->next = NULL;
      
        List *Item1 = malloc( sizeof(List ));
        Item1->c = 15.4; 
        Item1->n = 7;
        Item1->next = NULL ;
      
        AddItemEnd( RootItem, Item1 );
      
        List *IterationItem;
      
        printf( "List created with AddItemEnd()\n\n" );
        for( IterationItem = RootItem; IterationItem != NULL; IterationItem = IterationItem->next )
        {
          printf( "c: %lf\nn: %d\n\n", IterationItem->c, IterationItem->n );
        }
      
      
      
        List *item2 = malloc( sizeof( List ));
        item2->c = 23.4;
        item2->n = 1846;
        item2->next = NULL ;
      
        AddItemAtPos( RootItem, item2, 1 );
      
        printf( "\n\nList extended with AddItemAtPos()\n\n");
        for( IterationItem = RootItem; IterationItem != NULL; IterationItem = IterationItem->next )
        {
          printf( "c: %lf\nn: %d\n\n", IterationItem->c, IterationItem->n );
        }
        
        RemoveItemAtPos(RootItem, 1 );
      
        printf( "\n\nList after RemoveItemAtPos()\n\n");
        for( IterationItem = RootItem; IterationItem != NULL; IterationItem = IterationItem->next )
        {
          printf( "c: %lf\nn: %d\n\n", IterationItem->c, IterationItem->n );
        }
        free( (void*) RootItem );
        free( (void*) item2 );
      
        return 0;
      }
      

      【讨论】:

        【解决方案3】:

        按值传递

        Add 中,C 复制了所有函数参数;它们的范围是函数本身。如您所见,当返回时,函数参数会从堆栈中弹出,并且无法取回它们。改变结构的方法是传递一个指向结构的指针,然后使用结构指针解引用运算符修改该指针,(箭头-&gt;。)

        设计

        使用链表的原因是重新排序非常便宜,但是链表的头部是固定的,所以你不能改变它。您可以通过从内容中描述容器、列表本身来改变这一点。这类似于使用双指针,但我认为不太容易混淆。

        struct Noeud {
            double c;
            int n;
            struct Noeud* next; // pointe sur l'élément suivant
        };
        
        struct Liste {
            struct Noeud *tete; // singly-linked-list est defini par un pointer seul
        };
        

        然后你可以添加,(我已经包括assert.h。)

        /* `O(n)` */
        static void AddQueue(struct Liste *liste, struct Noeud *item) {
            assert(liste && item && item->next == NULL);
            struct Noeud* last = liste->tete;
            if(last == NULL) { // case spécieux
                liste->tete = item;
            } else {
                while (last->next != NULL) {
                    last = last->next;
                }
                last->next = item;
            }
        }
        

        但是,在列表的开头添加更简单且渐进更快。

        【讨论】:

          猜你喜欢
          • 2015-04-16
          • 2015-07-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多