- •Тема 2. ЕТАПИ РОЗВИТКУ ТЕОРІЇ АЛГОРИТМІВ ТА ЇЇ ЗАСНОВНИКИ
- •Тема 3. МОДЕЛІ ОБЧИСЛЕНЬ
- •Тема 4. ПОНЯТТЯ СТРУКТУР ДАНИХ
- •Тема 5 СТРУКТУРНІСТЬ ДАНИХ І ТЕХНОЛОГІЯ ПРОГРАМУВАННЯ
- •Тема 6. ІНФОРМАЦІЙНА МОДЕЛЬ
- •Тема 7. ПОКАЖЧИКИ ТА ОПЕРАЦІЇ НАД НИМИ
- •Тема 8. ФІЗИЧНА СТРУКТУРА ПОКАЖЧИКА
- •Тема 9. ПРЕДСТАВЛЕННЯ ПОКАЖЧИКІВ У МОВАХ ПРОГРАМУВАННЯ
- •Тема 10. ВИДІЛЕННЯ ТА ЗВІЛЬНЕННЯ ДИНАМІЧНОЇ ПАМ'ЯТІ
- •Тема 11. ПРИКЛАДИ РОБОТИ З ДИНАМІЧНИМИ ЗМІННИМИ
- •Тема 12. ЗАГАЛЬНА ХАРАКТЕРИСТИКА СПИСКОВИХ СТРУКТУР ДАНИХ
- •Тема 13. ЗВ’ЯЗНЕ ПРЕДСТАВЛЕННЯ ДАНИХ В ПАМ'ЯТІ КОМП’ЮТЕРА
- •Тема 14. СТЕКИ
- •Тема 15. МАШИННЕ ПРЕДСТАВЛЕННЯ СТЕКА І РЕАЛІЗАЦІЯ ОПЕРАЦІЙ
- •Тема 16. ЧЕРГИ
- •Тема 17. МАШИННЕ ПРЕДСТАВЛЕННЯ ЧЕРГИ. ЧЕРГИ З ПРІОРИТЕТАМИ. ДЕКИ.
- •Тема 18. ЛІНІЙНІ СПИСКИ
- •Тема 19: ДВОНАПРЯМЛЕНІ ЛІНІЙНІ СПИСКИ
- •Тема 20. ДЕРЕВА. СТВОРЕННЯ ТА ОБХІД БІНАРНОГО ДЕРЕВА
- •Тема 21: ЕЛЕМЕНТИ ТА ВЛАСТИВОСТІ БІНАРНОГО ДЕРЕВА
- •Тема 22. ОПЕРАЦІЇ З ВУЗЛАМИ ДЕРЕВА
- •Тема 23: АЛГОРИТМИ ВИЗНАЧЕННЯ ВЛАСТИВОСТЕЙ БІНАРНОГО ДЕРЕВА
- •Тема 24. ПОНЯТТЯ ГРАФА ТА ЙОГО ЗОБРАЖЕННЯ В ПАМ'ЯТІ КОМП'ЮТЕРА
- •Тема 26. ОБХІД ГРАФУ: ПОШУК ВГЛИБИНУ
- •Тема 27. ОБХІД ГРАФУ: ПОШУК УШИР
- •Тема 28. КЛАСИЧНІ АЛГОРИТМИ СОРТУВАННЯ ОДНОРІДНИХ ДАНИХ
- •Тема 29. ШВИДКІ АЛГОРИТМИ СОРТУВАННЯ ОДНОРІДНИХ ДАНИХ
- •Тема 30. КЛАСИЧНІ АЛГОРИТМИ ПОШУКУ ДАНИХ ЗА ЗАДАНИМИ КРИТЕРІЯМИ
- •Тема 31. КЛАСИФІКАЦІЯ КРИТЕРІЇВ ПОШУКУ ДАНИХ У МАСИВАХ
- •Тема 32. КРИПТОГРАФІЧНІ ЗАСОБИ ЗАХИСТУ ІНФОРМАЦІЇ
- •Тема 33. ПРОБЛЕМИ І ПЕРСПЕКТИВИ КРИПОТГРАФІЧНИХ СИСТЕМ
- •Тема 34. АЛГОРИТМИ ШИФРУВАННЯ
- •Тема 36. ПОКАЗНИКИ СКЛАДНОСТІ АЛГОРИТМІВ
Тема 18. ЛІНІЙНІ СПИСКИ
Стек і черга є лінійними списками, множина допустимих операцій над якими обмежена операціями над першим або останнім елементом. Далі розглядатимуться списки, над якими припустимі довільні дії. Найбільш ефективно у спискових структурах реалізуються операції вставки та видалення елементів, оскільки вони, на відміну від операцій видалення і вставки елементів масиву, не потребують зсуву групи елементів. В наступному списку представлені всі можливі варіанти застосування цих двох операцій:
∙створення списку, тобто внесення першого елемента до списку;
∙додавання елемента в кінець списку;
∙додавання елемента на початок списку;
∙вставка елемента в середину списку;
∙видалення елемента з початку списку;
∙видалення елемента з кінця списку;
∙видалення елемента з середини списку.
Узагальному випадку для роботи з однозв’язним лінійним списком потрібні такі
покажчики:
∙покажчик head на початок списку;
∙покажчик current на поточний елемент списку;
∙покажчик previous на елемент, розташований перед поточним;
∙покажчик newptr на елемент, що додається до списку;
∙покажчик last на кінець списку.
Урозв’язаннях конкретних задач можуть використовуватися не всі покажчики.
Далі розглядатимуться алгоритми основних операцій над однозв’язним лінійним списком. Кожний елемент однозв’язного списку можна реалізувати записом Item вигляду:
Item=record |
{тип елементу списку} |
data:string; |
{інформаційне поле елемента} |
next:ptr; |
{покажчик на наступний елемент} |
end; |
|
Додавання елемента в кінець списку виконується за алгоритмом додавання елемента до черги, а додавання елемента на початок списку – за алгоритмом додавання елемента до стеку. Ці операції вже розглядалися в попередніх лекціях. Так само вже розглядалася операція видалення елемента з початку списку, що здійснюється за алгоритмом видалення елемента зі стеку або черги.
Залишилося розглянути решту операцій, припускаючи, що при додаванні елемента для
нього вже була створена динамічна змінна newptr^ та було введене значення у його поле data.
Алгоритм створення одноелементного списку
1.Ініціалізувати початок списку: head:=newptr;
2.Ініціалізувати кінець списку: last:=newptr;
3.Записати ознаку того, що перший елемент є останнім: head^.next:=nil.
Алгоритм вставки елемента всередину списку
Нехай новий елемент має бути вставлений між елементами previous^ та current^ (рис.1).
1.Новий елемент вважати наступним для previous^: previous^next:=newptr.
2.Елемент current^ вважати наступним для нового елемента: newptr^.next:=current.
54
|
|
|
|
|
previous |
|
|
|
|
|
|
|
current |
|
|
|
|
|
head |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
data |
next |
|
|
data |
next |
|
|
|
|
|
|
data |
|
next |
|
data |
nil |
|
|
|
|
|
|
|
|
|
|
|
|||||||||
|
|
|
previous^.next:=newptr |
|
|
|
|
newptr^.next:=current |
|
|||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
newptr |
|
data |
next |
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Рис.1. Вставка елемента в середину списку
Алгоритм видалення елемента зсередини списку
Нехай видаляється елемент current^, розташований безпосередньо за елементом previous^ (рис.2).
1.Вважати, що за елементом previous^ буде розташований той елемент, що раніше знаходився за елементом current^: previous^.next:= current^.next;
2.Звільнити пам'ять із-під елемента current^: Dispose(current);
|
|
|
|
previous |
|
|
current |
|
|
|
|
|
head |
|
|
|
|
|
|
|
|
|
|
|
|
data |
next |
|
data |
|
next |
|
data |
next |
|
data |
nil |
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
previous.next:=current.next |
|
|
Рис.2. Видалення елемента зсередини списку
Алгоритм видалення елемента з кінця списку
Нехай на передостанній елемент посилається покажчик previous.
1.Записати до передостаннього елемента ознаку кінця списку: previous^.next:=nil;
2.Звільнити пам'ять із-під колишнього останнього елемента: Dispose(last);
3.Вважати останнім колишній передостанній елемент: last:= previous.
Програмна реалізація вище наведених алгоритмів представлена в прикладі обробки впорядкованого за алфавітом списку слів. Вважається, що користувач може додавати та видаляти слова зі списку і при цьому список має залишатися впорядкованим. Видалення відбувається так: користувач вводить деяке слово, а програма шукає це слово в списку. Якщо слово, знайдене, програма його видаляє, якщо ні – відображає повідомлення про безрезультатність пошуку.
Алгоритм роботи з алфавітним переліком слів з використання спискових структур
1.Вважати список порожнім
2.Вивести меню для роботи зі списком.
3.Якщо натиснута клавіша I, додати елемент до списку.
3.1.Виділити пам'ять для нового елемента.
3.2.Ввести нове слово та ініціалізувати ним поле даних нового елемента.
3.3.Якщо список порожній, вважати щойно утворений елемент списком.
3.4.Якщо список непорожній, визначити місце розташування нового елемента та вставити його до списку.
4.Якщо натиснута клавіша D, видалити елемент зі списку.
4.1.Ввести слово, що видаляється.
4.2.Якщо список порожній, вивести відповідне повідомлення.
55
4.3.Якщо список непорожній, проглядати значення елементів списку доти, доки введене слово не буде знайдено або доки список не буде вичерпано.
4.4.Якщо елемент із введеним значенням поля даних було знайдено, то його слід видалити.
4.5.Якщо введене слово не збігається зі значенням інформаційного поля жодного елемента списку, вивести повідомлення про відсутність шуканого елемента у списку.
5.Якщо натиснута клавіша Q, вийти з програми.
Програма Yrok8 реалізує розглянутий алгоритм. Крім процедур вставки та видалення, на увагу в цій програмі заслуговують:
∙функція SearchPlaceDelete, що виконує пошук введеного слова у списку;
∙процедура SearchPlaceInsert, яка відшукує позицію для вставки нового елемента.
Вобох цих підпрограмах здійснюється послідовний перебір елементів списку, під час якого шляхом циклічного виконання присвоєння current:=current^.next змінюється значення
покажчика current. Оскільки елемент, на який посилається покажчик previous, має бути попереднім для елемента, що на нього посилається current, то перш ніж змінна current набуде нового значення, її старе значення має бути збережене у змінній previous.
program Yrok8; {$APPTYPE CONSOLE}
uses |
|
|
SysUtils; |
|
|
type |
|
|
ptr=^Item; |
{тип покажчика на елемент} |
|
Item=record |
{тип елементу списку} |
|
data:string; |
{інформаційне поле елемента} |
|
next:ptr; |
{покажчик на наступний елемент} |
|
end; |
|
|
var |
|
|
head: |
ptr; |
{покажчик на початок списку} |
newptr: |
ptr; |
{покажчик на елемент, що вводиться} |
current: ptr; |
{покажчик на поточний елемент} |
|
previous: ptr; |
{покажчик на попередній елемент} |
|
ch: char; |
|
{код дії над елементом списку} |
str: string; |
{значення елемента, що вводиться} |
|
flag: boolean; |
{ознака успішності пошуку} |
{====створення одноелементного списку====} procedure CreateFirstItem;
begin |
|
head:=newptr; |
{покажчик на вершину списку перемістити на перший елемент} |
head^.next:=nil; |
{покажчик на наступний елемент має значення nil} |
end;
{====вставка елемента на початок списку====} procedure InsertBeginning;
begin
newptr^.next:=head; {зв"язати новий елемент з вершиною списку}
head:=newptr; |
{перемістити вершину списку на елемент, що додається} |
end; |
|
56
{====пошук позиції вставки списку=====} procedure SearchPlaceInsert;
begin
current:=head; {поточний покажчик на початок списку} repeat
previous:=current; {покажчик на попередній елемент} current:=current^.next; {покажчик на наступний елемент}
if current=nil |
{якщо кінець списку,} |
then flag:=true {то ознака закінчення пошуку} |
else flag:=current^.data>=str; {інакше, ознака продовження пошуку} until flag;
end;
{====вставка елемента в середину списку=====} procedure InsertIntoMiddle;
begin
previous^.next:=newptr; {зв"язок попереднього і нового елементів} newptr^.next:=current; {зв"язок нового і наступного елементів} end;
{====додавання слова до списку=====} procedure Insert;
begin
write('input element: '); readln(str); {ввести значення елемента}
new(newptr); |
{виділити пам"ять для елемента} |
|
newptr^.data:=str; {занести значення в пам"ять} |
||
if head=nil |
{якщо список порожній} |
|
then CreateFirstItem {формувати перший елемент списку} |
||
else |
{якщо список непорожній} |
|
if str<=head^.data |
{якщо значення нового елемента менше значення першого} |
|
then InsertBeginning {вставити елемент на початок списку} |
||
else |
{якщо значення нового елемента більше значення першого елемента} |
|
begin |
|
|
SearchPlaceInsert; {пошук місця вставки} |
||
InsertIntoMiddle; |
{вставка елемента} |
|
end; |
|
|
end; |
|
|
{====видалення першого елемента списку=====} |
||
procedure DelFirst; |
|
|
begin |
|
|
head:=current^.next; |
{вершину списку перемістити на наступний елемент} |
|
dispose(current); |
{звільнити пам"ять} |
|
end; |
|
|
{====пошук елемента для видалення=====} function SearchPlaceDelete: boolean;
begin
repeat |
|
previous:=current; |
{переміщення покажчика від поперднього до поточного, доки} |
current:=current^.next; {не буде знайдено потрібний елемент або кінець списку}
57
until (current^.data=str) or (current^.next=nil); SearchPlaceDelete:=current^.data=str;
end;
{====видалення елемента з середини списку=====} procedure DelMiddle;
begin previous^.next:=current^.next;
dispose(current); {звільнити пам"ять} end;
{====видалення слова зі списку=====} procedure Delete;
begin
if head=nil then {Якщо список порожній, вивести повідомлення} begin
writeln('List is empty. Press ENTER ...');
readln; |
|
end |
|
else |
{якщо список непорожній} |
begin
write('input value: '); readln(str); {ввести слово, що видаляється}
current:=head; |
|
{покажчик на початок списку} |
if current^.data=str |
{якщо шуканий елемент є першим,} |
|
then DelFirst |
{то видалити перший елемент} |
|
else |
{якщо шуканий елемент не є першим} |
|
if SearchPlaceDelete {якщо слово знайдене, } |
||
then DelMiddle |
{то видалення елементу з середини списку} |
|
else |
{якщо слово не знайдене,} |
|
begin |
|
{то вивести повідомлення} |
writeln(str,' not found in list. Press ENTER ...'); readln;
end;
end;
end;
{====виведення списку=====} procedure OutList;
begin |
|
current:=head; |
{покажчик на початок списку} |
if current=nil |
{якщо список порожній,} |
then writeln('List is empty') {то вивести повідомлення}
else |
{якщо список непорожній,} |
begin |
|
write('output list: '); repeat
write(current^.data,' '); {вивести значення елемента} current:=current^.next; {перемістити покажчик на наступний елемент}
until current=nil; |
{доки не закінчиться список} |
end; |
|
58
writeln;
end;
{====Головна програма ====}
begin |
|
head:=nil; |
|
repeat |
|
OutList; |
{вивести список} |
writeln; |
|
write('enter comman: I - input D - delete Q - quit '); {меню програми}
readln(ch); |
|
case ch of |
|
'I': Insert; |
{вставити елемент у список} |
'D': Delete; |
{видалити елемент зі списку} |
end; |
|
until ch='Q'; |
{вийти з пр ограми} |
end. |
|
Результат роботи програ ми Yrok8 зображений на рис.1.
Рис.3 Результат роботи програми Yrok8. Обробка списку слів, впорядкованих за алфавітом
59