Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
РП_31_АСД.pdf
Скачиваний:
164
Добавлен:
23.02.2016
Размер:
2.92 Mб
Скачать

Тема 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