Я знаю, как правило, два способа создать общую структуру данных связанных списков в C. И мне интересно, что лучше. Прежде чем задать вопрос, я познакомлю оба методы коротко:Два способа реализации связанного списка: что лучше?
Один из способов заключается в создании функции вокруг структуры, как следующее:
struct list_element {
struct list_element *prev;
struct list_element *next;
void *data;
};
Очевидно, что точки указателя данных в полезную нагрузку. Элемент struct list находится за пределами полезной нагрузки. Это, например, как glib разработал свой объект с двойным списком ссылок: http://library.gnome.org/devel/glib/2.26/glib-Doubly-Linked-Lists.html
Другой метод - способ, которым это делается в ядре Linux: http://isis.poly.edu/kulesh/stuff/src/klist/. Нет указателя void для полезной нагрузки в структуре элемента списка. Вместо этот элемент списка структуру входит в полезной структуре:
struct list_element {
struct list_element *prev;
struct list_element *next;
};
struct person {
char name[20];
unsigned int age;
struct list_element list_entry;
};
специальный макрос используется для получения указателя на полезную структуру данного указатель на LIST_ENTRY, его имя жгуты на-структуру полезной нагрузки и тип payload struct (макрос list_entry()).
Обратите внимание, что здесь возник вопрос: Какое преимущество заключается в том, что последний из двух методов построения связанного списка? Несколько раз я слышал, как люди говорят, что второе является более «родовым», чем первое, но почему? Я бы даже утверждать, что первый метод более общий, потому что структуры полезной нагрузки являются агностиками реализации списка, что не соответствует второму методу.
Еще один недостаток второго метода заключается в том, что если вы хотите разместить полезную нагрузку в нескольких списках, вы должны иметь элемент struct list_element для каждого списка в структуре полезной нагрузки.
Edit: Резюмируя до сих пор я видел два ответа, которые были важны для меня:
- С первого метода: удаление полезной нагрузки из списка включает в себя цикл через весь список, пока элемент списка не указывает на полезная нагрузка найдена. Вам не нужно делать это со вторым методом. (Ответа на этот вопрос Patrick)
- С помощью первого метода вам нужно сделать два malloc() для каждого элемента: один для полезной нагрузки и один для элемента списка. При втором методе достаточно одного malloc(). (Ответ от Родди)
Зачем вам нужны элементы в вашем списке, которые не содержат данных? Может быть, я должен отметить, что в первом методе все указатели void в списке всегда указывают на структуры одного типа. – Bart 2010-12-01 10:57:39
Второй вариант не требует, чтобы все узлы были одного типа. Если вы немного измените требования, поэтому `struct list_element` всегда является первым членом, то методы` next` и `prev` легко обобщаются и могут указывать на любую структуру, которая не должна быть та же структура, что и последний узел. (Если вы считаете, что это не безопасный тип и опасно, оно не может быть менее опасным типа, чем `void *`.) – 2010-12-01 11:04:24