🤝24. Динамические структуры данных. Двусвязные списки. Алгоритмы их обработки.
Динамические структуры данных - составные структуры данных, динамически меняющие свой размер во время выполнения программы.
Двусвязный список
Двунаправленный (двусвязный) список – это структура данных, состоящая из последовательности элементов, каждый из которых содержит информационную часть и два указателя на соседние элементы. При этом два соседних элемента должны содержать взаимные ссылки друг на друга.

typedef struct node{
int value; // значение
struct node* prev; // указатель на предыдущий элемент
struct node* next; // указатель на следующий элемент
} node;
type
– тип информационного поля элемента списка;
*next, *prev
– указатели на следующий и предыдущий элементы этой структуры соответственно.
struct node* list = malloc(sizeof(struct node));
list->value = 1;
list->next = NULL;
list->prev = NULL;
Основные операции
создание списка;
печать (просмотр) списка;
вставка элемента в список;
удаление элемента из списка;
поиск элемента в списке;
проверка пустоты списка;
удаление списка.
⚠️Многие коды представлены на С++. Меняйте вывод и выделение памяти.
Создание двунаправленного списка
Для того, чтобы создать список, нужно создать сначала первый элемент списка, а затем при помощи функции добавить к нему остальные элементы. Добавление может выполняться как в начало, так и в конец списка. Реализуем рекурсивную функцию.
node* listInit(int value)
{
node* new_list = (node*)malloc(sizeof(node));
new_list->value = value;
new_list->prev = NULL;
new_list->next = NULL;
return new_list;
}
Добавление элемента в начало списка ( listPush ):
void listPush(node** list_ptr, int value)
{
node* new_node = (node*)malloc(sizeof(node));
new_node->value = value;
new_node->prev = NULL;
if (*list_ptr != NULL)
(*list_ptr)->prev = new_node;
new_node->next = *list_ptr;
*list_ptr = new_node;
}
Добавление элемента в конец списка ( listPushBack ):
void listPushBack(node** list_ptr, int value){
node* new_node = (node*)malloc(sizeof(node));
new_node->value = value;
new_node->next = NULL;
if (*list_ptr != NULL) {
node* last = *list_ptr;
for(; last->next != NULL; last = last->next);
last->next = new_node;
new_node->prev = last;
} else {
new_node->prev = NULL;
*list_ptr = new_node;
}
}
Удаление элемента из начала списка c получением его значения(listPop):
int listPop(node** list_ptr)
{
if (*list_ptr != NULL) {
node* next = (*list_ptr)->next;
int value = (*list_ptr)->value;
free(*list_ptr);
if (next != NULL)
next->prev = NULL;
*list_ptr = next;
return value;
}
else
exit(-1);
}
Удаление элемента из конца списка с получением его значения (listPopBack ):
int listPopBack(node** list_ptr)
{
if (*list_ptr != NULL) {
node* last = *list_ptr;
for(; last->next != NULL; last = last->next);
node* prev = last->prev;
int value = last->value;
free(last);
if (prev != NULL)
prev->next = NULL;
else
*list_ptr = NULL;
return value;
}
else
exit(-1);
}
Печать (просмотр) двунаправленного списка
Операция печати списка для двунаправленного списка реализуется абсолютно аналогично соответствующей функции для однонаправленного списка. Просматривать двунаправленный список можно в обоих направлениях.
//печать двунаправленного списка
void Print_Double_List(Double_List* Head) {
if (Head != NULL) {
cout << Head->Data << "\t";
Print_Double_List(Head->Next);
//переход к следующему элементу
}
else cout << "\n";
}
//или
void listPrint(node** list_ptr)
{
for (node* current_node = *list_ptr; current_node != NULL; current_node =
current_node->next)
printf("%d\n", current_node->value);
}
Вставка элемента в двунаправленный список
В динамические структуры легко добавлять элементы, так как для этого достаточно изменить значения адресных полей. Операция вставки реализовывается аналогично функции вставки для однонаправленного списка, только с учетом особенностей двунаправленного списка

//вставка элемента с заданным номером в двунаправленный список
Double_List* Insert_Item_Double_List(Double_List* Head,
int Number, int DataItem){
Number--;
Double_List *NewItem=new(Double_List);
NewItem->Data=DataItem;
NewItem->Prior=NULL;
NewItem->Next = NULL;
if (Head == NULL) {//список пуст
Head = NewItem;
}
else {//список не пуст
Double_List *Current=Head;
for(int i=1; i < Number && Current->Next!=NULL; i++)
Current=Current->Next;
if (Number == 0){
//вставляем новый элемент на первое место
NewItem->Next = Head;
Head->Prior = NewItem;
Head = NewItem;
}
else {//вставляем новый элемент на непервое место
if (Current->Next != NULL) Current->Next->Prior = NewItem;
NewItem->Next = Current->Next;
Current->Next = NewItem;
NewItem->Prior = Current;
Current = NewItem;
}
}
return Head;
}
Last updated