
- •9 Лінійні списки. Основні визначення та поняття. Однонаправлені списки. Двонаправлені списки. Циклічні списки. Організація списків.
- •Тема 10 Масиви. Множини I кортежі. Зберігання множин і масивів. Зберігання розріджених матриць. Операції з масивами, множинами та кортежами
- •Тема 11 Нелінійні структури даних. Класифікація нелінійних структур даних. Таблиці. Зображення таблиць. Основні операції з таблицями.
- •Тема 12. Спискові структури. Основні поняття. Ієрархічні списки. Сіткові структурі. Організація спискових структур.
- •Тема 13. Пошук даних. Послідовний пошук. Двійковий пошук. Алгоритм Кнута, Моріса, Пратта. Алгоритм Бойера-Мурра. Порівняння алгоритмічної складності методів
- •Тема 14. Дерева порівнянь на векторній пам‘яті. Дерева порівнянь на зчепленій пам‘яті. Пошук у таблицях з обчислюваними адресами. Таблиці з прямим доступом. Хеш-таблиці. Задача колізії.
Тема 12. Спискові структури. Основні поняття. Ієрархічні списки. Сіткові структурі. Організація спискових структур.
Рівень І
Сіткова структура це …
Це орієнований зв’язаний граф без циклів, у якого будь-який породжений вузол може мати більше одного породжуючого вузла і , крім того, всі вузли розміщуються так, що породжені елементи розміщуються нижче породжуючих.
Петля у сітковій структурі це…
Деколи записи файла зв’язані з іншими записами цього ж файла, таку ситуацію називають петлею.
Цикл у сітковій структурі.
Циклом вважається ситуація, коли попередник вузла водночас є його послідовником. Відношення вхідний – породжений утворюють при цьому замкнутий контур.
Решітка це…
Решіткою називають частковий випадок сіткової структури, в якій граф є кореневим і вхідні вузли деякого породженого вузла належать одному і тому самому рівню.
Тема 13. Пошук даних. Послідовний пошук. Двійковий пошук. Алгоритм Кнута, Моріса, Пратта. Алгоритм Бойера-Мурра. Порівняння алгоритмічної складності методів
Рівень ІІІ
Алгоритм послідовного або лінійного пошуку. Складність алгоритму.
Алгоритм L.
Таблиця містить п записів R1 ,..., Rп з ключами k1 ,..., kп . Необхідно знайти запис iз заданим ключем k.
L1. Ініціалізація індексу проходження таблиці: і=1.
L2. Якщо k=ki - кінець успішний; якщо ні, перехід на L3.
L3. Зміна індексу і =i+1.
L4. Перевірка умови i<n? Так: перехід на L2. Ні - кінець неуспішний.
Ефективність алгоритму можна оцінити, підрахувавши кількість виконаних порівнянь тих значень ключів, які приймають участь у пошуку. Середня кількість таких порівнянь дорівнює величині п. Таким чином асимптоматична складність алгоритму - O(n).
void search(int What, int* Where, int While)
{
Int res = -1;
std::cout<<"Results of searching: \n";
for (int i = 0; i < While; i++)
if (Where[i] == What)
res = i;
; if (i == -1)
std::cout<<”Not found.”;
else std::cout<<”Found at “<<i<<std::endl;
}
Алгоритм двійкового пошуку. Складність алгоритму.
Тоді алгоритм D пошуку ключа К у векторі КЛЮЧ(і;j) можна записати наступною послідовністю кроків:
Алгоритм D
D0. Ініціалізація індексів і, j .
D1. Повторювати кроки D2 - D5 доти, доки i<j.
D2. Обчислення індекcа кореня дерева: m=[(i+j)/2].
D3. Якщо [КЛЮЧ (m)]= К, то REZ= т, кінець.
D4. Інакше: якщо [ КЛЮЧ (т)] <K,
тo і=т +1 (пошук справа); перехід на D2.
D5. Інакше j=m-1 (пошук зліва); перехід на D2;
Основна задача полягає у виключенні на кожному кроці з подальшого пошуку як можна більшої кількості елементів. Оптимальним рішенням буде вибір середнього елемента, оскільки при цьому буде виключена половина кількості елементів. Максимальне число порівнянь дорівнює О(log2 n)
void search(int What, int* Where, int Size)
{
sort(Where, Size - 1);
if (isSorted(Where, Size) && Size && Where)
{
std::cout<<"Results of searching: \n";
bool f = false;
int first = 0;
int last = Size;
int middle = first + (last - first) / 2;
if (What < Where[0] || What > Where[Size - 1])
std::cout<<"element is out of range.\n";
else
while (first < last)
{
if (What <= Where[middle])
last = middle;
else
first = middle + 1;
middle = first + (last - first) / 2;
}
while (Where[last] == What)
{
f = true;
std::cout<<last++<<"\t";
}
if (!f)
std::cout<<"number not found. Try smth else.\n";
else
std::cout<<"\n";
}
else
std::cout<<"Unable to sort array "
"and use binary search "
"and / or array is empty.\n";
}
Алгоритм прямого пошуку стрічки. Складність алгоритму.
Нехай задано масив S з n елементів та масив P з m елементів, m<=n. Необхідно знайти перше входження масиву P у масив S . Алгоритм зводиться до повтору порівнянь окремих елементів.
Алгоритм R
R1. Встановити і=1.. n-m, j=1..m.
R2. Якщо S[i] = P[j] , то зафіксувати перше співпадіння k=i, та перевірити співпадіння всього масиву P у масиві S. При першому неспівпадінні відмінити значенняk та продовжити пошук.
R3. Кінець.
Кількість порівнянь дорівнює n*m.
void search(char *What, char *Where)
{
int i, j;
for (i = 0; i < strlen(Where) - strlen(What); i++)
{
bool hit = true;
for (j = 0; j < strlen(What); j++)
if (What[j] == Where[i + j])
continue;
else
{
hit = false;
break;
}
if (hit)
{
std::cout<<"hit at "<<i<<"\t";
i = i + j - 1;
}
}
std::cout<<std::endl;
}
Алгоритм Кнута, Моріса і Прата пошуку в стрічці. Складність алгоритму.
Маємо масив символів S з n елементів (текст) та масив P з m - взірець. Необхідно знайти перше входження взірця в масив. Схема алгоритму полягає у поступовому порівнянні взірця з текстом та зсуву по тексту на кількість співпавших символів у разі знайденого неспівпадіння. Алгоритм використовує просте спостереження, що коли відбувається неспівпадіння тексту і взірця, то взірець містить у собі достатньо інформації для того, щоб визначити де наступне входження може початися, таким чином пропускаючи кількаразову перевірку попередньо порівняних символів. Попередньо проводиться дослідження взірця та визначається максимально можливий зсув взірця по тексту Dmax. Для цього вираховується відстань між однаковими символами у взірці, якщо такі є, інакше Dmax = m .
Алгоритм КМП
КМП 1. Встановити і=0.
КМП 2. j=0, d=1.
КМП 3. Поки j<m, i<n
Перевірка: якщо S[i]=P[j], то d++, i++.j++ поки d != m.
КМП 4. Інакше встановити зсув взірця на d позицій по тексту якщо d <. Dmax , або на Dmax позицій якщо d > Dmax .Перейти на крок КМП 2.
КМП 5. Кінець.
Складність алгоритму становить O(n+m).
int FindDmax(char *pS)
{
int len=strlen(pS);
int Dmax=len;
for (int i=0; i<len; i++)
{
for (int j=i+1; j<len; j++)
if (pS[i]==pS[j])
if (j-i<Dmax)
{
Dmax=j-i;
break;
}
}
return Dmax;
}
int KMPSearch (char *pS, char *pW, int Dmax)
{
int SLen=strlen(pS);
int WLen=strlen(pW);
int i;
for (i=0; i<SLen-WLen+1;)
{
if (pS[i]!=pW[0])
{
i++;
continue;
}
int j;
int k=i;
for (j=0; j<WLen; j++)
{
if (pS[k]==pW[j])
k++;
else
break;
}
if (j==WLen)
return i;
else
if (Dmax<=j)
i+=Dmax;
else
i+=j;
}
return -1;
}
Алгоритм Бойера – Мура пошуку у стрічці. Складність алгоритму.
В даному алгоритмі розглядається поняття стоп-символа - це є символ в тексті, який є першим неспівпадінням тексту і взірця при порівнянні справа (з кінця взірця). Розглянемо три можливих ситуації:
1. Стоп-символ у взірці взагалі не зустрічається, тоді зсув дорівнює довжині взірця m.
2. Крайня права позиція k входження стоп-символа у взірці є меншою від його позиції j у тексті. Тоді взірець можна зсунути вправо на k-j позицій так, щоб стоп-символ у взірці і тексті опинились один під одним.
3. Крайня права позиція k входження стоп-символа у взірці є більшою від його позиції j у тексті. Такий зсув ігнорується.
У третій ситуації необхідно знайти співпадіння взірця і тексту. Якщо у взірці є ще один такий самий символ, то необхідно зсунути взірець до співпадіння цього символу з символом в тексті. Інакше зсув дорівнює 1.
Алгоритм B:
[string, substring] – string - рядок, substring - підрядок
B1. Ініціалізація. j = m , d = 1;
B2. Перевірка. Якщо Ai = Pj, то перевіряємо входження рядка P в A
починаючи з позиції k = i + m - 1, при цьому при кожному співпадіні j--, k--. Якщо
j<= 0 переходимо на крок B5, інакше переходимо на крок B3.
B3. Зсув. Якщо елемент k присутній в шуканому слові, то находимо його
позицію в слові починаючи з права, та зсуваємо все слово вправо на позицію
k-ого символа в шуканому слові, віднявши при цьому 1. Інакше зсуваємо слово
на m - 1.
B4. Повторення. Повторюємо крок B2 поки i <= n.
B5. Вихід.
АЛАРМ!! Цей алгоритм такий який в методичці але насправді це спрощений варіант оригінального БМ
int BMsearch(char* str, const char* word)
{
int M=strlen(word);
int d[256];
for(int i=0;i<256;i++)
{
d[i]=M;
}
M--;
for(int i=0;i<M;i++)
{
d[(unsigned char)word[i]]=M-i;
}
for(int i=M;;i+=d[(unsigned char)str[i]])
{
for(int j=M, k=i;;k--, j--)
{
if(j<0)
{
return i-M;
}
else if(str[k]!=word[j])break;
}
if(!str[i])break;
}
return -1;
}