Пустые узлы не нужны для реализации односвязных списков.Они используются в качестве альтернативы определению структуры списка, отличной от структуры элемента списка.
Учитывая ваши требования, вы должны определить структуру списка, которая содержит указатель на начало списка и указатель на хвостиз списка.Это приведет к тому, что обе операции, вставка в конце и удаление из головки, будут работать n постоянное время.
Необходимо соблюдать осторожность, чтобы правильно поддерживать эти указатели, когда список становится пустым.
Вотпростой пример:
struct list_elem_s {
struct list_elem_s *next;
int data;
//... other payload fields
};
struct list_s {
struct list_elem_s *head;
struct list_elem_s *tail;
};
// initialize a list as empty
void list_initialize(struct list_s *list) {
list->head = list->tail = NULL;
}
// free all elements from a list
void list_delete(struct list_s *list,
void (*free_node)(struct list_elem_s *node)) {
struct list_elem_s *node;
while ((node = list->head) != NULL) {
list->head = node->next;
node->next = NULL;
if (free_node)
free_node(node);
}
list->tail = NULL;
}
// add a node at the tail
void list_push(struct list_s *list, struct list_elem *node) {
node->next = NULL;
if (list->tail) {
list->tail->next = node;
} else {
list->head = node;
}
list->tail = node;
}
// remove a node at the head
struct list_elem *list_pop_head(struct list_s *list) {
struct list_elem_s *node;
if ((node = list->head) != NULL) {
if ((list->head = node->next) == NULL)
list->tail = NULL;
}
return node;
}