Односвязный список. Операция удаления элемента
Есть ли способ удалить элемент из односвязного списка за О(1)? При условии, что у нас есть указатель на удаляемый элемент.
Ответы (1 шт):
Автор решения: Stanislav Volodarskiy
→ Ссылка
В C и в C++ можно сделать односвязный список с удалением элемента за константу. Для этого в интерфейс функций добавляется дополнительный уровень косвенности: функции получают не адрес узла, а адрес указателя на адрес узла (обычно в предыдущем элементе списка). Идею подал Джон Кармак.
// gcc -std=c11 -pedantic -Wall -Wextra -Werror -O3 carmack-list.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node_t node_t;
struct node_t {
char value;
node_t *next;
};
void insert_head(node_t **head, char value) {
node_t *new_node = malloc(sizeof(node_t));
new_node->value = value;
new_node->next = *head;
*head = new_node;
}
void remove_head(node_t **head) {
node_t *old_node = *head;
*head = (*head)->next;
free(old_node);
}
node_t **find(node_t **head, char value) {
node_t **node;
for (node = head; *node != NULL; node = &(*node)->next) {
if ((*node)->value == value) {
break;
}
}
return node;
}
node_t *make_list(const char *s) {
node_t *head = NULL;
for (int i = strlen(s) - 1; i >= 0; --i) {
insert_head(&head, s[i]);
}
return head;
}
void print_list(node_t *head) {
for (node_t *node = head; node != NULL; node = node->next) {
putc(node->value, stdout);
}
putc('\n', stdout);
}
int main() {
node_t *list = make_list("C+-C+-C+-C");
print_list(list);
for (; ; ) {
node_t **node = find(&list, 'C');
if (*node == NULL) {
break;
}
remove_head(node);
print_list(list);
}
}
$ gcc -std=c11 -pedantic -Wall -Wextra -Werror -O3 carmack-list.c && ./a.out C+-C+-C+-C +-C+-C+-C +-+-C+-C +-+-+-C +-+-+-