#c #linked-list
Вопрос:
Я хотел бы добавить элемент в список элементов. Мой список представляет собой структуру, содержащую двойник, целое число и указатель на следующий элемент. Не мог бы кто-нибудь сказать мне, как сделать функцию добавления, пожалуйста
#include lt;stdio.hgt; #include lt;stdlib.hgt; 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-gt;next; } array.next = amp;item; printf("%pn", array.next); } int main(){ Liste array = {12.4, 4, NULL}; printf("%fn", array.c); Liste item = {15.4, 7, NULL}; Add(array, item); printf("%pn", array.next); return 0; }
Ответ №1:
Проходное значение
В 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 amp;amp; item amp;amp; item-gt;next == NULL); struct Noeud* last = liste-gt;tete; if(last == NULL) { // case spécieux liste-gt;tete = item; } else { while (last-gt;next != NULL) { last = last-gt;next; } last-gt;next = item; } }
Однако добавить в начале списка гораздо проще и асимптотически быстрее.
Ответ №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-gt;next != NULL ) { Last = Last-gt;next; } Last-gt;next = Item; } void AddItemAtPos( List *RootItem, List *Item, unsigned int Pos ) { if( Pos == 0 ) { Item-gt;next = RootItem; } else { List *TempItem = RootItem; for( unsigned int i = 1; i lt; Pos amp;amp; TempItem-gt;next != NULL; i ) { TempItem = TempItem-gt;next; } Item-gt;next = TempItem-gt;next; TempItem-gt;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 lt; Pos amp;amp; TempItem-gt;next != NULL; i ) { TempItem = TempItem-gt;next; } if( TempItem-gt;next == NULL ) { return; }else if( TempItem-gt;next-gt;next != NULL ) { List *ItemToDelete = TempItem-gt;next; TempItem-gt;next = TempItem-gt;next-gt;next; free( (void*) ItemToDelete ); }else { free( (void*) TempItem-gt;next ); TempItem-gt;next =NULL; } } } int main(void) { List *RootItem = malloc( sizeof( List )); RootItem-gt;c = 12.4; RootItem-gt;n = 4; RootItem-gt;next = NULL; List *Item1 = malloc( sizeof(List )); Item1-gt;c = 15.4; Item1-gt;n = 7; Item1-gt;next = NULL ; AddItemEnd( RootItem, Item1 ); List *IterationItem; printf( "List created with AddItemEnd()nn" ); for( IterationItem = RootItem; IterationItem != NULL; IterationItem = IterationItem-gt;next ) { printf( "c: %lfnn: %dnn", IterationItem-gt;c, IterationItem-gt;n ); } List *item2 = malloc( sizeof( List )); item2-gt;c = 23.4; item2-gt;n = 1846; item2-gt;next = NULL ; AddItemAtPos( RootItem, item2, 1 ); printf( "nnList extended with AddItemAtPos()nn"); for( IterationItem = RootItem; IterationItem != NULL; IterationItem = IterationItem-gt;next ) { printf( "c: %lfnn: %dnn", IterationItem-gt;c, IterationItem-gt;n ); } RemoveItemAtPos(RootItem, 1 ); printf( "nnList after RemoveItemAtPos()nn"); for( IterationItem = RootItem; IterationItem != NULL; IterationItem = IterationItem-gt;next ) { printf( "c: %lfnn: %dnn", IterationItem-gt;c, IterationItem-gt;n ); } free( (void*) RootItem ); free( (void*) item2 ); return 0; }
Ответ №3:
Ключевыми элементами при работе со списками являются указатели и использование выделения памяти.
Если мы проигнорируем вашу функцию добавления и просто приведем простой пример, вы, вероятно, поймете суть этого.
Сначала выделите вам начальный список вот так
Liste* array = malloc(sizeof(Liste));
Теперь у вас есть один неинициализированный блок памяти , на который array
указывает. Затем вам нужно его инициализировать .
array-gt;c = 12.4; array-gt;n = 4; array-gt;next = NULL;
чтобы добавить новую запись в свой список, вам нужно снова выделить память для следующего узла и инициализировать его, а также установить указатель следующего предыдущего узла , чтобы он указывал на него, т. е. array-gt;next
.
Liste* item = malloc(sizeof(Liste)); item-gt;c = 15.4; item-gt;n = 7; item-gt;next = NULL; array-gt;next = item;
теперь у вас есть список из двух элементов, где массив указывает на первый
печать вашего короткого списка
Liste* p = array; while (p != NULL) { printf("%lf %d %pn", p-gt;c, p-gt;n, p-gt;next); p = p-gt;next; }
Таким образом, ваши функции добавления не выделяют память и копируют параметры, так что это не сработает.
Ваша функция добавления должна содержать указатель либо на первый, либо на последний элемент в вашем списке, например
void Add(Liste* start, double c, int n)
Затем вы делаете так, как я показал вам выше, создаете новый узел и присваиваете значения
Если вы хотите иметь возможность передавать пустой список для добавления, то вам нужно поступить по-другому, так 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(amp;start, 12.4, 4); Add(amp;start, 15.4, 7); ...