
- •1. Сортування
- •1.1. Сортування масивів
- •1. Сортування простими включеннями;
- •2. Сортування простим вибором;
- •1.1.1. Сортування простими включеннями
- •1.1.2. Сортування простим вибором
- •1.1.3. Сортування простим обміном (засіб “бульбашки”)
- •1.1.4. Шейкер-сортування
- •1.1.5. Швидке сортування
- •1.2. Сортування масива рядків
- •1.3. Сортування файлів
- •2. Рекурсивні алгоритми
- •2.1. Алгоритми з поверненням
- •2.1.1. Шахова задача про хід коня
- •2.1.2. Шахова задача про вісім ферзів
- •3. Динамічні інформаційні структури
- •3.1. Динамічні змінні. Вказівники
- •3.1.1. Засоби створення та використання динамічних даних
- •3.2. Рекурсивні типи даних
- •3.3. Списки
- •3.3.2. Двозв’язні та кiльцевi списки
- •3.3.3. Черги і стеки
- •3.4. Деревовидні структури
- •3.4.1. Бінарні дерева
- •3.4.2. Ідеально збалансовані дерева
- •3.4.3. Дерева пошуку
- •3.4.4. Збалансовані дерева (авл-дерева)
- •4. Завдання до лабораторних та контрольних робіт.
- •4.1. Сортування.
- •4.2. Списки.
2.1. Алгоритми з поверненням
Такі алгоритми використовуються для задач, пов’язаних з “штучним інтелектом”. Вони характерні тим, що вирішують задачу не за фіксованими правилами, а методом спроб і помилок. Процес спроб і помилок поділяється на окремі підзадачі, які набільш природно описуються за допомогою рекурсії.
2.1.1. Шахова задача про хід коня
Дана дошка, розміром n x n, яка має n x n полів. Кінь, що може ходити за шаховими правилами, розміщується на полі з координатами x0, y0. Hеобхідно конем пройти по всім полям дошки, тобто виконати обхід дошки, якщо він існує, за (n*n ‑ 1) ходів, за умови, що на кожне поле кінь стає тільки один раз.
Очевидним є такий алгоритм: або виконати наступний хід, або він неможливий.
Procedure <Cпроба_наступного_ходу>;
Begin
Repeat
<вибір наступного з можливих ходів> {із списка чергових ходів}
If <хід можливий> Then
Begin
<записуємо хід>
If <дошка не заповнена> Then
Begin
<спроба наступного ходу>
If <невдача> Then
<видалення попереднього ходу>
End
End
Until <хід був вдалим> or <немає інших можливих ходів>
End
Виберемо подання для даних.
Дошку можна представити у вигляді матриці h розміром n x n.
Type
index=1..n;
Var
h : array [index,index] Of integer;
Для того, щоб мати історію “захвату” дошки, кожне захвачене поле будем позначати не булевим виразом, який тільки б підтверджував факт зайнятості, а цілим числом – порядковим номером ходу.
Для цього можна прийняти такі узгодження:
h[x,y]=0 – поле (x,y) не відвідувалось
h[x,y]=i – поле відвідувалося на i-тому ходу (1<= i <= n * n)
Параметри процедури повинні визначати початкові умови для наступного ходу, а також повідомляти про його вдалість чи невдалість. Початкові умови для наступного ходу визначаються заданням координат поля x, y, з якого треба робити хід, а також номером ходу i (для його фіксації). Для рішення останньої задачі необхідний булевий параметр-результат:
q=true – хід виконано;
q=false – хід не виконано.
Ще деякі узгодження:
якщо i<= n * n – дошка не заповнена;
якщо u та v – локальні змінні для координат ходу, то “хід можливий” за таких умов:
1<= u <=n та 1<= v <=n – тобто поле не за межами дошки
h[u,v]=0 – поле раніше не відвідувалось
фіксація ходу – h[u,v]=i;
стирання ходу – h[u,v]=0;
Звернемось до задачі:
Якщо задані початкові координати, то для наступного ходу є вісім різних можливостей вибору координат (u,v). Для того, щоб отримати з координат (x,y) координати (u,v), будемо додавати до них різниці координат, тобто відстань у клітинках поля від початкової позицїї коня до поточної, які будем зберігати у масивах a та b.
а= 2, 1, -1, -2, -2, -1, 1, 2
b= 1, 2, 2, 1, -1, -2, -2, -1
Рекурентна процедура перший раз викликається з параметрами x0,y0. Цьому полю присвоюється індекс 1.
{ “Хід коня” }
Program KnightSTore;
Const
n=5;
nsq=25;
Type
index=1..n;
Var
i,j : integer;
q : boolean;
s : set Of index;
a,b : array [1..8] Of integer;
h : array [index,index] Of integer;
Procedure Try(i:integer; x,y:index; Var q:boolean);
Var
k,ux,vy : integer;
q1 : boolean;
Begin
k:=0;
Repeat
k:=k+1;
q1:=false;
ux:=x+a[k];
vy:=y+b[k];
If (ux in s) and (vy in s) Then
If h[ux,vy]=0 Then
Begin
h[ux,vy]:=i;
If i<nsq Then
Begin
Try (i+1,ux,vy,q1);
If Notq1 Then
h[ux,vy]:=0;
End
Else
q1:=true;
End;
Until q1 or (k=8);
q:=q1;
End; {Try}
{—————————————————————————}
Begin
s:=[1,2,3,4,5];
a[1]:=2; b[1]:=1;
a[2]:=1; b[2]:=2;
a[3]:=-1; b[3]:=2;
a[4]:=-2; b[4]:=1;
a[5]:=-2; b[5]:=-1;
a[6]:=-1; b[6]:=-2;
a[7]:=1; b[7]:=-2;
a[8]:=2; b[8]:=-1;
{—————очистити дошку———————————}
For i:=1 To n Do
For j:=1 To n Do
h[i,j]:=0;
{—————починаємо з першої позиції————}
h[1,1]:=1;
Try(2,1,1,q);
Ifq Then
For i:=1 To n Do
Begin
For j:=1 To n Do
Write(h[i,j]:5);
Writeln;
End
Else
Writeln(‘Немає рішення’);
End.
Загальна схема алгоритма з поверненням назад має вигляд:
Procedure Try;
Begin
<ініціювати вибір можливих кроків>
Repeat
<вибрати наступний крок>
If <можливо> Then
Begin
<запам’ятати його>
If <рішення неповне> Then
Begin
<спробувати наступний крок>
If <невдача> Then
<стерти запис>
End;
End;
Until <хід зроблено> або <хід неможливий>;
End
Якщо кількість досліджуваних подальших путів розв’язку фіксовано, наприклад, m, тоді процедура може мати такий вигляд:
Procedure Try(i:integer);
Var
k:integer;
Begin
k:=0;
Repeat
k:=k+1;
If <можливий> Then
Begin
<записати>
If i<n Then
Begin
Try(i+1);
If <невдача> Then
<витерти запис>
End;
End;
Until <успіх> або (k=m);
End;