За кількістю зв‟язків між елементами списки бувають:
однозв‟язні;
двозв‟язні.
За топологією списки можуть бути:
лінійні;
циклічні.
Список, який було розглянуто у цьому розділі, є лінійний однозв‟язний (однонапрямлений). У такому списку кожний попередній елемент посилається на наступний, і за таким списком можна рухатися лише у напрямку від першого елемента до останнього (лінійно). Інакше кажучи, елементи лінійного списку і зв‟язки поміж ними можна розташувати у пряму лінію, окрім того, зв‟язки поміж елементами мають чіткий і незмінний напрямок.
Інколи виникає потреба проходити за списком в обох напрямках і “знати” не лише наступний елемент, а й попередній. У такому разі до елемента слід долучити ще одне поле – адресу попереднього елемента, тобто кожний елемент матиме два зв‟язки з сусідніми елементами. На рисунку це позначається двома стрілками: вліво (зв‟язок елемента з попереднім) і вправо (зв‟язок елемента з наступним). Такий список називається лінійним двозв‟язним (двонапрямленим), оскільки зв‟язки мають два напрямки: від першого елемента до останнього і від останнього до першого. Схематично зобразити цей список можна так:
first
last
0
4
–5
0
1
8
0
Кожний елемент, окрім поля з даними, має два додаткових поля, які містять адреси попереднього й наступного елементів. Унаслідок цього виникає можливість проходження за списком у якому завгодно напрямку.
Оголошення лінійного двозв‟язного списку має вигляд:
struct Element
{ int d; Element* next; Element* prev; };
Функція створення першого елемента масиву: void fir(int x)
Приклад 13.7 Створити список з інформацією про маршрут руху автобуса: назва станції й час, який минув від виїзду з кінцевого пункту до приїзду на зазначену станцію. Перевірити, чи є у списку інформація про зворотний рух (назва першої станції збігається з назвою останньої, назва другої – з назвою передостанньої тощо). Визначити назву кінцевої станції та час у дорозі.
Розв‟язок. Оскільки для порівняння назв станцій треба буде йти за списком водночас з обох кінців, список має бути двонапрямленим лінійним.
464
Розділ 13
З умови завдання невідомо, чи уведено станції до списку за зростанням часу, який минув від моменту відправлення. Тому при створюванні списку слід долучати кожний новий елемент так, щоб наприкінці введення список був відсортованим за зростанням часу руху.
for (int i=1; i<StringGrid1->RowCount; i++) for (int j=0; j<2; j++)
StringGrid1->Cells[j][i]="";
for (int i=1; i<StringGrid2->RowCount; i++) for (int j=0; j<2; j++)
StringGrid2->Cells[j][i]="";
}
468
Розділ 13
У циклічному однозв‟язному списку за останнім елементом знов іде перший елемент. Це означає, що у полі next останнього елемента записано адресу першого елемента, тобто
last->next=first;
Схематично такий список можна зобразити як
first
last
4
–5
0
1
8
адреса
адреса
адреса
адреса
адреса
–5
0
1
8
4
чи як
–5
0
first
4
last 1
8
Оголошення циклічного однозв‟язного списку буде таким самим, як оголошення лінійного однозв‟язного списку.
Функція створювання першого елемента:
void fir(int x)
{ first=new Element;
first
first->d=x;
4
first->next=first;
last=first;
}
Функція долучення нового елемента до списку (між останнім і першим):
void add_el(int x)
first
{ Element* c=new Element;
c
4
c->d=x;
c->next=first;
1
last->next=c;
last=c;
}
–5
Функція виведення списку до Memo:
0
void print_el(TMemo* memo)
{ Element* c=first; last if(first==0) {ShowMessage ("Empty"); return;} do{
memo->Lines->Add(IntToStr(c->d)); c=c->next;
}while(c!=first); // Допоки не дістались першого елемента