Зубенко, Омельчук - Програмування. Поглиблений курс
.pdf
Розділ IV. АЛГОРИТМИ
Стандартні узагальнені алгоритми. У стандартній бібліотеці ша-
блонів STL визначені узагальнені алгоритми для роботи з контейнер- ними типами (табл. 4.1). Для використання алгоритмів, що не зміню- ють елементів послідовності модифікуючих і сортувальних алгорит- мів, у програму потрібно ввести заголовний файл <algorithm>, а для обчислювальних алгоритмів – заголовний файл <numeric> (табл. 4.2).
Усі алгоритми реалізовані як шаблони функцій (див. підрозд. 3.12) і обробляють вхідну послідовність елементів контейнера, задану парою ітераторів [first, last) (останнім елементом, що обробляється, є last-1). Багато алгоритмів реалізовано в кількох варіантах, для різних наборів параметрів, тому тут наведені лише їхні назви. Деякі з пере- лічених тут алгоритмів уже згадувалися вище.
Таблиця 4.1. Алгоритми, визначені в <algorithm>
Функція |
|
Призначення |
|
|
adjacent_find |
Пошук першої пари збіжних елементів |
|
||
binary_search |
Перевірка входження заданого елемента в упо- |
|||
Copy |
рядкований інтервал |
|
|
|
Копіювання вхідного інтервалу в новий контейнер |
||||
copy_backward |
Копіювання вхідного інтервалу в новий кон- |
|||
count |
тейнер у оберненому порядку |
|
|
|
Підрахунок кількості елементів у інтервалі |
|
|||
count_if |
Підрахунок кількості елементів у інтервалі, що |
|||
equal |
відповідає заданому предикату |
|
||
Бінарний пошук у інтервалі інтервалу елемен- |
||||
equal_range |
тів, що дорівнюють заданому елементу |
|
||
Бінарний пошук у впорядкованому інтервалі ін- |
||||
|
тервалу елементів, що дорівнюють заданому еле- |
|||
fill |
менту |
|
|
|
Заповнює інтервал заданим значенням |
|
|||
fill_n |
Заповнює |
контейнер, |
починаючи |
з |
find |
n-го елемента, заданим значенням |
|
||
Заповнює перші n елементів заданим значен- |
||||
find_end |
ням |
|
|
|
Пошук у одному інтервалі останнього входжен- |
||||
find_first_of |
ня іншого |
|
|
|
Пошук у першому інтервалі одного зі значень |
||||
find_if |
другого інтервалу |
|
|
|
Пошук у інтервалі елемента, що задовольняє |
||||
for_each |
предикат |
|
|
|
Застосовує задану функцію (функтор) до всіх |
||||
|
елементів інтервалу |
|
|
|
521
ПРОГРАМУВАННЯ
|
Продовження табл. 4.1. |
|
Функція |
Призначення |
|
generate |
Заповнює інтервал значеннями, що обчислені |
|
generate_n |
заданою функцією (функтором) |
|
Заповнює перші n елементів контейнера зна- |
||
|
ченнями, що обчислені заданою функцією (фу- |
|
includes |
нктором) |
|
Перевіряє, чи входить один упорядкований |
||
inplace_merge |
інтервал у інший |
|
Злиття на місці |
||
iter_swap |
Обмінює значення елементів, що адресовані |
|
|
парою ітераторів, але не модифікує самі літе- |
|
lexicographical_compare |
ратори |
|
Лексикографічно попарно порівнює два інтер- |
||
lower_bound |
вали |
|
Бінарний пошук у впорядкованому інтервалі |
||
|
першого елемента, більшого чи рівного задано- |
|
make_heap |
му |
|
Конвертує елементи з діапазону в купу, в якій |
||
|
перший елемент є найбільшим і для якої кри- |
|
|
терій сортування може бути визначений бінар- |
|
max |
ним предикатом |
|
Порівняти два елементи. Порівнює два об'єкти |
||
|
й повертає більший із двох, де критерій може |
|
max_element |
бути визначений бінарним предикатом |
|
Знаходить перше входження найбільшого еле- |
||
|
мента в зазначеному діапазоні, де критерій |
|
|
пошуку може бути визначений бінарним пре- |
|
merge |
дикатом |
|
Запис об'єднаної послідовності в нову |
||
min |
Порівняти два елементи. Порівнює два об'єкти |
|
|
й повертає менший із двох, де критерій може |
|
min_element |
бути визначений бінарним предикатом |
|
Знаходить перше входження найменшого еле- |
||
|
мента в зазначеному діапазоні, де критерій |
|
|
пошуку може бути визначений бінарним пре- |
|
mismatch |
дикатом |
|
Пошук перших незбіжних елементів у двох по- |
||
next_permutation |
слідовностях |
|
Отримати наступну перестановку |
||
nth_element |
Елементи, менші за n-й, переміщуються ліво- |
|
partial_sort |
руч від нього, а більші – праворуч |
|
Сортування початкової частини інтервалу |
||
partial_sort_copy |
Сортування початкової частини інтервалу з |
|
|
копіюванням результату в новий контейнер |
522
|
Розділ IV. АЛГОРИТМИ |
|
|
Продовження табл. 4.1. |
|
Функція |
Призначення |
|
partition |
Переставлення елементів, що задовольняють |
|
pop_heap |
заданий предикат, на початок інтервалу |
|
Видаляє найбільший елемент від початку купи |
||
|
до останнього положення в діапазоні й потім |
|
prev_permutation |
формує нову купу з елементів, що залишилися |
|
Отримати попередню перестановку |
||
push_heap |
Додає елемент із кінця діапазону до існуючої |
|
|
купи, що складається з елементів, які передують |
|
random_shuffle |
діапазону |
|
Випадкова перестановка елементів інтервалу |
||
remove |
Видалити з інтервалу всі елементи, що дорів- |
|
remove_copy |
нюють заданому |
|
Видалити з інтервалу всі елементи, що дорів- |
||
|
нюють заданому, результат скопіювати в новий |
|
remove_copy_if |
контейнер |
|
Видалити з інтервалу всі елементи, що задово- |
||
|
льняють заданий предикат, результат скопію- |
|
remove_if |
вати в новий контейнер |
|
Видалити з інтервалу всі елементи, що задово- |
||
replace |
льняють заданий предикат |
|
Замінити всі елементи інтервалу, що дорівню- |
||
replace_copy |
ють заданому, на нові |
|
Замінити всі елементи інтервалу, що дорівню- |
||
|
ють заданому, на нові, результат скопіювати в |
|
replace_copy_if |
новий контейнер |
|
Замінити всі елементи інтервалу, що задоволь- |
||
|
няють заданий предикат, на нові, результат |
|
replace_if |
скопіювати в новий контейнер |
|
Замінити всі елементи інтервалу, що задоволь- |
||
reverse |
няють заданий предикат, на нові |
|
Переставити елементи інтервалу в оберненому |
||
reverse_copy |
порядку |
|
Переставити елементи інтервалу в оберненому |
||
|
порядку, результат скопіювати в новий кон- |
|
rotate |
тейнер |
|
Циклічна перестановка елементів інтервалу |
||
rotate_copy |
Циклічна перестановка елементів інтервалу, |
|
search |
результат скопіювати в новий контейнер |
|
Пошук в одному інтервалі першого входження |
||
search_n |
іншого |
|
Пошук інтервалу з n елементів, що дорівнюють |
||
set_difference |
заданому |
|
Різниця множин-інтервалів |
523
ПРОГРАМУВАННЯ
|
|
Закінчення табл. 4.1. |
|
Функція |
|
Призначення |
|
set_intersection |
|
Перетин множин-інтервалів |
|
|
|||
set_symmetric_difference |
Симетрична різниця множин-інтервалів |
||
set_union |
|
Об'єднання множин-інтервалів |
|
sort |
|
Сортування інтервалу |
|
sort_heap |
|
Конвертує купу до діапазону, що сортується |
|
stable_partition |
|
Перестановка елементів, що задовольняють |
|
|
|
заданий предикат, на початок інтервалу зі збе- |
|
stable_sort |
|
реженням відносного порядку елементів |
|
|
Перестановка елементів, що задовольняють |
||
swap |
|
заданий предикат, на початок інтервалу |
|
|
Обмінює значення об'єктів |
||
swap_ranges |
|
Обмінює значення із двох інтервалів |
|
transform |
|
Застосовує задану функцію (функтор) до зада- |
|
|
|
ного інтервалу (інтервалів) з отриманням нової |
|
unique |
|
послідовності елементів |
|
|
Видаляє з інтервалу однакові сусідні елементи, |
||
unique_copy |
|
залишаючи єдиний |
|
|
Видаляє з інтервалу однакові сусідні елементи, |
||
|
|
залишаючи єдиний; результат скопіювати в |
|
upper_bound |
|
новий контейнер |
|
|
Бінарний пошук у впорядкованому інтервалі |
||
|
|
першого елемента, більшого за заданий |
|
Таблиця 4.2. Алгоритми, визначені в заголовному файлі <numeric> |
|||
Функція |
|
Призначення |
|
accumulate |
Обчислює суму значень елементів послідовності з |
||
|
діапазону [first, last) з початковим значен- |
||
|
ням. Наприклад, якщо задана послідовність |
||
|
{1,2,2,4,5} і початкове значення 0, то результатом |
||
|
роботи алгоритму буде 14. Операція додавання |
||
|
може бути замінена іншою бінарною операцією, |
||
adjacent_difference |
що передається як параметр |
||
Обчислює часткову різницю. Створює нову послі- |
|||
|
довність, в якій значення кожного елемента (крім |
||
|
першого, що рівний першому елементу вихідного |
||
|
інтервалу) дорівнює різниці поточного елемента та |
||
|
його попередника у вихідній послідовності із за- |
||
|
даного діапазону. Наприклад, якщо маємо {1, 3, 4, |
||
|
5, 5, 7}, то результатом буде {1, 2, 1, 1, 0, 2}. За- |
||
|
мість різниці у вихідну послідовність може бути |
||
|
записаний результат деякої іншої узагальненої |
||
|
процедури, яка є бінарною операцією |
||
524
|
Розділ IV. АЛГОРИТМИ |
|
|
|
|
Функція |
ПризначенняЗакінчення табл. 4.2. |
|
inner_product |
Знаходить скалярний добуток двох послідовно- |
|
|
||
|
стей з інтервалів. Наприклад, якщо послідовності |
|
|
{1, 2, 4} та {1, 1, 2}, то результатом буде |
|
|
1*1+2*1+4*2=11. Замість операцій додавання та |
|
|
множення як параметри можна передати інші |
|
partial_sum |
бінарні операції |
|
Обчислює часткову суму. Створює нову послідов- |
|
|
|
ність із послідовності, обмеженої діапазоном |
|
|
[first, last]: у новій послідовності значення |
|
|
кожного елемента дорівнює сумі всіх попередніх, |
|
|
включаючи й поточний. Наприклад, з послідовно- |
|
|
сті {0, 1, 2, 2} буде створена послідовність {0, 1, 3, |
|
|
5}. Замість операції суми можна використовувати |
|
|
іншу бінарну операцію |
|
*Література для CР:. динамічні структури даних і алгоритми на них – [8, 60, 65, 77, 95, 124, 125].
Контрольні запитання та вправи
1.Що таке динамічні структури даних?
2.Що таке зв'язаний список?
3.Як реалізується однозв'язний список?
4.Які основні операції над однозв'язними списками?
5.Як реалізується двозв'язний список?
6.Як реалізуються стеки й операції на них?
7.Як реалізуються черги й операції на них?
8.Яка відмінність між стеком і чергою?
9.Яка відмінність зв'язаного списку від стеку й черги? 10. Як реалізується бінарне дерево?
11. Скільки всього є варіантів обходу бінарного дерева?
12. Що таке контейнер та ітератор?
13. Що таке послідовний контейнерний тип векторів?
14. Що таке послідовний контейнерний тип списків?
15. Що таке послідовний контейнерний тип двосторонніх черг? 16. Що таке асоційовані контейнерні типи відношень і множин? 17. Що таке стандартні узагальнені алгоритми?
18. Написати клас, що реалізує булеву алгебру множин цілих чи- сел з операціями та предикатами: введення-виведення, об'- єднання, перетин, різниця, симетрична різниця, включення, рівність, приналежність елемента множині. Множини подати
увигляді лінійного списку елементів.
525
ПРОГРАМУВАННЯ
19.Написати функції, що реалізують алгебру багаточленів від однієї змінної із цілими коефіцієнтами. Операції алгебри: введення-виведення, додавання, множення на одночлен і ба- гаточлен, ділення двох багаточленів (з остачею й часткою у вигляді багаточленів). Багаточлени подати як лінійний спи- сок пар (коефіцієнт, степінь змінної).
20.Циклічним називається список, останній елемент якого міс- тить не NULL, а показує на його голову. Реалізувати основні
операції для роботи з такими списками.
21. Написати програму для розв'язання відомої задачі: n солда- тів стали в коло. Із k -го солдата починається рахування. Че- рез p солдатів той, на кого випало, виходить із кола, а раху-
вання починається знову з наступного солдата до тих пір, поки не залишиться останній. Знайти його номер. Застосу- вати циклічний список.
22.Написати програму для перетворення арифметичного вира- зу на форму ОПЗ, застосовуючи стек у вигляді масиву.
23.Реалізувати обчислення арифметичного виразу у формі ОПЗ.
24.Написати програму tail, що друкує n останніх введених ря- дків. За умовчанням n = 5 , але n може бути задано й у ко- мандному рядку. Командний рядок > tail - n викликає друкування останніх n рядків. У кожний момент зберігати в пам'яті не більше n рядків. Застосувати: а) чергу; б) цикліч- ний список у вигляді масивів.
25.Написати функції для роботи із чергами на основі лінійного списку, які здійснюють:
а) заміну k -го вузла в черзі;
б) вилучення k -го вузла із черги; в) конкатенацію кількох черг; г) розбиття черги на кілька черг; д) створення копії черги; е) визначення довжини черги;
є) пошук вузла(ів) черги із заданими властивостями.
26.Написати програму на основі однозв'язного списку, що дозво- ляє додавати й видаляти дані списку, шукати інформацію, збе- рігати список у файл і зчитувати його з файла для таблиць:
а) каталог книг у бібліотеці; б) список студентів у групі; в) список товарів у магазині ; г) список клієнтів банку; д) телефонний довідник.
27.Для таблиць із попереднього завдання написати програму на основі двозв'язного списку, що дозволяє додавати й видаля-
526
Розділ IV. АЛГОРИТМИ
ти дані списку, шукати інформацію за ключем, зберігати список у файл і зчитувати його з файла.
28.Для таблиць із вправи 26 написати програму на основі біна- рного дерева пошуку (порядок лексикографічний за ключо- вим полем), що дозволяє додавати й видаляти дані списку, шукати інформацію за ключем, зберігати список у файл і зчитувати його з файла.
29.Для лінійного однозв'язного списку цілих чисел від кожного додатного числа відняти найменше з додатних. Процедуру продовжувати, поки всі елементи списку не стануть від'єм- ними. Зазначити кількість ітерацій у процедурі.
30.Написати функцію, що читає з клавіатури дужковий вираз і перевіряє його на приналежність мові Діка: а) для дужок ( , ); б) для дужок (,),[,],{,}. Використати стек у динамічній пам'яті.
31.Написати функції для роботи із загальними списками з ато- мами-ідентифікаторами: 1) створення й виведення списку;
2)пошуку всіх атомів списку; 3) пошуку частоти входжень усіх атомів у список; 4) усунення й заміни одного атома на інший.
32.Для завдань 18-30 використати відповідні контейнерні типи. Проаналізувати, який із варіантів програми простіший для реалізації й розуміння.
4.4.Динамічні таблиці
¾Таблиці як масиви структур
¾Таблиці у вигляді зв'язаних списків
¾Підвищення ефективності при пошуку в таблицях
¾Пряма адресація
¾Хеш-таблиці з колізіями
¾Відкрите хешування
¾Закрите хешування
¾Таблиці у вигляді дерев пошуку
Ключові слова: таблиця як масив, рядок таблиці, операції з таблицями, до- давання й видалення рядка, пошук рядка, таблиця як зв'язаний список рядків, хеш- таблиця, хеш-функція, таблиця з прямою адресацією, колізія, відкрите й закрите хешування, лінійне хешування.
527
ПРОГРАМУВАННЯ
У підрозд. 4.1 розглядалася задача пошуку елементів у таблицях фік- сованої довжини. Ми вже знаємо, що таблиця – це кортеж векторів пев- ної фіксованої структури. Самі вектори називаються рядками таблиці й подаються зазвичай структурами. Наприклад, якщо таблиця має вигляд
Прізвище, ім'я, по-батькові |
Курс |
Середній бал |
Іваненко Іван Іванович |
2 |
4.25 |
Петренко Петро Петрович |
1 |
3.5 |
Сидоров Сидір Сидорович |
1 |
5 |
то її рядок можна описати таким чином:
typedef struct student { char *key;
int rate;
float estimationsult; }Student;
Основні операції з таблицями: додавання й видалення рядка, мо- дифікація рядка, пошук рядка за ключем.
Реалізація операцій над таблицями залежить від способу подання таблиць. Розглянемо ці способи.
4.4.1. ТАБЛИЦІ ЯК МАСИВИ СТРУКТУР
Найпростішим є подання таблиць у вигляді динамічних масивів їх- ніх рядків:
Student tableStArray[n];
Приклад 4.26. Таблиця як масив структур:
Лістинг.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <conio.h>
#int countLine=50;/*задає максимальну кількість рядків у таблиці*/
typedef struct student { char name[10];
int rate;
float estimationsult; }Student;
528
Розділ IV. АЛГОРИТМИ
typedef Student *StudentPtr;
Student tableStArray[countLine];
Student emptyCellArray;
/*ініціалізація інформації про студента*/ Student setEmtySt(Student st)
{
st.estimationsult=0; strcpy(st.name," "); st.rate=0;
return st;
}
/*друкування таблиці*/ void printArrayTable(void)
{
for(int i=0; i<countLine; i++) printf("\n%s\t%f\t%d", tableStArray[i].name,
tableStArray[i].estimationsult, tableStArray[i].rate);
}
/*ініціалізація таблиці*/ void ArrayTableInit(void)
{
emptyCellArray=setEmtySt(emptyCellArray); for(int i=0; i<countLine; i++)
tableStArray[i]=emptyCellArray;
}
/*пошук рядка в таблиці за ключовим полем name; результат – індекс рядка, якщо його знайдено, або countLine, якщо відповідного рядка немає*/
int ArrayTableFind(char key[10])
{
int i=0;
while((i<countLine)&&(strcmp(tableStArray[i].name, key))!=0) i++;
return i;
}
/*перевірка на рівність двох рядків*/ int StructEqual(Student st1, Student st2)
{
if((st1.rate==st2.rate)&&(st1.estimationsult==st2.estimation sult)&&(strcmp(st1.name, st2.name)))
return 1;
529
ПРОГРАМУВАННЯ
else return 0;
}
/*додавання рядка на першу вільну позицію в таблиці*/ void ArrayTableInsert(Student st)
{
int pos=ArrayTableFind(emptyCellArray.name); if(pos==countLine)
printf("\nТаблиця переповнена. Запис не відбув-
ся!!!\n");
else tableStArray[pos]=st;
}
/*видалення рядка за ключем*/
void ArrayTableDelete(char key[10])
{
int pos=ArrayTableFind(key); if(pos==countLine)
printf("Елемент для видалення не знайдено!"); else tableStArray[pos]=emptyCellArray;
}
■
4.4.2. ТАБЛИЦІ У ВИГЛЯДІ ЗВ'ЯЗАНИХ СПИСКІВ
Гнучкішим із погляду модифікації таблиць є їхнє подання у вигляді зв'язаних списків (див. підрозд. 4.3.1). Розглянемо реалізацію основ- них табличних операцій на основі однозв'язного списку.
Приклад 4.27. Таблиця як зв'язаний лінійний список:
#include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <conio.h>
typedef struct item { char name[10];
int rate;
float estimationsult;
struct item *next; /*покажчик на наступний елемент списку*/ } Item;
typedef Item *Itemptr;
/*друкування значень елементів списку, start – голова списку*/ void display(Itemptr start)
530
