
- •Програмування
- •1. Алгоритми 12
- •2. Комп’ютери і програми 47
- •3. Мова програмування паскаль 56
- •4. Прості типи даних. Лінійні програми 61
- •5. Процедурне програмування 73
- •6. Програмування розгалужень 79
- •7. Оператори повторення з параметром. Масиви 99
- •7.13. Задачі і вправи 114
- •8. Ітераційні цикли 116
- •8.6. Задачі і вправи 124
- •9. Рекурсія 126
- •9.4. Задачі і вправи 135
- •10. Швидкі алгоритми сортування і пошуку 137
- •10.8. Задачі і вправи 148
- •11. Складні типи даних: записи і файли 150
- •11.11. Задачі і вправи 169
- •12. Множини 172
- •12.5. Задачі і вправи 175
- •13. Динамічні структури даних 176
- •14. Методологія структурного програмування: підсумки 192
- •1. Алгоритми
- •1.1. Змістовне поняття алгоритму
- •1.2. Виконавець алгоритмів і його система команд
- •1.3. Основні властивості алгоритмів
- •1.4. Величини
- •1.5. Типи величин
- •1.6. Цілі числа
- •1.7. Дійсні числа
- •1.8. Рядкові величини
- •У слові w знайти слово p і замінити його словом q.
- •1.9. Форми запису алгоритмів
- •1:Кінець.
- •X2 присвоїти значення x1
- •1:Кінець.
- •1.10. Команди управління
- •1.11. Блок - схеми
- •1.12. Допоміжні алгоритми
- •1.13. Базові структури управління
- •1.14. Абстракція даних
- •Приклад 1.7. Атд Планіметрія (виконавець Геометр)
- •1.15. Структурне програмування
- •1.16. Парадигма процедурного програмування
- •2. Комп’ютери і програми
- •2.1. Комп’ютер як універсальний Виконавець
- •2.1.1. Зовнішні пристрої комп’ютера
- •2.1.2. Центральні пристрої комп’ютера
- •2.1.3. Поняття про машинну мову
- •2.2. Мови програмування високого рівня
- •2.2.1. Коротка історія розвитку мов програмування
- •2.2.2. Про історію розвитку методів проектування програм
- •2.3. Основні етапи проектування програми
- •2.4. Технологія трансляції програм
- •2.5. Поняття про систему програмування
- •3. Мова програмування паскаль
- •3.1. Алфавіт мови
- •3.2. Концепція даних
- •3.3. Імена та їх застосування
- •3.4. Структура Pascal-програми
- •3.5. Поняття про лексику, прагматику, синтаксис і семантику мови програмування
- •3.6. Синтаксичні діаграми як засіб визначення мови програмування
- •4. Прості типи даних. Лінійні програми
- •4.1. Заголовок програми
- •4.2. Константи і їх використання. Розділ констант
- •4.3. Змінні програми. Розділ змінних
- •4.4. Стандартні прості типи даних
- •4.5. Тип даних Integer
- •4.6. Тип даних Real
- •4.7. Тип даних Сhar
- •4.8. Поняття виразу. Значення виразу. Тип виразу
- •4.9. Розділ операторів. Оператор присвоювання
- •4.10. Оператори введення - виведення
- •4.11. Приклад лінійної програми
- •4.12. Поняття складності виразу. Оптимізація обчислень
- •4.13. Оптимізація лінійних програм
- •4.14. Задачі і вправи
- •5. Процедурне програмування
- •5.1. Опис процедури
- •5.2. Формальні параметри. Локальні і глобальні об’єкти
- •5.3. Оператор процедури. Фактичні параметри
- •5.4. Функції
- •5.5. Приклади
- •6. Програмування розгалужень
- •6.1. Поняття умови. Тип даних Boolean (логічний)
- •6.2. Складений оператор
- •6.3. Оператори вибору: умовний оператор
- •6.4. Приклади
- •6.5. Задачі вибору й упорядкування
- •6.5.1. Задачі вибору
- •6.5.2. Дерево розв’язувань задачі вибору
- •6.5.3. Задачі на зважування
- •6.5.4. Ефективність алгоритму як кількість його кроків
- •6.5.5. Вибір даного елемента
- •6.6. Задачі упорядкування
- •6.6.1. Упорядкування елементів
- •6.6.2. Порівняння, перестановки і пересилання
- •6.7. Оптимізація розгалужень
- •6.8. Розділ типів. Перелічуваний тип
- •6.9. Оператори вибору: оператор варіанта
- •6.10. Вправи
- •7. Оператори повторення з параметром. Масиви
- •7.1. Оператор циклу з параметром
- •7.2. Циклічні програми. Складність циклічної програми. Оптимізація циклічних програм
- •7.3. Обмежені типи
- •7.4. Складні (складені) типи
- •7.5. Регулярний тип. Масиви
- •7.6. Пошук елемента в масиві
- •7.7. Ефективність алгоритму за часом
- •7.8. Мітки. Оператор переходу. Застосування оператора переходу для дострокового виходу з циклу
- •7.9. Постановка задачі сортування
- •7.10. Сортування масивів
- •7.10.1. Прості алгоритми сортування
- •7.11 Сортування обмінами
- •7.12. Сортування вибором
- •7.13. Задачі і вправи
- •8. Ітераційні цикли
- •8.1. Оператори повторення While і Repeat
- •8.2. Алгоритми пошуку і сортування. Лінійний пошук у масиві
- •8.3. Поліпшений алгоритм сортування обмінами
- •8.4. Бінарний пошук в упорядкованому масиві
- •8.5. Алгоритми сортування масивів (продовження). Сортування вставками
- •8.5.1 * Ефективність алгоритму
- •8.6. Задачі і вправи
- •9. Рекурсія
- •9.1. Рекурсивно-визначені процедури і функції
- •9.2. Приклади рекурсивних описів процедур і функцій
- •I стержень j стержень 6-I-j стержень
- •I стержень j стержень 6-I-j стержень
- •I стержень j стержень 6-I-j стержень
- •9.3. Переваги і недоліки рекурсивних алгоритмів
- •9.4. Задачі і вправи
- •10. Швидкі алгоритми сортування і пошуку
- •10.1. Нижня оцінка часу задачі сортування масиву за числом порівнянь
- •10.2. Швидкі алгоритми сортування: Сортування деревом
- •10.2.1. *Аналіз складності алгоритму
- •10.3. Пірамідальне сортування
- •10.3.1.*Аналіз складності алгоритму
- •10.4. Швидке сортування Хоара
- •10.5. Пошук k-того в масиві. Пошук медіани масиву
- •10.6.* Метод “розділяй і володій”
- •10.7.* Метод цифрового сортування
- •10.8. Задачі і вправи
- •11. Складні типи даних: записи і файли
- •11.1. Складні типи даних у мові Pascal
- •11.2. Записи
- •11.3. Записи з варіантами
- •11.4. Оператор приєднання
- •11.5. Рядки і засоби їх обробки
- •Процедури і функції типу String.
- •11.7. Файли. Управління файлами
- •11.8. Основні задачі обробки файлів
- •11.9. Сортування файлів
- •11.9.1. Алгоритм сортування злиттям
- •11.9.2. Аналіз складності алгоритму
- •11.10. Задача корегування файла
- •11.11. Задачі і вправи
- •12. Множини
- •12.1. Множинний тип
- •12.2. Конструктор множини
- •12.3. Операції і відношення над множинами
- •12.4. Застосування множин у програмуванні
- •12.5. Задачі і вправи
- •13. Динамічні структури даних
- •13.1. Стандартні динамічні структури
- •13.2. Посилальний тип даних. Посилання
- •13.3. Програмування динамічних структур даних
- •13.4. Стеки, списки, черги
- •13.5. Задачі
- •13.6. Дерева
- •13.7. Бінарні дерева
- •13.8. Задачі
- •14. Методологія структурного програмування: підсумки
- •14.1. Основні структури управління
- •14.2. Основні структури даних
- •14.3. Методологія програмування “зверху-вниз”
- •14.4. Приклад: Система лінійних рівнянь
- •14.5. Проектування модулів. Модуль rat
- •14.6. Реалізація модуля
- •14.7. Висновки (модульне програмування)
- •14.8. Заключне зауваження: переходимо до об’єктів
I стержень j стержень 6-I-j стержень
Відмітимо тепер, що на стержні J лежить кільце з найбільшим діаметром, тобто цей стержень можна використовувати без порушення обмежень, пов’язаних з величинами діаметрів. Тому можна тепер переставити всю піраміду з N-1 кільця з стержня 6-I-J на J, (рис. 9.4) і задача розв’язана!
Рис. 9.4
n-1 кільце
I стержень j стержень 6-I-j стержень
Відмітивши, що при N = 1 задача розв’язується за допомогою процедури Step (I, J), опишемо процедуру HanojTower (N,I,J):
Procedure HanojTower(N, I, J: Integer);
Begin
If N = 1
then Step(I, J)
else begin
HanojTower(N-1, I, 6-I-J);
Step(I, J);
HanojTower(N-1, 6-I-J, J)
end
End;
Процедуру Step(I, J) можна реалізувати, використовуючи представлення даних у масиві Rings[1..N, 1..3] і графічну візуалізацію переміщення кілець.
Визначимо складність алгоритму за часом C(n) (кількість кроків-викликів Step), вписавши рекурентне співвідношення: С(n) = 2C(n-1) + 1
Легко тепер довести, що С(n) = 2n - 1. Доведено, що ця кількість кроків є мінімально можливою, тому наш алгоритм оптимальний.
Приклад 9.5. Лінійні діафантові рівняння
Перелічити всі невід’ємні цілі розв’язки лінійного рівняння a1x1 + a2x2 + ... + anxn = b з цілими додатними коефіцієнтами.
Як і в попередніх прикладах, опишемо алгоритм рекурсивно, здійснивши зведення вихідної задачі до задачі меншого розміру.
Перепишемо вихідне рівняння у виді:
a1 x1 + a2 x 2 + ... + a n-1 x n-1 = b - a n x n
Організуємо перелік всіляких значень xn, при яких права частина b - a n x n > 0. xn = 0, 1, ... y, де y = b div an. Тоді перші n-1 компонент розв’язка (x1, ... , x n-1, x n) вихідного рівняння – розв’язок рівняння
a1 x1 + a2 x2 + ... + a n-1 x n-1 = b - a n x n .
Таким чином ми звели розв’язок вихідного рівняння до розв’язку у+1 рівняння з n-1 невідомим, і, отже, можемо реалізувати алгоритм рекурсивно. Визначимо умови виходу з рекурсії:
при b = 0 існує єдиний розв’язок – (0, 0, ..., 0)
при n = 1 якщо b mod a1 = 0 то x1 = b div a1 інакше розв’язків немає.
Таким чином, виходити з рекурсивних обчислень треба в двох (крайніх) випадках. Ми встановили і параметри процедури: n і b.
Procedure Solution(n, b : integer);
Var
i, j, y, z : Integer;
Begin
If b = 0
then begin
For j := 1 to n do X[j] := 0;
WriteSolution
end
else If (n = 1) and (b mod a[1] = 0)
then begin
X[1]:= b div a[1];
WriteSolution
end
else If n > 1
then begin
z := a[n];
y := b div z;
For i := 0 to y do begin
X[n] := i;
Solution(n - 1, b - z*i)
end
end
End;
Program AllSolutions;
Const
n = 4;
Type
Vector = array[1..n] of Integer;
Var
a, X : Vector;
b : Integer;
i : Integer;
{Procedure WriteSolution друкує розв’язок X[1..n] }
{Procedure Solution}
Begin
{Введення масиву коефіцієнтів a[1..n] і св. члена b}
Solution(n, b)
End;
Приклад 9.6. Піднесення числа до натурального степеня
Піднести дійсне число а у натуральний степінь n.
Раніше ця задача була розв’язана методом послідовного домноження результату на а. Однак її можна розв’язати ефективніше, якщо застосувати метод половинного ділення степеня n. Саме: an = (a n/2) )2. Оскільки число n не обов’язково парне, формулу треба уточнити:
a^n = (a n div 2) 2 * a n mod 2. Доповнивши визначення a n визначенням a1 = a і замінивши домноження на a n mod 2 розбором випадків парний-непарний, отримаємо:
Function CardPower(a : Real; n : Integer) : Real;
var
b : Real;
Begin
If n = 1
then CardPower := a
else begin
b := Sqr(CardPower(a, n div 2));
If n mod 2 = 0
then CardPower := b
else CardPower := a*b
end
End;
Доведіть, що функція CardPower використовує не більш O(log2n) множень і піднесень у квадрат.
Приклад 9.7. Перетин зростаючих послідовностей
Нехай A = [a1, a2,...,an] і B = [b1, b2, ... , bm] – дві зростаючі числові послідовності. Перетином цих послідовностей називається зростаюча послідовність С = [с1, с2,..., сk], що складається з тих і тільки тих чисел, які належать обом послідовностям. Треба знайти C = AB.
Зведемо задачу до кількох підзадач, більш простих, ніж вихідна. Поділимо для цього вихідні послідовності на частини
A = [a1]A2; B = [b1] B2, де A 2 = [a 2,...,a n], B 2 = [b 2,...,b n]
Тоді
AB = (a1 A2) (b1 + B2) = a1b1 a1B2 A2b1 A2B2
(Дужки в позначеннях одноелементних множин опущені)
Так як послідовності A і B зростають, маємо:
Якщо a1 = b1 то AB = a1b1 A2B2 = a1 A2B2
Якщо a1 < b1 то AB = b1A2 A2B2 = A2B
Якщо a1 > b1 то AB = a1B2 A2B2 = AB2
Ці відношення зводять вихідну задачу до задач менших розмірів, тому їх можна використовувати для рекурсивного описання обчислень.
Процедура Intersect пошуку перетину залежить від параметрів i та j – номерів початкових елементів підпослідовностей A[i..m] і B[j..n], представлених масивами A[1..m] і B[1..n]. Знайдений елемент перетину роздруковується.
Procedure Intersect(i, j : Integer);
Begin
If (i <= m) and (j <= n)
then If a[i] = b[j]
then begin
Write(a[i]);
Intersect(i+1, j+1)
end
else If a[i] < b[j]
then Intersect(i+1, j)
else Intersect(i, j+1)
End;