C _Учебник_МОНУ
.pdfМасиви в С++ |
179 |
Перевіримо роботу цього циклу на масиві з 7-ми елементів:
5, –1.3, –7.1, 4.8, 2, 7, 1.6.
Після виконання наведеного вище циклу цей масив набуде вигляду
–1.3, –7.1, 4.8, 2, 5, 1.6, 7
тобто масив ще не є остаточно відсортованим за зростанням і дію наведеного вище циклу слід повторювати, допоки масив не набуде вигляду
–7.1, –1.3, 1.6, 2, 4.8, 5, 7.
У поданій нижче таблиці наведено результати чотирьох проходів масивом. Після останнього проходу масив вже відсортовано.
|
|
Елементи масиву |
|
|
|||
|
|
|
|
|
|
|
|
|
0 |
1 |
2 |
3 |
4 |
5 |
6 |
початок |
5 |
–1.3 |
–7.1 |
4.8 |
2 |
7 |
1.6 |
1-й крок |
–1.3 |
7.1 |
4.8 |
2 |
5 |
1.6 |
7 |
2-й крок |
–7.1 |
–1.3 |
2 |
4.8 |
1.6 |
5 |
7 |
3-й крок |
–7.1 |
–1.3 |
2 |
1.6 |
4.8 |
5 |
7 |
4-й крок |
–7.1 |
–1.3 |
1.6 |
2 |
4.8 |
5 |
7 |
Оскільки заздалегідь невідомо, скільки разів треба повторювати проходження масивом, доцільно організувати ще один цикл. Зовнішній цикл (по i) дозволяє перебрати всі елементи масиву для порівняння з іншими елементами, доступ до яких організовано у вкладеному циклі (по j). Можна навести два різновиди організації порівнянь елементів у циклах:
1) Циклічно порівнюються два сусідні елементи – a[j] та a[j+1]. За рахунок того, що після кожного проходження циклом один з елементів ставатиме на своє місце, можна скоротити кількість повторювань вкладеного циклу до (n – i – 1) разів.
for (i=0; i<n-1; i++) for (j=0; j<n–i-1; j++) if (a[j] > a[j+1])
{tmp = a[j]; a[j] = a[j+1];
a[j+1] = tmp;
}
Перевіримо роботу цього циклу на масиві з 7-ми елементів:
9, 8, 7, 6, 5, 4, 3.
Для наочності взято початковий масив, елементи якого розташовано у порядку, протилежному до того, який має бути набуто. У таблиці подано вигляд масиву після кожної ітерації циклу по i. Сірим кольором і рамкою виокремлено елементи, які беруть участь у перестановках наступної ітерації.
180 |
Розділ 5 |
|
0 |
|
1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
||||||||
початок |
9 |
|
|
|
8 |
|
|
7 |
|
|
6 |
|
|
5 |
|
|
|
4 |
|
|
3 |
|
і=0 |
8 |
|
|
|
7 |
|
|
6 |
|
|
5 |
|
|
4 |
|
|
|
3 |
|
9 |
||
і=1 |
7 |
|
|
|
6 |
|
|
5 |
|
|
4 |
|
|
3 |
|
|
8 |
|
9 |
|||
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||
і=2 |
6 |
|
|
|
5 |
|
|
4 |
|
|
3 |
|
7 |
8 |
|
9 |
||||||
|
|
|
|
|
|
|
|
|
||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
і=3 |
5 |
|
|
|
4 |
|
|
3 |
|
6 |
7 |
8 |
|
9 |
||||||||
і=4 |
4 |
|
|
|
3 |
|
5 |
|
6 |
7 |
8 |
|
9 |
|||||||||
і=5 |
3 |
4 |
5 |
|
6 |
7 |
|
8 |
|
9 |
2) Циклічно порівнюються два елементи – a[i] та a[j]. За рахунок того, що після кожного проходження циклом один з елементів ставатиме на своє місце, можна скоротити кількість повторювань вкладеного циклу, розпочинаючи вкладений цикл не з 0-го елемента, а з (i + 1)-го.
for (i=0; i<n-1; i++) for (j=i+1; j<n; j++) if (a[i] > a[j])
{tmp = a[i]; a[i] = a[j]; a[j] = tmp; }
Подібно до першого фрагменту, наведемо подібну таблицю для того само початкового масиву.
|
0 |
1 |
|
2 |
|
3 |
|
4 |
|
5 |
6 |
|
|
||||||
початок |
9 |
|
8 |
|
|
7 |
|
|
6 |
|
|
5 |
|
|
4 |
|
3 |
|
|
і=0 |
3 |
|
9 |
|
|
8 |
|
|
7 |
|
|
6 |
|
|
5 |
|
4 |
|
|
і=1 |
3 |
4 |
|
9 |
|
|
8 |
|
|
7 |
|
|
6 |
|
5 |
|
|
||
і=2 |
3 |
4 |
5 |
|
|
9 |
|
|
8 |
|
|
7 |
|
6 |
|
|
і=3 |
3 |
4 |
5 |
6 |
9 |
8 |
7 |
і=4 |
3 |
4 |
5 |
6 |
7 |
9 |
8 |
і=5 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
Сортування елементів масиву організуємо в окремій функції. Слід звернути увагу на заголовок цієї функції:
void sort(float a[], int n)
де sort – ім‟я функції, за яким її можна буде викликати;
float a[], int n – параметри функції: масив дійсних чисел а (який функція сортуватиме) і кількість елементів масиву n;
void – тип результату, який вказує на те, що функція виконуватиме сортування і змінюватиме масив, але жодних інших обчислень вона не виконуватиме і нічого, окрім зміненого масиву, повертати немає потреби.
Викликати розглянуту функцію можна, якщо написати ім‟я функції й у круглих дужках зазначити два фактичні параметри: ім‟я масиву та кількість його елементів, наприклад:
sort(a, |
15); |
// Якщо елементів є 15 |
sort(a, |
n); |
// Якщо елементів є n |
Масиви в С++ |
181 |
|
Вхід |
|
i=0,n–2 |
|
j=i+1,n–1 |
Ні |
аi > аj |
|
Так
tmp = аi
аi = аj
аj = tmp
Вихід
Схема алгоритму
Початок
Введення n
n>15 Так n=15
Ні
i 0, n 1
Введення
А[i]
sort(a, n)
i 0, n 1
Виведення
А[i]
Кінець
Схема алгоритму до основної програми
Текст функції та основної програми: void sort(float a[], int n)
{ int i, j; |
// Параметри наступних циклів |
float tmp; |
// Тимчасова зміна для переставлянь елементів |
for |
(i=0; i<n-1; i++) |
for |
(j=i+1; j<n; j++) |
if |
(a[i] > a[j]) |
{tmp = a[i]; a[i] = a[j];
a[j] = tmp;
}
}
//------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{int n,i; float a[15];
// Зчитування кількості заповнених рядків Memo1 n = Memo1->Lines->Count;
if (n>15) n=15; for (i=0; i<n; i++)
a[i]=StrToFloat(Memo1->Lines->Strings[i]);
sort(a, n); // Виклик функції
Memo2->Clear(); for (i=0; i<n; i++)
Memo2->Lines->Add(FloatToStr(a[i]));
}
182 |
Розділ 5 |
Д р у г и й с п о с і б Аналізуючи попередній алгоритм сортування, можна скоротити кількість
проходжень по масиву. В наведеному нижче прикладі функції sort2() запропоновано алгоритм сортування, де булева змінна ok відіграє роль своєрідного ліхтарика, який “вмикається” (ok=1) лише в разі переставляння сусідніх елементів, тобто є сигналом, що ще не всі елементи є упорядковано і треба повторювати перевірки.
Текст функції:
void sort2(float a[], int n)
{int i; float tmp; bool ok=1; while (ok)
{ok=0;
for (j=0; j<n-1; j++) if (a[j] > a[j+1])
{tmp = a[j]; a[j] = a[j+1]; a[j+1] = tmp; ok = 1;
}
}
}
Перевіримо роботу цього циклу на масиві з 7-ми елементів:
–0.9, –2.1, 6.3, 3, 8, 5.1, 30.
В таблиці показано вигляд масиву після кожного проходження масивом.
|
0 |
1 |
2 |
3 |
4 |
5 |
6 |
початок |
–0.9 |
–2.1 |
6.3 |
3 |
8 |
5.1 |
30 |
1-й прохід |
–2.1 |
–0.9 |
3 |
6.3 |
5.1 |
8 |
30 |
2-й прохід |
–2.1 |
–0.9 |
3 |
5.1 |
6.3 |
8 |
30 |
3-й прохід |
–2.1 |
–0.9 |
3 |
5.1 |
6.3 |
8 |
30 |
Отже, на відміну від попереднього способу сортування, кількість проходжень циклом істотно скорочується, залежно від початкового розташування елементів. Останнє проходження циклом можна назвати холостим, оскільки перестановок у ньому немає, а отже, булева змінна ok не “вмикається” (ok=1), що є сигналом, що всі елементи упорядковано, – і відбувається вихід з циклу while.
Т р е т і й с п о с і б
Доволі поширеним є ще один спосіб сортування за допомогою мінімального елемента, алгоритм якого реалізовано у наведеній нижче функції sort3(). Його суть полягає в тому, що з послідовності обирають мінімальний (чи максимальний) елемент і переставляють його до початку (кінця) масиву, змінюючи місцями з перевірюваним. Кількість перестановок – (n+1)/2.
Масиви в С++ |
183 |
Розглянемо цей алгоритм для сортування за зростанням масиву з 7-ми елементів:
5, –1.3, –7.1, 4.8, 2, 7, 1.6.
Щоб елементи було розташовано за зростанням, слід віднайти мінімальний елемент масиву і поставити його на перше місце. Після цього повторити аналогічні дії для решти елементів (окрім першого, який вже стоїть на своєму місці). У таблиці на кожній ітерації жирним позначено мінімальний елемент, рамкою виокремлено елементі, які беруть участь у подальшому пошуку мінімального елемента і перестановках.
|
0 |
1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
|||||||||
початок |
|
5 |
|
–1.3 |
|
|
|
–7.1 |
|
|
4.8 |
|
|
2 |
|
|
|
7 |
|
|
1.6 |
|
і=0 |
|
–7.1 |
|
–1.3 |
|
|
|
5 |
|
|
4.8 |
|
|
2 |
|
|
|
7 |
|
|
1.6 |
|
і=1 |
|
–7.1 |
|
–1.3 |
|
|
5 |
|
|
4.8 |
|
|
2 |
|
|
|
7 |
|
|
1.6 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
і=2 |
|
–7.1 |
|
–1.3 |
|
1.6 |
|
|
4.8 |
|
|
2 |
|
|
|
7 |
|
|
5 |
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
і=3 |
|
–7.1 |
|
–1.3 |
|
1.6 |
|
2 |
|
|
4.8 |
|
|
|
7 |
|
|
5 |
|
|||
і=4 |
|
–7.1 |
|
–1.3 |
|
1.6 |
|
2 |
|
4.8 |
|
|
7 |
|
|
5 |
|
|||||
і=5 |
|
–7.1 |
|
–1.3 |
|
1.6 |
|
2 |
|
4.8 |
|
5 |
7 |
|
void sort3(float a[], int n) //n – кількість елементів масиву
{int i, j, imin; float tmp; for (i=0; i<n-1; i++)
{imin=i;
for (j=i+1; j<n; j++)
if (a[imin] > a[j]) imin=j; tmp = a[i];
a[i] = a[imin];
a[imin] = tmp;
}
}
Приклад 5.10 В одновимірному масиві дійсних чисел, який складається з 14-ти (парної кількості) елементів, переставити місцями елементи, які стоять поряд (1 та 2, 3 та 4 тощо).
Текст функції та її виклику в основній програмі: void Perehod (float A[], int n)
{int i; float z;
for (i=0; i<n; i+=2)
{z = A[i];
A[i] = A[i+1]; A[i+1] = z;
}
}
//-------------------------------------------------
Вхід i=0, n-1, 2
z = A[i]
A[i] = A[i+1]
A[i+1] = z
Вихід