
- •Основні положення теорії алгоритмів та її застосування
- •Введення до теорії алгоритмів
- •Загальні риси алгоритмів
- •Машина Поста
- •Машина т’юринга
- •Основи лямбда-числення та функціонального програмування
- •Теза Черча-т’юринга про алгоритмічну розв’язність задачі
- •Проблема розв’язності (зависання)
- •Алгоритмічно нерозв’язні задачі
- •Проблема відсутності загального методу вирішення задачі
- •Проблема інформаційної невизначеності задачі
- •Проблема логічної нерозв’язності задачі
- •Побудова машини т’юринга для обчислення деяких простих функцій
- •Введення до оцінки складності алгоритмів
- •Визначення порядку складності алгоритму
- •Оптимізація алгоритмів
- •Структури даних в алгоритмічній мові програмування
- •Визначення алгоритмічної мови програмування
- •Базові елементи сучасної мови програмування: типи даних; екземпляри даних; вирази; оператори; функції; класи.
- •Поняття типу даних
- •Прості типи: числові; символьні; логічні.
- •Тип даних рядок
- •Структуровані типи даних: масиви, записи, множини
- •Типи даних за значенням і за посиланням
- •Сумісність типів та перетворення між типами даних
- •Екземпляри даних: змінні, константи
- •Видимість даних
- •Управління ходом виконання та структурування програм в алгоритмічній мові програмування
- •Вирази, операнди та операції
- •Основні операції: арифметичні; логічні; бульові; з використанням рядків
- •Поняття оператора
- •Прості оператори: присвоювання; виклику функції
- •Оператори управління ходом виконання: розгалуження; вибору; цикли; переходу
- •Структурування програм: функції та класи
- •Параметри функцій: вхідні, результуючі.
- •Рекурсивні функції
- •Файли: текстові, бінарні
- •Алгоритми чисельних методів, апроксимації функцій, інтегрування та вирішення рівнянь з одним невідомим
- •Чисельні методи
- •Особливості вирішення задач чисельними методами, точність та коректність рішень
- •Апроксимації функцій: лінійна інтерполяція; інтерполяційний многочлен Ньютона.
- •Чисельне інтегрування: метод трапецій; метод Сімпсона; метод Сімпсона з оцінкою погрішності.
- •Вирішення рівнянь з одним невідомим: метод простих ітерацій; метод Ньютона; метод парабол.
- •Алгоритми вирішення системи лінійних рівнянь, пошуку екстремуму функції
- •Вирішення системи лінійних рівнянь методом Гауса
- •Пошук екстремуму функцій одної змінної: метод золотого перетину; метод парабол.
- •Пошук екстремуму функцій багатьох змінних: метод координатного спуску; метод найскорішого спуску.
- •Алгоритми обробки масивів
- •Визначення масивів
- •Операції над масивами
- •Упорядкування масивів: сортування вибором; сортування вставкою; бульбашкове сортування; сортування методом Шелла; метод швидкого сортування.
- •Вибір методів сортування
- •Пошук в упорядкованих масивах методом половинного поділу, інтерполяційним методом
- •Застосування індексів для пошуку у невпорядкованих даних
- •Алгоритми обробки даних на основі списків та дерев
- •Визначення списку
- •Види списків: незалежні списки, однозв’язані списки; двозв’язані списки; кільцеві списки; упорядковані списки
- •Основні операції над списками: включення елементу до списку; видалення елементу; перехід між елементами; ітератор для списку
- •Упорядкування та пошук в списках
- •Похідні структури даних: черга, стек, дек
- •Визначення дерева
- •Впорядковані дерева
- •Бінарні дерева
- •Основні операції з бінарними деревами: включення елементу; видалення елементу; обхід дерева
- •Балансування дерева
- •Алгоритми обробки текстових даних на основі регулярних виразів
- •Введення до теорії кінцевих автоматів
- •Графічне представлення кінцевих автоматів
- •Використання кінцевого автомату: синтаксичний аналіз.
- •Реалізація синтаксичного аналізу файлу з розділяючими комами
- •Детерміновані та недетерміновані кінцеві автомати
- •Регулярні вирази
- •Форма Бекуса-Наура для запису регулярних виразів
- •Синтаксичний аналіз регулярних виразів
- •Компіляція регулярних виразів
- •Інструменти для спрощення роботи з регулярними виразами
- •Зіставлення рядків з регулярними виразами.
- •Алгоритми систем числення
- •Введення до систем числення
- •Двійкова система числення
- •Шістнадцяткова система числення
- •Системи числення з нетрадиційними основами
- •Перетворення між різними системами числення
- •Арифметика чисел з плаваючою комою
- •Точність операцій з плаваючою комою
- •Арифметика великих чисел
- •Алгоритми криптографії та хешування
- •Значення випадкових чисел у програмуванні
- •Алгоритми генерації рівномірно розподілених псевдовипадкових чисел
- •Перевірка якості випадкових чисел
- •Кодування з виправленням помилок
- •Стиснення даних
- •Стиснення даних зі словником
- •Алгоритм стиснення даних Лемпела-Зіва
- •Введення до криптографії
- •Елементи теорії порівнянь
- •Шифрування за допомогою випадкових чисел
- •Створення таємного ключа по Діффі-Хеллману
- •Система rsa
- •Алгоритми цифрового підпису
- •Введення до хешування
- •Функції хешування
- •Проста функція хешування рядків
- •Функції хешування з використанням рандомізації
- •Вирішення конфліктів за допомогою лінійного зондування
- •Псевдовипадкове зондування
- •Подвійне хешування
Упорядкування масивів: сортування вибором; сортування вставкою; бульбашкове сортування; сортування методом Шелла; метод швидкого сортування.
Сортування – процес перестановки об’єктів у певному порядку.
Основне призначення сортування – полегшення пошуку об’єктів.
Існує велика кількість алгоритмів сортування, одного «найкращого» до нинішнього часу не винайдено. Вибір підходящого алгоритму залежить від характеру даних, їх розподілу, пам’яті, у якій вони зберігаються.
Наприклад, поширеним є поділ алгоритмів сортування на:
внутрішні – сортування масивів і даних в оперативній пам’яті;
зовнішні – сортування даних у файлах.
На рис. 6.1 умовно представлено сортування масиву, на рис. 6.2 – сортування файлу.
Рисунок 6.1 – Сортування масиву
Рисунок 6.2 – Сортування файлу
За зміною порядку елементів розрізняють:
стійке сортування – при виконанні алгоритму на відсортованому наборі даних порядок елементів не змінюється;
нестійке сортування – при виконанні алгоритму на відсортованому наборі даних порядок елементів змінюється.
Ключ – елемент даних, за яким здійснюється сортування. Для ключа має використовуватися такий тип даних, для якого існує спосіб визначення порядку елементів.
Складність виконання алгоритму – кількість операцій, а також обсяг додаткової пам’яті, необхідної для його виконання.
Найпростіший алгоритм сортування водночас є неефективним (нерозумним), його складність О(n3):
using System;
using System.Collections.Generic;
using System.Text;
namespace SortApplication
{
class Program
{
static void swap(int[] arr, int i, int j)
{
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
static void stupidSort(int[] arr)
{
int i = 0;
while (i < arr.Length - 1)
{
if (arr[i + 1] < arr[i])
{
swap(arr, i, i + 1);
i = 0;
}
else
{
i++;
}
}
}
static void Main(string[] args)
{
int[] testArr = { 44, 55, 12, 42, 94, 18, 06, 67};
stupidSort(testArr);
foreach (int i in testArr)
{
Console.Write("{0} ", i);
}
Console.ReadLine();
}
}
}
Інший варіант нерозумного сортування – сортування Акульшина: генеруються всі можливі перестановки масиву, для яких здійснється перевірка правильного порядку. Складність: О (n × n!).
Алгоритм сортування вставками
Основна ідея алгоритму полягає в тому, щоб поступово впорядковувати масив, вставляючи нові елементи у вже впорядковану частину (рис. 6.3). Складність алгоритму – О (n2).
Рисунок 6.3 – Схематичне представлення роботи алгоритму сортування простими вставками
Код програми:
using System;
using System.Collections.Generic;
using System.Text;
namespace SortingApplication
{
class Program
{
static void insertSort(int[] a)
{
int i, j, value;
for (i = 1; i < a.Length ; i++)
{
value = a[i];
for (j = i - 1; (j >= 0) && (a[j] > value); j--)
{
a[j + 1] = a[j];
}
a[j + 1] = value;
}
}
static void Main(string[] args)
{
int[] testArr = {44, 55, 12, 42, 94, 18, 06, 67};
insertSort(testArr);
foreach (int i in testArr)
{
Console.Write("{0} ", i);
}
Console.ReadLine();
}
}
}
Результат виконання програми (рис. 6.4).
Рисунок 6.4 – Результат виконання програми
Особливості алгоритму – простий і наглядний в реалізації, однак ресурсоємний.
Модифікований варіант даного алгоритму – сортування бінарними вставками оснований на тому, що у вже відсортованій частині масиву елементи можна включати, виконуючи бінарний пошук.
Алгоритм бульбашкового сортування
Алгоритм бульбашкового сортування передбачає повторні проходи по масиву, який сортується. За кожен прохід елементи порівнюються попарно і якщо порядок серед двох елементів невірний, то здійснюється обмін елементів. Проходи по масиву виконуються до тих пір, доки не стане зрозуміло, що обміни елементів вже не потрібні, тобто масив відсортований.
Свою назву алгоритм отримав за принципом роботи – у процесі його виконання елемент, який стоїть не на власному місці, «спливає» до необхідної позиції наче бульбашка у воді.
Схематично робота алгоритму представлена на рис. 11.3.
Складність алгоритму – О(n2).
Рисунок 6.5 – Схематичне представлення роботи алгоритму бульбашкового сортування
Код програми, яка виконує бульбашкове сортування:
using System;
using System.Collections.Generic;
using System.Text;
namespace SortApplication
{
class Program
{
static void swap(int[] arr, int i, int j)
{
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
static void bubbleSort(int[] arr)
{
for (int i = arr.Length - 1; i > 0; i--)
{
for (int j = 0; j < i; j++)
{
if (arr[j] > arr[j + 1])
{
swap(arr, j, j + 1);
}
}
}
}
static void Main(string[] args)
{
int[] testArr = {44, 55, 12, 42, 94, 18, 06, 67};
bubbleSort(testArr);
foreach (int i in testArr)
{
Console.Write("{0} ", i);
}
Console.ReadLine();
}
}
}
Модифікації алгоритму:
виявлення проведених обмінів;
шейкер-сортування.
Алгоритм сортування за методом Шелла
Ідея алгоритму – необхідно порівнювати елементи, які знаходяться не тільки поряд, а і на відстані один від одного. Спочатку порівнюються і сортуються між собою ключі, які стоять на певній відстані d. Після цього процедура повторюється для деяких менших значень d, і так до тих пір, доки d не стане рівним одному, у такому разі робота методу буде ідентична сортуванню простими вставками.
Схематично робота алгоритму представлена на рис. 6.6.
Складність алгоритму: O(n log n)
Рисунок 6.6 – Схематичне представлення роботи алгоритму
Код програми:
using System;
using System.Collections.Generic;
using System.Text;
namespace SortApplication
{
class Program
{
static void shellSort(int[] arr)
{
int j;
int step = arr.Length / 2;
while (step > 0)
{
for (int i = 0; i < (arr.Length - step); i++)
{
j = i;
while ((j >= 0) && (arr[j] > arr[j + step]))
{
int tmp = arr[j];
arr[j] = arr[j + step];
arr[j + step] = tmp;
j--;
}
}
step = step / 2;
}
}
static void Main(string[] args)
{
int[] testArr = {44, 55, 12, 42, 94, 18, 06, 67};
shellSort(testArr);
foreach (int i in testArr)
{
Console.Write("{0} ", i);
}
Console.ReadLine();
}
}
}
Особливості алгоритму – за звичайних обставин кількість порівнянь є меншою, ніж у алгоритмів сортування вставками та бульбашкового сортування.
Алгоритм швидкого сортування
Алгоритм швидкого сортування або алгоритм сортування Хоара – найшвидший серед відомих алгоритмів сортування загального призначення. Розроблений англійським інформатиком Чарльзом Хоаром. Швидшими за нього є лише спеціалізовані алгоритми, які побудовані з урахуванням специфіки даних, для яких вони використовуються.
Ідея алгоритму основана на принципі «поділяй і володарюй»:
Обираємо деякий елемент, який буде називатися опорним елементом.
Здійснюємо операцію поділу масиву: реорганізуємо його таким чином, щоб всі елементи менші чи рівні опорному були зліва від нього, а всі більші – справа.
Рекурсивно за цим же алгоритмом впорядковуємо списки елементів, які знаходяться зліва і справа від опорного.
Складність алгоритму: в середньому – О(n log n), найгірший випадок – О (n2).
Код програми:
using System;
using System.Collections.Generic;
using System.Text;
namespace SortApplication
{
class Quicksort
{
public static void qsort(int[] items)
{
qs(items, 0, items.Length - 1);
}
static void qs(int[] items, int left, int right)
{
int i, j;
int x, y;
i = left; j = right;
x = items[(left + right) / 2];
do
{
while ((items[i] < x) && (i < right))
{
i++;
}
while ((x < items[j]) && (j > left))
{
j--;
}
if (i <= j)
{
y = items[i];
items[i] = items[j];
items[j] = y;
i++; j--;
}
} while (i <= j);
if (left < j)
{
qs(items, left, j);
}
if (i < right)
{
qs(items, i, right);
}
}
}
class Program
{
static void Main(string[] args)
{
int[] testArr = {44, 55, 12, 42, 94, 18, 06, 67};
Quicksort.qsort(testArr);
foreach (int i in testArr)
{
Console.Write("{0} ", i);
}
Console.ReadLine();
}
}