Двусвязный список — это тип связанного списка, в котором каждый узел имеет ссылки как на следующий узел, так и на предыдущий узел. Это позволяет эффективно выполнять операции вставки и удаления, а также обход списка в обоих направлениях (т. е. вперед и назад).
В двусвязном списке каждый узел обычно имеет два поля: data и next, в которых хранится значение узла и ссылка на следующий узел в списке соответственно.  В дополнение к этим двум полям каждый узел в двусвязном списке также имеет другое поле с именем prev, в котором хранится ссылка на предыдущий узел в списке.
Вот пример узла двусвязного списка в C:
struct Node {
    int data;
    struct Node* next;
    struct Node* prev;
};
Чтобы создать двусвязный список, нам сначала нужно создать структуру Node и выделить для нее память с помощью функции malloc.  Затем мы можем присвоить значения полям data, next и prev структуры Node.
Вот пример создания двусвязного списка и вставки в него некоторых узлов:
struct Node* head = NULL; struct Node* second = NULL; struct Node* third = NULL; // allocate memory for the nodes head = (struct Node*)malloc(sizeof(struct Node)); second = (struct Node*)malloc(sizeof(struct Node)); third = (struct Node*)malloc(sizeof(struct Node)); // set the data for the nodes head->data = 1; second->data = 2; third->data = 3; // set the next and prev pointers for the nodes head->next = second; head->prev = NULL; second->next = third; second->prev = head; third->next = NULL; third->prev = second;
В приведенном выше примере мы создали три узла и присвоили значения их data полям.  Мы также устанавливаем указатели next и prev для каждого узла, связывая их вместе, чтобы сформировать двусвязный список.  Узел head указывает на второй узел, который, в свою очередь, указывает на третий узел, образуя цепочку узлов.  Указатели prev для каждого узла указывают на предыдущий узел в списке, что позволяет нам перемещаться по списку в обоих направлениях.
Чтобы пройти по двусвязному списку, мы можем начать с узла head и следовать указателям next, пока не достигнем конца списка.  Мы также можем начать с последнего узла и следовать указателям prev, чтобы пройти по списку в обратном направлении.
Вот пример обхода двусвязного списка в обоих направлениях:
// traversing the list forwards
struct Node* current = head;
while (current != NULL) {
    printf("%d ", current->data);
    current = current->next;
}
// traversing the list backwards
current = third;
while (current != NULL) {
    printf("%d ", current->data);
    current = current->prev;
}
В приведенном выше примере мы начинаем с узла head и перемещаемся по списку вперед, следуя указателям next.  По мере продвижения мы печатаем поле data каждого узла.  Затем мы начинаем с узла third и перемещаемся по списку в обратном направлении, следуя указателям prev.
 
                                                                     
                                                                     
                                                                     
                                                                    