3. Пошук елемента в масиві.
Задача пошуку елемента в послідовності - одна з важливих задач програмування як з теоретичної, так і практичної точок зору. Ось її формулювання:
Нехай A = {a1, a2, ...} - послідовність однотипних елементів і b - деякий елемент, який володіє властивістю P. Знайти місце елемента b в послідовності А. Оскільки представлення послідовності в пам’яті може бути здійснено в виді масиву, задачі можуть бути уточнені як задачі пошуку елемента в масиві A:
1.Знайти максимальний елемент масиву;
2.Знайти даний елемент масиву;
3.Знайти k-тий за величиною елемент масиву;
Найбільш прості і часто оптимальні алгоритми основані на послідовному перегляді масиву A з перевіркою властивості P на кожному елементі.
Приклад 2. Пошук мінімального елемента в масиві.
Рrogram MinItem;
Const n = 23;
Var A : Array [1..n] of Real;
Min, Item : Real; Index, i : Integer;
Begin
{Блок введення масиву}
Index := 1; Min := A[1];
For i := 1 to n do begin
Item := A[i];
If Min > Item
then begin Index := i; Min := Item end
end;
{Виведення значень Index, Min}
End.
Змінна Item введена для того, щоб уникнути повторних обчислень індексного виразу в A[i]. Ми пропонуємо читачу розглянути поведінку цього алгоритму і його модифікації у випадку, коли мінімальних елементів у масиві декілька і треба знайти перший, останній, а також всі мінімальні елементи.
Розглянемо задачу пошуку даного елементу в масиві. Очевидний алгоритм її розв’язування - послідовний перегляд масиву і порівняння кожного елемента масиву з даним. Але коли елемент знайдений, перегляд можна припинити. Це означає, що виконання циклу переривається. У мові є засіб переривання - оператор переходу.
4. Постановка задачі сортування.
Під сортуванням послідовності розуміють процес перестановки елементів послідовності у визначеному порядку. Мета такої впорядкованості - полегшення подальшої обробки даних (зокрема, задачі пошуку). Тому задача сортування - одна з найбільш важливих внутрішніх задач програмування.
Цікаво, що задача сортування є ідеальним прикладом великої кількості різноманітних алгоритмів, розв’язування одної і тої ж задачі. Розглядаючи різні методи сортування, ми побачимо, як зміна алгоритму приводить до нових, більш ефективних у порівнянні з простими, розв’язувань задачі сортування.
Крім цього, послідовності можна представити (реалізувати) в пам’яті різними структурами даних. Як і слід очікувати, ефективність алгоритмів стає дуже залежною від реалізації послідовності.
Нехай дана послідовність елементів a1, a2, ... , an. Елементи цієї послідовності - дані довільного типу, на якому визначено відношення порядку “<<” (менше) таке, що будь-які два різні елементи можна порівняти.
Сортування означає перестановку елементів послідовності ak1, ak2, ... , akn таку, що ak1 << ak2 << ... << akn.
Приклад: послідовність документів, кожний з яких містить інформацію про людину, включаючи його вік. Потрібно розмістити документи цієї послідовності у порядку за віком, починаючи з старшого.
Сортування масивів.
Якщо послідовність a1, a2, ... , an реалізована як масив А[1..n], вся вона розміщена в адресованій пам’яті. Тому наряду з вимогами ефективності за часом основна вимога - економне використання пам’яті. Це означає, що алгоритм не повинен використовувати додаткові масиви і пересилки з масиву А в ці масиви.
Постановка задачі сортування в загальному виді передбачає, що існують тільки два типи дій з даними сортованого типу : порівняння двох елементів (x << y) і пересилання елемента (x := y). Тому зручна міра складності алгоритму сортування масиву А[1..n] за часом - кількість порівнянь C(n) і кількість пересилань M(n).
Прості алгоритми сортування.
Прості алгоритми сортування можна класифікувати як сортування обміном, сортування вибором і сортування вставками.
Сортування обмінами.
Основна дія сортування обмінами - порівняння двох елементів і, якщо результат порівняння від’ємний, перестановка їх місцями:
Якщо при i < j a[i] > a[j] то переставити a[i] і a[j].
В найбільш простому варіанті порівнюються елементи a[j] і a[j+1], що стоять поряд:
Приклад 3.
Program BublSort;
Const n = 100;
Var a : array[1..n] of Real;
i, j : Integer;
TempMem : Real;
Begin
{ Блок введення масиву }
For i := n - 1 downto 1 do
For j := 1 to i do
If a[j] > a[j+1]
then begin
TempMem := a[j+1]; a[j+1] := a[j]; a[j] := TempMem end;
{ Блок виведення масиву }
End.
Сортування вибором.
Приклад 4.
Основна дія сортування вибором - пошук найменшого елемента в частині масиву, що переглядається і перестановка з першим елементом частини, що переглядається:
For i := 1 to n - 1 do begin
k := Індекс( Min(a[i], ..., a[n]));
Переставити a[i], a[k]
end;
Program SelectSort;
Const n = 10;
Var a : array[1..n] of Real;
i, j, MinIndex : Integer;
TempMem : Real;
Begin
{Блок введення масиву}
For i := 1 to n - 1 do begin
{ пошук мінімального елемента }
MinIndex := i;
for j := i + 1 to n do
If a[j] < a[MinIndex] then MinIndex := j;
{перестановка елементів}
TempMem := a[MinIndex]; a[MinIndex] := a[i]; a[i] := TempMem
end;
{Блок виведення масиву}
End.
Сортування вставками.
Ще один простий алгоритм сортування - сортування вставками базується на наступній ідеї: припустимо, що перші k елементи масиву A[1..n] вже упорядковані:
A[1] A[2] ... A[k], A[k+1], ..., A[n]
Знайдемо місце елемента A[k+1] в початковому відрізку A[1],...,A[k] і вставимо елемент на своє місце, отримавши упорядковану послідовність довжини k+1. Оскільки початковий відрізок масиву упорядкований, пошук треба реалізувати як бінарний. Вставці елемента на своє місце повинна передувати процедура зсуву “хвоста” початкового відрізка для звільнення місця.
Program InsSort;
Const n = 100;
Var A : array[1..n] of Integer;
k : Integer;
l, r, i, j : Integer;
b : Integer;
Begin
{Блок читання масиву A}
For k := 1 to n-1 do begin
b := A[k+1];
If b < A[k]
then begin
l := 1; r := k; {Бінарний пошук}
Repeat
j := (l + r) div 2;
If b < A[j] then r := j else l := j + 1;
until (l = j);{ Зсув “хвоста” масиву на 1 позицію праворуч}
For i := k downto j do A[i+1] := A[i];
A[j] := b ; { Пересилання елемента на своє місце}
end
end;
{Блок виведення масиву A}
End.
Оцінимо ефективність алгоритму. Пошук міста елемента A[k+1] потребує, як показано вище, O(log2 k ) порівнянь. Тому у гіршому випадку кількість порівнянь С (n) є
C(n) = O(log2 2 ) + ... + O(log2(n-1)) + O(log2 n) = O(n log2 n)
Зсув “хвоста” на кожному кроку зовнішнього циклу у гіршому випадку потребує k перестановок. Тому у гіршому випадку
M(n) = 1 + ... + (n-2) + (n-1) = n*(n-1)/2 = O(n2)
Таким чином, алгоритм сортування вставками значно ефективніший, ніж всі розглянуті раніше алгоритми за числом порівнянь. Однак число перестановок у гіршому випадку також буде значним, як і у самому неефективному алгоритмі - сортуванню простими обмінами.
