You are on page 1of 32

Міністерство освіти і науки України

Національний університет водного господарства

та природокористування

Кафедра обчислювальної техніки

04-04-200

МЕТОДИЧНІ ВКАЗІВКИ

для виконання лабораторних робіт


з дисципліни
"Програмування під платформу .NET"
студентами напряму підготовки
6.050102 "Комп’ютерна інженерія"

Частина І

Рекомендовано
методичною комісією
напряму підготовки
"Комп’ютерна інженерія"
Протокол № 7
від 03 березня 2017 р.

Рівне 2017
Методичні вказівки для виконання лабораторних робіт з дисципліни
"Програмування під платформу .NET" студентами напряму підготовки
6.050102 "Комп’ютерна інженерія". Частина І. / П. В. Ольшанський, –
Рівне: НУВГП, 2017, – 32 с.

Упорядник П. В. Ольшанський, старший викладач кафедри


обчислювальної техніки.
Відповідальний за випуск
Б.Б. Круліковський, кандидат технічних наук, доцент,
завідувач кафедри обчислювальної техніки
Зміст

Лабораторна робота №1.


Програмування лінійних алгоритмів мовою C# .NET 3

Лабораторна робота №2.


Програмування розгалужених алгоритмів мовою C# .NET 8

Лабораторна робота №3.


Програмування циклічних алгоритмів мовою C# .NET 12

Лабораторна робота №4.


Обробка одновимірних масивів в C# .NET 17

Лабораторна робота №5.


Алгоритми сортування, пошуку та злиття одновимірних
масивів в C# .NET 24

© Ольшанський П.В., 2017


© НУВГП, 2017

2
Лабораторна робота №1.
Програмування лінійних алгоритмів мовою C# .NET
Приклад 1.1. Обмін значень. Обміняти місцями в пам’яті
комп’ютера значення двох змінних a та b однакового типу
(наприклад, int).
Розв’язок. Потрібно використати ще одну змінну t того самого типу
для проміжного зберігання початкового значення змінної a :
register int t = a ; a = b ; b = t ;
Завдання 1.1. Обміняти місцями в пам’яті комп’ютера значення
трьох змінних a, b, c типу int. Розглянути всі можливі варіанти
обміну.
Приклад 1.2. Розв’язати задачу з прикладу 1.1 без використання
третьої проміжної змінної.
Розв’язок.
Варіант 1. З використанням арифметичних операцій:
a=a+b; b=a-b; a =a-b;
Або в скороченій формі:
a+=b; b=a-b; a-= b;
або
a = - (a - = b) + (b + = a);
або
a = - (a - = b + = a); b - = a ;
Пояснення
Нехай a = a0; b = b0.
Тоді a = a0 + b0; b = (a0 + b0) - b0 = a0; a = (a0 + b0) - a0 = b0 .
Трюк полягає в тому , що для виконання арифметичних операцій
використовується щонайменше два регістри процесора, в той час, як
для пересилання даних між змінними - досить одного, тому хоч
змінної t в записі програми немає, її роль виконує один з регістрів
процесора.
Варіант 2. З використанням логічної операції XOR (виключне АБО):
a=a^b; b=b^a; a =a^b;
або в скороченій формі:
a^=b; b ^=a; a^= b;
або b^=a ^=b; a^= b;

3
Якщо в першому варіанті можливе переповнення або втрата
значень при додаванні чисел різного порядку, то другий варіант
коректно виконується з даними будь-якого типу, який допускає
побітові логічні операції.
Завдання 1.2. Обміняти місцями в пам’яті комп’ютера значення двох
змінних a, b, c типу float (double) з використанням операцій множення
і ділення.
Завдання 1.3*. Обміняти місцями в пам’яті комп’ютера значення
двох змінних a, b, c типу int з використанням операцій множення,
цілочисельного ділення та алгебраїчного модуля (%).
Приклад 1. 3. Використовуючи тільки оператор присвоєння і
операцію множення, обчислити a8, a16, a32, a64 за найменшу кількість
операцій.
Розв’язок.
b=a*a; b = b * b ; /// a4 b = b * b ; /// a8
16 32
b = b * b ; /// a b = b * b ; /// a b = b * b ; /// a64
Приклад 1. 4. Використовуючи тільки оператор присвоєння і
операцію множення обчислити a9, a27, a45, a100 за найменшу кількість
операцій множення.
Розв’язок для а в 9-му степені.
Розв’язок для а в 27-му
a2 = a * a ;
степені
a4 = a2 * a2 ; /// a4
a8 = a4 * a4 ; /// a8 a3 = a * a * a ;
a9 = a8 * a ; /// 4 операції * 4 = a27 = a3 * a3 * a3 ;
або інший варіант /// 4 операції * 2 =
a3 = a * a * a ;
a9 = a3 * a3 * a3 ; /// 4 операції * 2 =
Розв’язок для а в 45-му степені aбо інший варіант
(45= 32+8+4+1 ) (45=15+15+15)
a2 = a * a ; a2 = a * a ;
a4 = a2 * a2 ; /// a4 a4 = a2 * a2 ; /// a4
a8 = a4 * a4 ; /// a8 a8 = a4 * a4 ; /// a8
a16 = a8 * a8 ; /// a16 a15 = a8 * a4 * а2 * a ; /// a15
a32 = a16 * a16 ; /// a32 a45 = a15 * a15 * a15 ;
a45 = a32 * a8 * a4 * a ;
/// 8 операцій * 5 =
/// 8 операцій * 6 =

4
Розв’язок для а в 100-му степені (100= 64+32+4 )
a2 = a * a ;
a4 = a2 * a2 ; /// a4
a8 = a4 * a4 ; /// a8
a16 = a8 * a8 ; /// a16
a32 = a16 * a16 ; /// a32
a64 = a32 * a32 ; /// a64
a100 = a64 * a32 * a4 ; /// 8 операцій *
Завдання 1.4. Використовуючи тільки оператор присвоєння і
операцію множення, обчислити a11, a22, a44, a99 за найменшу кількість
операцій.
Приклад 1. 4. Скласти програму для обчислення площі трикутника
за відомими довжинами сторін a, b, c.
Розв’язок
using System;
namespace Heron
{ class Program
{ public static void Main(string[] args)
{Console.WriteLine(
"Обчислення площі трикутника за формулою Герона");
double a,b,c;
Console.Write("Введiть значення a = ");
a = double.Parse(Console.ReadLine());
Console.Write("Введiть значення b = ");
b = double.Parse(Console.ReadLine());
Console.Write("Введiть значення c = ");
c = double.Parse(Console.ReadLine());
double p = ( a + b + c ) / 2 ;
double S = Math.Sqrt( p*(p - a)*(p - b)*(p - c));
Console.WriteLine("Площа трикутника S = {0}", S);
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
}
}

Завдання 1.5. Скласти програму для обчислення площі трапеції за


відомими довжинами основ та висоти.

Завдання 1.6. Скласти програму для визначення вартості золота,


рівного Вашій вазі. Передбачувана ціна золота $1257 за тройську
унцію. 1 тройська унція = 31г.

5
Приклад 1. 5. Скласти програму для обчислення площі трикутника
за відомими координатами вершин A( x1, y1 ), B( x2, y2 ), C( x3, y3 ).

Розв’язок
using System;
namespace TrianglesArea
{
class Program
{
public static void Main(string[] args)
{
Console.WriteLine( "Обчислення площі трикутника
за координатами вершин");
double x1,y1,x2,y2,x3,y3;
Console.Write("Введiть значення x1 = ");
x1 = double.Parse(Console.ReadLine());
Console.Write("Введiть значення y1 = ");
y1 = double.Parse(Console.ReadLine());
Console.Write("Введiть значення x2 = ");
x2 = double.Parse(Console.ReadLine());
Console.Write("Введiть значення y2 = ");
y2 = double.Parse(Console.ReadLine());
Console.Write("Введiть значення x3 = ");
x3 = double.Parse(Console.ReadLine());
Console.Write("Введiть значення y3 = ");
y3 = double.Parse(Console.ReadLine());
double S = Math.Abs((x1 *(y2 - y3) +
x2 *(y3 - y1) + x3 *(y1 - y2))/2);
Console.WriteLine("Площа трикутника S = {0}", S);
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
}
}

Завдання 1.7. Скласти програму для обчислення площі трикутника


за відомими довжиною сторони та двох прилягаючих кутів.

Завдання 1.8. Скласти програму для обчислення площі


прямокутника за відомими координатами вершин A( x1, y1 ), B( x2,
y2 ), C( x3, y3 ), D( x4, y4 ).

6
Використання нестандартних функцій
Приклад 1. 6. Скласти програму для обчислення площі опуклого
чотирикутника за відомими довжинами сторін a, b, c, d та діагоналі f .
Використати функцію для обчислення площі трикутника
Розв’язок
using System;
namespace QuadsArea
{ class Program
{public static void Main(string[] args)
{
Console.WriteLine(
"Обчислення площі чотирикутника");
double a,b,c,d,f;
Console.Write("Введiть значення a = ");
a = double.Parse(Console.ReadLine());
Console.Write("Введiть значення b = ");
b = double.Parse(Console.ReadLine());
Console.Write("Введiть значення c = ");
c = double.Parse(Console.ReadLine());
Console.Write("Введiть значення d = ");
d = double.Parse(Console.ReadLine());
Console.Write("Введiть значення f = ");
f = double.Parse(Console.ReadLine());
double S = TrianglesArea( a,b,f) +
TrianglesArea( c,d,f);
Console.WriteLine(
"Площа чотирикутника S = {0}", S);
}
static double TrianglesArea(double a, double b,
double c)
{
double p = ( a + b + c ) / 2 ;
double S = Math.Sqrt(
p * ( p - a ) * ( p - b ) * ( p - c ) ) ;
return S ;
}
}
}

Завдання 1.9. Скласти програму для обчислення площі правильного


N-кутника за відомим радіусом описаного кола та кількістю сторін.
Завдання 1.10. Скласти програму для обчислення площі правильного
N-кутника, якщо задані довжина сторони та кількість сторін.

7
Лабораторна робота №2.
Програмування розгалужених алгоритмів
мовою C# .NET
Приклад 2.1. Скласти програму для визначення найменшого із
чотирьох заданих чисел a, b, c, d . Використати функцію для
визначення меншого із двох заданих чисел.
Розв’язок
using System;
namespace MinABCD
{
class Program
{
public static void Main(string[] args)
{ Console.WriteLine("Визначення найменшого
із чотирьох заданих чисел ");
double a,b,c,d;
Console.Write("Введiть значення a = ");
a = double.Parse(Console.ReadLine());
Console.Write("Введiть значення b = ");
b = double.Parse(Console.ReadLine());
Console.Write("Введiть значення c = ");
c = double.Parse(Console.ReadLine());
Console.Write("Введiть значення d = ");
d = double.Parse(Console.ReadLine());
double min = MinXY( MinXY(a,b),MinXY(c,d));
Console.WriteLine(
"Найменше із {0},{1},{2},{3} = {4}",a,b,c,d,min);
}
static double MinXY(double x, double y)
{double m;
if (y > x) m = x;
else m = y;
Console.WriteLine(
"Мінімум iз {0} та {1} дорiвнює {2}", x, y, m);
return m ;
}
}
}
Зауваження. Умовний оператор може записуватись всередині
формул у вигляді тернарної операції:
double m = (y > x) ? x : y;

8
Приклад 2.2. Визначити, яке з двох заданих чисел x та y менше, а яке
більше. Скласти програму без використання умовного оператора.
Розв’язок.
double min = (x + y) / 2 – Math.Abs(x - y)/2;
double max = (x + y) / 2 + Math.Abs(x - y)/2;
Зауваження. Насправді умовний оператор неявно використовується
при обчисленні функції Abs(x) :
if (x<0) Abs = -x ; else Abs = x
Приклад 2.3. Скласти програму для знаходження коренів
квадратного рівняння a*x*x+b*x+c=0
Розв’язок.
using System;
namespace SquareEquation
{class Program
{public static void Main(string[] args)
{ Console.WriteLine(
"Розв’язування квадратного рівняння");
double a,b,c,d;
Console.Write("Введiть значення a = ");
a = double.Parse(Console.ReadLine());
Console.Write("Введiть значення b = ");
b = double.Parse(Console.ReadLine());
Console.Write("Введiть значення c = ");
c = double.Parse(Console.ReadLine());
d =b*b-4*a*c;
if (d<0)
{d = Math.Sqrt(-d);
double re = -b/(2*a);
double im = d/(2*a);
Console.WriteLine( "Комплексні корені
x1 = {0}+{1}i, x2 = {0}-{1}i",re,im);
}
else
{d = Math.Sqrt(d);
double x1 = (-b+d)/(2*a);
double x2 = (-b-d)/(2*a);
Console.WriteLine(
"Дійсні корені x1 = {0}, x2 = {1}", x1, x2);
}
}
}
}

9
Завдання 2.1. Скласти програму для знаходження всіх дійсних
коренів біквадратного рівняння та обчислення їх кількості
a*x*x*x*x+b*x*x+c=0 або a*z*z+b*z+c=0 , z=x*x

Календарні розрахунки
Приклад 2. 4. Скласти програму для визначення дня тижня для
заданої дати ХХ та ХХІ століть.
Розв’язок. Враховуючи, що 31 грудня 1989 року була неділя,
знайдемо кількість днів, яка пройшла від початку двадцятого сторіччя
до заданої дати. Потім за залишком від ділення на 7 можна визначити
день тижня.
При цьому календарні розрахунки (обчислення кількості
пройдених днів) можна значно спростити, якщо початок року
перенести з 1 січня на 1 березня. Тоді кожен з пройдених 11 місяців
матиме 30 або 31 день і з допомогою множення числа 30,59 на
кількість пройдених від 1 березня місяців і виділення цілої частини
одержаного добутку дістанемо точне число днів за скоректовану
кількість місяців. Додавши цілу частину добутку 365,25 на кількість
пройдених років і число днів за останній місяць, отримаємо шукану
кількість днів.
Наведений алгоритм коректно працює для дат ХХ і ХХІ
століть. Для інших століть потрібно враховувати високосні сторіччя за
григоріанським календарем: якщо номер століття ділиться націло на 4,
то останній рік має 366 днів, якщо ні , то – 365. Наприклад, 1600, 2000
рік - 366 днів, 1700,1800,1900,2100 – 365.
using System;
namespace XX_XXI_Century
{ class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Календарні розрахунки");
int day, month, year;
Console.Write("Введiть число day = ");
day = int.Parse(Console.ReadLine());
Console.Write("Введiть місяць month = ");
month = int.Parse(Console.ReadLine());
Console.Write("Введiть рік year = ");
year = int.Parse(Console.ReadLine());
int cor = ( 12 -month ) / 10 ;
int year1 = year - cor ;

10
int month1 = month + 12 * cor - 2 ;
int number = (int)( (double)((year1-1900)*365.25))
+(int)((double)( month1 * 30.59 )) + day + 29 ;
int dayOfWeek = number % 7 ;
switch (dayOfWeek)
{
case 0:
Console.WriteLine("Sunday");
break;
case 1:
Console.WriteLine("Monday");
break;
case 2:
Console.WriteLine("Tuesday");
break;
case 3:
Console.WriteLine("Wednesday");
break;
case 4:
Console.WriteLine("Thursday");
break;
case 5:
Console.WriteLine("Friday");
break;
case 6:
Console.WriteLine("Saturday");
break;
}
}
}
}
Завдання 2.2. Скласти програму для визначення відстані (кількості
днів) між двома заданими датами ХХ та ХХІ століть. Обчислити
кількість прожитих Вами днів.

11
Лабораторна робота №3.
Програмування циклічних алгоритмів
мовою C# .NET

Табулювання функції
Приклад 3.1. Скласти програму для побудови таблиці значень
функції y=sin x , для x в діапазоні від x0=0 до x1=45 градусів з
кроком h=5 градусів.
Розв’язок з оператором циклу з передумовою while
while (<умова повторення>) <тіло циклу>;
using System;
namespace Tabulation
{ class Program
{public static void Main(string[] args)
{Console.WriteLine("Табулювання функції ");
double x0, x1, h;
Console.Write("Введiть початок відрізка x0 = ");
x0 = double.Parse(Console.ReadLine());
Console.Write("Введiть кінець відрізка x1 = ");
x1 = double.Parse(Console.ReadLine());
Console.Write("Введiть крок h = ");
h = double.Parse(Console.ReadLine());
double x = x0 ;
while (x <= x1)
{ double y = Math.Sin ( x * Math.PI /180 ) ;
Console.WriteLine(
" x = {0:F2} y = {1:F16} \n", x, y);
x = x + h ;
} } } }

Розв’язок з оператором циклу з післяумовою do … while


do { <тіло циклу> } while (< умова повторення >)
double x = x0 ;
do
{ double y = Math.Sin ( x * Math.PI /180 ) ;
Console.WriteLine(
" x = {0:F2} y = {1:F16} \n", x, y);
x = x + h ;
}
while (x < x1);

12
Розв’язок з оператором циклу з параметром for
for(<ініціалізація параметра>; <умова повторення>;
<зміна параметра> ) <тіло циклу>;
double x = x0 ;
int n = (int) ((x1 - x0)/h) ;
for ( int i = 0 ; i <= n ; i++)
{ double y = Math.Sin ( x * Math.PI /180 ) ;
Console.WriteLine(
" x = {0:F2} y = {1:F16} \n", x, y);
x = x + h ;
}
Скінченна сума
Приклад 3.2. Cкласти програму для обчислення суми квадратів цілих
чисел від 1 до 100. S = 12+22 +32+42+52 +62+72 +82 +92 +...+1002
Розв’язок
double s = 0.0d ;
for ( int i = 1 ; i <= 100 ; i++ )
s = s + (double) (i*i) ;
Console.WriteLine(" s = {0}", s);
Сума знакозмінного ряду
Приклад 3.3. Cкласти програму для обчислення суми знакозмінного
ряду S=1 - 1/2+1/3 - 1/4+1/5 - 1/6 + ... -1/100000
а) в прямому порядку ;
б) в оберненому порядку ;
а) в прямому порядку окремо додатні та від’ємні числа;
б) в оберненому порядку окремо додатні та від’ємні числа.
Порівняти одержані результати. Пояснити виникнення похибок. Який
з варіантів є найбільш точним?
Розв’язок
double s = 0.0d ; double z = 1.0d ;
for ( int i = 1 ; i <= 100000 ; i++ )
{ s = s + z/(double)i ; z=-z ;}
Console.WriteLine(
"Сума в прямому порядку s = {0:E16}", s);
s = 0.0d ; z = -1.0d ;
for ( int i = 100000 ; i >= 1 ; i-- )
{ s = s + z/(double)i ; z=-z ;}
Console.WriteLine(
"Сума в зворотньому порядку s = {0:E16}", s);

13
double s1 = 0.0d ;
for ( int i = 1 ; i < 100000 ; i+=2 )
s1 = s1 + 1.0d /(double)i ;
Console.WriteLine(
"Сума додатніх в прямому порядку s1 = {0:E16}", s1);
double s2 = 0.0d ;
for ( int i = 2 ; i <= 100000 ; i+=2 )
s2 = s2 + 1.0d /(double)i ;
Console.WriteLine(
"Сума від’ємних в прямому порядку s2 = {0:E16}", s2);
Console.WriteLine("s1 - s2 = {0:E16}", s1-s2);
s1 = 0.0d ;
for ( int i = 99999 ; i >= 1 ; i-=2 )
s1 = s1 + 1.0d /(double)i ;
Console.WriteLine(
"Сума додатніх в зворотньому порядку s1 = {0:E16}",s1);
s2 = 0.0d ;
for ( int i = 100000 ; i > 1 ; i-=2 )
s2 = s2 + 1.0d /(double)i ;
Console.WriteLine(
"Сума від’ємних в зворотньому порядку s2={0:E16}",s2);
Console.WriteLine("s1 - s2 = {0:E16}", s1-s2);
Алгоритм Евкліда
Приклад 3.4. Скласти програму для визначення найбільшого
спільного дільника двох натуральних чисел за алгоритмом Евкліда,
який грунтується на властивості :
Найбільший спільний дільник двох чисел не змінюється,
якщо одне з чисел замінити їх різницею
Розв’язок.
int x, y;
Console.Write("Введiть число x = ");
x = int.Parse(Console.ReadLine());
Console.Write("Введiть число y = ");
y = int.Parse(Console.ReadLine());
while (x != y )
{ if (x>y) x-= y ; else y-=x; }
Console.WriteLine("НСД = {0}", x);
Числа Фібоначчі
Приклад 3.5. Задано x1=1, x2=1 - перших два елементи числової
поcлідовності. Кожен наступний елемент дорівнює сумі двох
попередніх. Скласти програму для обчислення елемента з номером n.

14
int n;
Console.Write("Введiть номер n= ");
n = int.Parse(Console.ReadLine());
int x1 = 1; int x2 = 1 ;
for (int i = 3 ; i<=n ; i++)
{
int x:= x1 + x2 ; x1 = x2 ; x2 = x ;
}
Console.WriteLine(" x[{0}] = {1}", n, x);

Cкладні проценти
Завдання 3.1. За один хід поршня з резервуару відкачується k
відсотків повітря. Обчислити залишок повітря після n ходів, якщо
початкова маса m.

Завдання 3.2. За один рік банк нараховує p% . Скласти програму для


обчислення величини рахунку через n років для початкового внеску в
розмірі S гривень.
Двійкові числа
Приклад 3.6. Cкласти програму для переведення цілих чисел з
десяткової системи числення в двійкову.
Розв’язок. Переведення відбувається з допомогою послідовного
ділення заданого десяткового числа і отримуваних часток на 2.
Остання частка із залишками від ділення, записаними у зворотньому
порядку, дають шуканий двійковий код, наприклад,

_ 765 |_2_
744 372|_2_
----- 372 186|_2_
1 ----- 186 93|_2_
0 ----- 92 46|_2_
0 --- 46 23|_2_
1 --- 22 11|_2_
0 --- 10 5 |_2_
1 --- 4 2|_2_
1 -- 2 1
1 --
0
(765)10= (1011101001)2

15
int n;
Console.Write("Введiть ціле число n= ");
n = int.Parse(Console.ReadLine());
string s = "";
do
{if ( n % 2 == 1) s = "1" + s ;
else s = "0" + s;
n = n / 2 ;
}
while ( n != 0) ;
Console.WriteLine("Binary = {0}", s);

Двійкові дроби
Приклад 3.7. Cкласти програму для переведення десяткових дробів в
двійкову систему числення з точністю K розрядів.
Розв’язок. Переведення відбувається з допомогою послідовного
множення заданого десяткового дробу на 2. Якщо отримується
число>1, в двійкове представлення записується цифра “1”, інакше
цифра “0”. Поскільки скінченні десяткові дроби в двійковій формі
стають для більшості випадків нескінченними, то на певному кроці
процес множення обривають.

0, 678 double r ;
х 2 int k = 10; /// точність
--------- Console.Write(
1, 356 (-1)
х 2 "Введiть десятковий дріб
--------- (число від 0.0 до 1.0) r = ");
0, 712 ( 0) r = double.Parse(Console.ReadLine());
х 2 string s = "0.";
--------- for ( int i = 1; i<=k ; i++)
1, 424 (-1)
х 2 {
--------- r *= 2.0d;
0, 848 (0) if (r < 1.0d ) s += "0" ;
х 2 else {s += "1" ; r -= 1.0d ;}
---------
1, 696 (-1) }
х 2 Console.WriteLine("Binary = {0}", s);
---------
1, 392 (-1 )
х 2
---------
0, 784 (0) ( 0, 678 )10= =( 0, 1010110 ...) 2

16
Лабораторна робота №4.
Обробка одновимірних масивів в C# .NET

4.1. Загальні відомості про масиви

• Масив може бути одновимірним (вектор) або масивом масивів,


серед яких виділяють двовимірні з однаковою довжиною рядків
(матриця), ступінчасті (зубчасті або розріджені), тривимірні і т.д.
• Кількість вимірів та довжину кожного виміру задають в
момент створення екземпляра масиву. Ці значення неможливо змінити
під час існування екземпляра, але можна створити новий масив іншої
розмірності з таким самим ідентифікатором. Тоді попередній
екземпляр масива зникне з пам’яті і стане недоступний.
• Значения за замовчуванням елементів числових масивів
дорівнює нулю, а елементи-посилання отримують за замовчуванням
значення NULL.
• Розріджені зубчасті масиви є масивами масивів, їх елементи є
посиланнями (вказівниками) і ініціалізуються значенням NULL.
• Індекси масивів починаються з нуля: масив с n елементами
індексується від 0 до n-1.
• Елементи масива можуть бути довільного типу, включно з
типом масиву.
• Типи масиву є посиланнями (reference type), похідними від
абстрактного базового типа Array. Поскільки він реалізує тип
IEnumerable, в C# до всіх масивів можна застосовувати цикл foreach
для послідовного перегляду і обробки всіх елементів.

Традиційно масивом вважається пронумерований набір даних


одного типу, розміщених послідовно в оперативній пам’яті і
об’єднаних одним ім’ям (ідентифікатором). Звертання до окремих
елементів масиву здійснюється з допомогою номера-індекса, який
вказується в квадратних дужках після імені масиву, наприклад, A[1],
A[100], A[i].
Масиви відносяться до складних типів даних, які будуються на
основі простих та інших складних типів.
Оголошення, ініціалізація одновимірних масивів
В мові C# масиви є об’єктами класу System.Array. Вони
автоматично розміщуються в динамічній пам’яті і перед
використанням повинні бути оголошені, причому розмірність при
цьому можна не вказувати.

17
Для оголошення одновимірного масиву в C# використовується
наступний синтаксис:
type[] arrayName; тип даних [] назва_масиву;
Приклади: int[] b; double[] Weight;
На відміну від С++, де масиви можуть створюватись як статично
так і динамічно, у C# всі масиви є динамічними, тому, у наведених
прикладах ідентифікатори “b” та “Weight” фактично є посиланнями на
майбутні масиви.
Спроба використати таке посилання до його ініціалізації
призводить до помилки компіляції.
Масиви у C# створюються (ініціалізуються) за допомогою
оператора new, синтаксис якого для одновимірних масивів
аналогічний синтаксису відповідного оператора мови С++:

назва масиву = new тип даних[кількість елементів];

Після створення масиву його елементи автоматично


ініціалізуються нульовими значеннями, наприклад, 0, “\0”, NULL
залежно від типу елементів.
Ініціалізацію елементів масиву можна виконати безпосередньо в
момент його створення. При цьому вказувати кількість елементів не
обов’язково: компілятор визначить її за кількістю вказаних
ініціалізаторів:

назва масиву = new тип даних[] {зн.1, зн.2, ..., зн.N};

При використанні ініціалізаторів в момент оголошення


дозволяється взагалі не використовувати оператор new для створення
масиву.
Приклади:
float[] s = {0.1f, 0.2f, 0.4f, 0.8f};
int[] myArray = new int[100];
char[] a = new char[3] {“і”, “ї”, “є”};
double[] x; x = new double[] {0.1, 0.2, 0.3};
string[] weekDays = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };

Якщо ми не вказуємо значення елемента масиву, а лише


виділяємо пам'ять, то в C# за замовчуванням записується нуль.

18
Для обробки масивів, як правило, використовуються цикли
з лічильником-параметром for. При спробі звернутись до елемента
масиву за індексом, що виходить за допустимі межі, середовище
виконання CLR генерує виключення IndexOutOfRangeException
(“Індекс знаходиться поза межами масиву”).
Приклад заповнення масиву випадковими числами:
int[] myArray = new int[100];
Random RndGen = new Random ();
for (int i = 0; i < myArray.Length; i++)
{ myArray[i] = RndGen.Next (10);}
Якщо необхідно послідовно отримати доступ до значення
кожного елемента масиву, доцільно використовувати спеціальний
оператор foreach (англ. for each - для кожного).
Приклад:
double[] x;
x = new double[] {0.1, 0.2, 0.3};
foreach ( double Val in x)
{System.Write (Val + “ “); }

4.2. Масиви як об’єкти


В C# масиви фактично є об’єктами, а не просто адресованими
областями неперервної пам’яті, як в C і C++. Array є абстрактним
базовим класом всіх типів масивів. Можна використовувати
властивості і методи класу Array. Наприклад, можна використати
властивість Length для визначення довжини масиву:
int[] numbers = { 1, 2, 3, 4, 5 };
int lengthOfNumbers = numbers.Length;
або Rank для визначення кількості вимірів:
int[,] theArray = new int[5, 10];
System.Console.WriteLine(
"The array has {0} dimensions.", theArray.Rank);
// Output: The array has 2 dimensions.

4.3. Створення масивів довільного типу


Масиви можна створювати також з допомогою статичного методу
CreateInstance(). Це зручно, коли наперед невідомий тип елементів
масиву, поскільки тип можна передати методу CreateInstance() в якості
параметра.
Значення в массив встановлюються методом SetValue(), а читаються
методом GetValue().

19
Приклад.
/// Створюємо масив типу string розмірності 5
Array myArr = Array.CreateInstance(typeof(string),5);
/// Ініціалізуємо перші два елементи масиву
myArr.SetValue("Name",0); myArr.SetValue("Age",1);
/// Зчитуємо дані з масиву
string s = (string)myArr.GetValue(1);

4.4. Приклади обробки одновимірних масивів


Приклад 4.1. Обчислити суму елементів заданого дійсночисельного
масиву розмірності N. Елементи задаються введенням з консолі.
using System;
namespace arrays
{
class Program
{
public static void Main(string[] args)
{
int N;
Console.Write("Введiть розмірність масиву N = ");
N = int.Parse(Console.ReadLine());
/// ініціалізація масиву
double[] X = new double [N];
/// введення масиву з консолі
for(int i=0;i<N;i++)
{ Console.Write("Введiть елемент Х[{0}] = ",i);
X[i] = double.Parse(Console.ReadLine());
}
/// обчислення суми елементів масиву
double S = 0.0d;
for (int i=0;i<N;i++) S+=X[i];
Console.WriteLine(
"Сума елементів масиву S = {0}", S);
// виведення елементів масиву
for (int i=0;i<N;i++)
Console.Write("Х[{0}] = {1} ",i,X[i]);
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
}
}

20
Приклад 4.2. Обчислити суму від’ємних елементів заданого дійсно-
чисельного масиву розмірності N.
/// обчислення суми від’ємних елементів масиву
double S = 0.0d;
for (int i=0;i<N;i++) if (X[i]<0)S+=X[i];
Console.WriteLine(
"Сума від’ємних елементів масиву S = {0}", S);

Приклад 4.3. Обчислити суму елементів з парними індексами


заданого дійсно- чисельного масиву розмірності N.
/// обчислення суми елементів з парними індексами
double S = 0.0d;
for (int i=0;i<N;i+=2) S+=X[i];
Console.WriteLine(
"Сума елементів з парними індексами S = {0}", S);

Приклад 4.4. Обчислити кількість від’ємних елементів заданого


дійсно чисельного масиву розмірності N.
/// обчислення кількості від’ємних елементів масиву
int K = 0;
for (int i=0;i<N;i++) if (X[i]<0) K++;
Console.WriteLine(
"Кількість від’ємних елементів масиву K = {0}",K );

Приклад 4.5. Обчислити середнє арифметичне від’ємних елементів


заданого дійсночисельного масиву розмірності N.
/// обчислення середнього арифметичного
/// від’ємних елементів масиву
int K = 0; double S = 0.0d;
for (int i=0;i<N;i++) if (X[i]<0) {K++; S+=X[i];}
Console.WriteLine( "середнє арифметичне
від’ємних елементів = {0}",S/K );

Приклад 4.6. Визначити мінімальний елемент заданого


дійсночисельного масиву розмірності N.
/// мінімальний елемент масиву
double Min = X[0];
for (int i=1;i<N;i++) if ( X[i] < Min ) Min = X[i];
Console.WriteLine(
"Мінімальний елемент масиву Min = {0}", Min );

21
Приклад 4.7. В заданому масиві X розмірності N змінити порядок
розташування елементів на протилежний без використання
додаткового масиву.
Варіант 1 (без використання методу Array.Reverse)
double T ;
for (int i=0; i < N/2 ; i++)
{ T = X[i] ; X [i]= X[N-i-1]; X [N-i-1]= T; }
Варіант 2 (з використанням методу Array.Reverse)
Array.Reverse(X);

Приклад 4.8. Для заданих векторів X та Y розмірності N


обчислити скалярний добуток.
double S = 0.0d;
for (int i=0;i<N;i++) S+=X[i]*Y[i];
Console.WriteLine(
"Скалярний добуток векторів S = {0}", S);
Площа многокутника
Приклад 4.9. Скласти програму для обчислення площі
многокутника за відомими координатами його вершин, які задані
векторами X та Y розмірності N.
double S = 0.0d;
for (int i=0;i<N;i++)
S+= X[i]*(Y[(i+1)%N] – Y[(i+2)%N] ;
S/=2;
Console.WriteLine("Площа многокутника S = {0}", S);

4.5. Копіювання масивів


Поскільки масиви — вказівникові типи, присвоєння змінної
типу масиву іншій змінній створює дві змінні, що вказують на один
масив в пам’яті.
Для копіювання масивів використовуються методи
Array.Сору() та Array.Clone().
Метод Clone() створює неглибоку копію масива. Якщо
елементи масива відносяться до типу-значень, то всі вони
копіююються, якщо масив містить елементи типів-посилань, то самі
елементи не копіюються, а копіюються лише посилання на них.
Метод Array.Сору() теж створює поверхневу копію, але якщо Clone()
створює новий масив, то Сору() вимагає існування масива з
достатньою кількістю елементів.

22
Приклад 4.10.
string[] arr2 = new string[5];
/// Створюємо масив типу string розмірності 5
Array myArr = Array.CreateInstance(typeof(string),5);
/// Ініціалізуємо перші три елементи масиву
myArr.SetValue("Name",0);
myArr.SetValue("Age",1);
myArr.SetValue("Adress",2);
/// Копіюємо масив методом Clone()
string[] arr1 = (string[])myArr.Clone();
foreach (string s in arr1) Console.Write(s+"");
Console.WriteLine();
/// Копіюємо масив методом Copy()
Array.Copy(myArr, arr2, myArr.Length);
foreach (string s in arr2) Console.Write(s+" ");
Console.WriteLine();

4.6. Генерування масиву простих чисел ( Алгоритм Ератосфена )


Приклад 4.11.
int N=1000000; ///тип ulong від 0 до
18446744073709551615
ulong [] P = new ulong[N];
ulong k, d, L; int m; bool Prime;
P[0]=2; P[1]=3 ;
k = 5 ; m = 2 ;
do
{ d = (ulong) Math.Sqrt(k);
Prime = true ;
L=0;
do
{if (k%P[L]==0) { Prime=false; break ;}
L++;
}
while (P[L] <= d);
if (Prime) { P[m]=k; m++;}
k+=2;
}
while (m<N);
/// виведення останніх 10 елементів масиву
for (int i=N-10;i<N;i++)
Console.Write("Х[{0}] = {1} ",i,P[i]);
Console.WriteLine();

23
Лабораторна робота №5.
Алгоритми сортування, пошуку та злиття
одновимірних масивів в C# .NET

5.1. Сортування масивів


Відсортованим в прямому порядку (або за зростанням ) називається
масив, для елементів якого виконуються співвідношення
A[0] ≤ A[1] ≤ A[2] ≤ ... ≤ A[N-1] ≤ A [N]
Інверсією називається таке розташування сусідніх елементів масиву,
яке не відповідає потрібному порядку сортування, тобто,
A[ i] > A [ i + 1]
Для масивів, відсортованих в зворотньому порядку ( або за спаданням
) наведені вище співвідношення протилежні.
Кількість інверсій є мірою впорядкованості масиву. У повністю
відсортованому масиві кількість інверсій = 0, якщо масив
відсортований в протилежному порядку, кількість інверсій = N-1.
Для оцінки ефективністі і швидкості роботи конкретних алгоритмів
сортування використовують середньостатистичні значення кількості
операцій порівнянь і кількості перестановок (обміну значень), які
потрібно виконати для впорядкування. Також для кожного алгоритму
перевіряють ефективність роботи в особливих випадках: коли масив
майже або повністю відсортований або відсортований в
протилежному порядку.
З метою скорочення записів і зручності для перестановки двох
елементів (обміну значень змінних) в алгоритмах сортування
використовується процедура Swap.
Це можна здійснювати трьома способами (див. лаб. роботу 1)
/// Обмін значень двох елементів будь-якого типу
private static void Swap(ref int i, ref int j)
{ int temp = i; i = j; j = temp ;}
/// Обмін значень двох елементів числових типів + -
private static void Swap(ref int i, ref int j)
{ i = i + j; j = i - j; i = i - j;}
/// або { i+= j; j = i - j; i-= j;}

/// Обмін значень двох елементів побітовим XORом


private static void Swap(ref int i, ref int j)
{ i = i ^ j; j = j ^ i; i = i ^ j;}
/// або { i ^= j; j ^= i; i ^= j;}

24
Метод бульбашки (англ. Bubble sort) полягає в порівнянні сусідніх
елементів масиву між собою з їх перестановкою у випадку, якщо їх
розташування не відповідає потрібному порядку сортування (тобто у
випадку інверсії). В результаті одного перегляду масиву самий
“важкий” елемент витісняється в кінець масиву, тому для наступного
перегляду довжину масиву можна зменшити на одиницю. Метод
названий за аналогією з поведінкою повітряних бульбашок у склянці
кока-коли, коли самі великі бульбашки відриваються від дна і
досягають поверхні першими.
/// Сортування методом бульбашки (Bubble sort)
private static void BubbleSort(ref int[] A)
{for ( int L=A.Length;L>1; L--)
for ( int K=0;K<L-1;K++)
if ( A[K] > A[K+1] ) Swap(ref A[K], ref A[K+1]);
}
На практиці метод бульбашки застосовується для сортування майже
впорядкованих масивів та файлів баз даних, які виникають при
періодичному доповненні відсортованих раніше новими елементами.
Сортування змішуванням (англ. Cocktail sort) — вдосконалений
метод бульбашки. Аналізуючи метод бульбашки, відмічаємо дві
обставини:
1) Якщо при переміщенні вздовж частини масиву перестановки не
відбуваються, то ця частина масиву вже відсортована і далі
непотрібно її переглядати.
2) При переміщенні від початку до кінця масиву максимальний
елемент досягає кінця масиву, а мінімальний зміщується тільки на
одну позицію. Якщо рухатись в протилежному напрямі, то навпаки –
мінімальний елемент досягає свою позицію на початку масиву, а
максимальний рухається повільно.
Тому у вдосконаленому методі бульбашки запам’ятовують позиції
інверсій, і встановлюють межі наступного перегляду в місцях, де
відбувались останні перестановки. Масив переглядається по черзі
справа наліво і зліва направо.
/// Шейкерне сортування
static void CocktailSort(ref int[] A)
{int start, finish;
int countIf = 0;//лічильник порівнянь
int countSwap = 0;//лічильник перестановок

25
for (int i = 0; i < A.Length/2; i++)
{ start = 0; finish = A.Length - 1;
do
{ countIf += 2;
/// перегляд зліва направо
if (A[start] > A[start + 1])
{ Swap(ref A[start], ref A[start+1]); countSwap++;}
start++; /// переміщаємо ліву границю перегляду
/// перегляд справа наліво
if (A[finish-1] > A[finish])
{ Swap(ref A[finish-1], ref A[finish]); countSwap++;}
finish--; ///переміщаємо праву границю перегляду
} /// умова продовження переглядів
while (start <= finish);
}
Console.WriteLine("Кількість порівнянь = {0}",countIf);
Console.WriteLine
("Кількість перестановок = {0}",countSwap);
}

Швидке сортування. (англ. Quick sort) -- найбільш ефективний


алгоритм для невпорядкованих масивів з великою кількістю інверсій.
Рекурсивний, тобто викликає в оперативній пам’яті власні копії, тому
використовує значний об’єм додаткової пам’яті.
Складається з таких кроків :
• вибір ведучого елемента в центрі масиву;
• розбиття масиву: елементи, розташовані справа і менші ведучого
міняються місцями з елементами зліва, які більші ведучого; в
результаті ведучий елемент потрапляє на потрібне місце, бо зліва
будуть розташовані всі елементи менші за нього, а справа більші;
• до лівої частини повторно застосовується такий самий алгоритм,
тобто викликається копія процедури швидкого сортування;
• до правої частини повторно застосовується такий самий алгоритм.
Рекурсивні виклики тривають до тих пір, поки частини містять хоча б
один елемент.
Метод швидкого сортування реалізований у стандартному методі Sort
() класу Array. Метод Sort() вимагає від елементів реалізації
інтерфейсу IComparable. Прості типи, такі як System.String і
System.Int32, реалізують IComparable, тому можна сортувати
елементи, що відносяться до цих типів.
З допомогою різних варіантів методу Sort() можна відсортувати масив

26
повністю або в заданих межах або відсортувати два масива, що
містять відповідні пари "ключ-значення". Після сортування в масиві
можна здійснювати пошук з допомогою ефективного алгоритму
бінарного пошуку, реалізованого в методі BinarySearch().
Приклад 5.1.
using System;
namespace ArraySorting
{class Program
{public static void Main(string[] args)
{ int[] A = { 4, 5, -183, 12, 34, 0, 2 ,-13 };
Console.WriteLine("Заданий масив: ");
foreach (int x in A) Console.Write("{0} ",x);
Console.WriteLine();
Console.WriteLine("Відсортований масив:");
Array.Sort(A);
foreach (int x in A)Console.Write("{0} ",x);
Console.WriteLine();
/// Бінарний пошук заданого елемента
/// у відсортованому масиві
Console.WriteLine("Пошук числа 12 у масиві А:");
int search = Array.BinarySearch(A, 12);
Console.WriteLine(
"Число 12 знаходиться на {0} позиції",search+1);
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
}
}

Завдання 5.1.
• Створити цілочисельний масив А розмірності N=100.
int N=100; int[] A = new int[N];
• Заповнити масив випадковими числами в діапазоні [-N, N-1].
/// створення об’єкту класу Random
Random R = new Random();
/// цикл для всіх індексів масиву А
for (int i = 0; i < A.Length; i++)
/// одержуємо ціле невід’ємне число
/// в діапазоні[0,2*N-1]
/// віднявши N одержимо діапазон [-N, N-1]
A[i] = R.Next (2*N)-N;
• Вивести масив А на консоль по 10 елементів в рядку

27
/// виведення елементів масиву
Console.WriteLine("Масив A")
for (int i=0;i<N;i++)
{Console.Write("{0} \t",A[i]);
if (i%10==9) Console.WriteLine();}
Console.WriteLine();
• Дослідити створений масив на впорядкованість (обчислити
кількість інверсій).
int Inv = 0;
for (int i=0;i<N-1;i++)
if (A[i]>A[i+1]) Inv ++;
Console.WriteLine("Кількість інверсій = {0}", Inv);
• Створити копію А1 масиву А
/// Копіюємо масив методом Clone()
int[] A1 = (int[])A.Clone();
• Відсортувати масив А1 методом швидкого сортування Array.Sort.
Array.Sort(A1);
• Вивести відсортований масив А1 на консоль по 10 елементів в
рядку.
• Перевірити відсортований масив А1 на впорядкованість
(обчислити кількість інверсій).
Inv = 0;
for (int i=0;i<N-1;i++)
if (A1[i]>A1[i+1]) Inv ++;
Console.WriteLine("Кількість інверсій = {0}", Inv);
• Створити нову копію А1 масиву А.
/// Копіюємо масив методом Clone()
A1 = (int[])A.Clone();
• Відсортувати масив А1 вдосконаленим методом бульбашки (метод
перемішування або шейкерне сортування).
CocktailSort(ref A1);
• Вивести відсортований масив А1 на консоль по 10 елементів в
рядку.
• Перевірити відсортований масив А1 на впорядкованість
(обчислити кількість інверсій).
• Відлагодити програму.
• Додати системні функції для вимірювання проміжків часу між
початком і закінченням роботи алгоритмів сортування.
using System.Diagnostics; // додати на початку програми

28
Stopwatch T = new Stopwatch();
T.Start();
Array.Sort(A1); /// сортування масиву (QuickSort)
T.Stop();
Console.WriteLine
("час сортування методом QuickSort {0} ",T.Elapsed);
T.Reset();
T.Start();
CocktailSort(ref A1);
T.Stop();
Console.WriteLine
("час сортування методом CocktailSort {0} ",T.Elapsed);
• Відключити (коментарями /* */) код для виведення масивів.
• Збільшити розмірність масивів (N=10000).
Console.WriteLine("кількість елементів N={0}”,N);
• Порівняти час сортування обома алгоритмами.
• Застосувати алгоритм швидкого сортування до вже відсортованого
масиву (з вимірюванням часу).
• Застосувати алгоритм шейкерного сортування до вже
відсортованого масиву (з вимірюванням часу).
• Порівняти час роботи обох алгоритмів для вже відсортованого
масиву.
• Змінити розташування елементів у вже відсортованому масиві А1
на протилежне методом Array.Reverse.
Array.Reverse(A1);
• Обчислити кількість інверсій.
• Застосувати алгоритм швидкого сортування до відсортованого в
протилежному порядку масиву А1 (з вимірюванням часу).
• Змінити розташування елементів у вже відсортованому масиві А1
на протилежне методом Array.Reverse.
Array.Reverse(A1);
• Застосувати алгоритм шейкерного сортування до відсортованого в
протилежному порядку масиву А1 (з вимірюванням часу).
• Порівняти час роботи обох алгоритмів для відсортованого в
протилежному порядку масиву. Записати результати та висновки в
звіт.
• Додати до звіту відлагоджені тексти програм та скріншоти з
початковим та відсортованим масивами (для N=100).

29
5.2. Злиття відсортованих масивів
Завдання 5.2.
• Створити цілочисельний масив А розмірності N=100.
int N=100; int[] A = new int[N];
• Заповнити масив випадковими числами в діапазоні [0, N-1].
• Вивести масив A на консоль по 10 елементів в рядку.
• Відсортувати масив А методом швидкого сортування Array.Sort.
Array.Sort(A);
• Вивести відсортований масив A на консоль по 10 елементів в
рядку.
• Перевірити відсортований масив на впорядкованість (обчислити
кількість інверсій).
• Створити цілочисельний масив B розмірності M=200.
int M=200; int[] B = new int[M];
• Заповнити масив випадковими числами в діапазоні [0, M-1].
• Вивести масив B на консоль по 10 елементів в рядку.
• Відсортувати масив B методом швидкого сортування Array.Sort.
Array.Sort(B);
• Вивести відсортований масив B на консоль по 10 елементів в
рядку.
• Перевірити відсортований масив на впорядкованість (обчислити
кількість інверсій).
• Об’єднати (злити) відсортовані масиви в новий масив Z
розмірності N+M так, щоб елементи в новому масиві були
впорядковані.
З відсортованих масивів беремо по одному елементу, порівнюємо між
собою і менший записуємо в результуючий масив. Для контролю за
процесами вибірки та занесення для кожного з трьох масивів A, B, Z
використовується свій лічильник a , b , k. Якщо з одного масиву
вибрано всі елементи, в результуючий дописується залишок іншого.
Приклад 5.2.
/// Злиття двох відсортованих масивів
int [] Z = new int[N+M]; int a = 0 ; int b = 0 ;
for ( int k = 0 ; k<N+M ; k++)
{if ( a >= N) { Z[ k ] = B [ b ] ; b++ ; continue ;}
if ( b >= M) { Z[ k ] = A [ a ] ; a++ ; continue ;}
if (A[ a ] <= B [ b ]) { Z[ k ] = A [ a ]; a++ ; }
else { Z[ k ] = B [ b ] ; b++ ; }
}

30
• Вивести масив Z на консоль по 10 елементів в рядку.
• Перевірити масив Z на впорядкованість (обчислити кількість
інверсій).
• Додати до звіту відлагоджений текст програм та скріншоти з
початковими та результуючим масивами.

5.3. Алгоритми пошуку значень елементів в масивах
5.3.1. Лінійний пошук
Використовується для пошуку одного елемента (або декількох рівних
елементів) з потрібним значенням у заданому невідсортованому
масиві.
Лінійний пошук - алгоритм послідовного перегляду масиву і
порівняння всіх елементів з шуканим значенням. Є найпростішим
алгоритмом пошуку, не накладає жодних обмежень на масив і має
просту реалізацію. У зв'язку з малою ефективністю в порівнянні з
іншими алгоритмами лінійний пошук зазвичай використовують лише
тоді, коли відрізок пошукової системи містить дуже мало елементів,
однак лінійний пошук не вимагає додаткової пам'яті або
обробки/аналізу масиву.
Приклад 5.3.
static int LinearSearch(int[] A, key)
{ L=-1;
for ( int i=0; i < A.Length ; i++)
if ( A[i] == key){ L = I ; break }
return L;
}
Тут Arr.Length - це розмірність масиву, key - значення яке ми
шукаємо, якщо елемент масиву співпадає з key, повертаємо його
індекс. Якщо елемент із заданим значенням відсутний, --
повертається -1.
5.3.2. Двійковий (бінарний) пошук
Також називають методом поділу пополам або дихотомія.
Використовується для швидкого пошуку потрібної інформації у
заданому відсортованому масиві.
Дихотомічний пошук (двійковий пошук) — алгоритм знаходження
заданого значення у впорядкованомумасиві, який полягає у порівнянні
серединного елемента масиву з шуканим значенням, і повторенням
алгоритму для тієї або іншої половини, залежно від результату

31
порівняння. Зазвичай реалізується методом рекурсії, або ітерації.
Основна вимога до масиву-впорядкованість.
Приклад реалізації дихотомічного пошуку рекурсивним методом.
Приклад 5.4.
static void BinarySearch(int[] A, value, low, high)
{ if (high < low) return -1 ; // не знайдено
mid = (low + high) / 2 ;
if (A[mid] > value)
return BinarySearch( A, value, low, mid-1);
else
if (A[mid] < value)
return BinarySearch( A, value, mid+1, high)
else return mid ; // знайдено
}

Спочатку порівнюється шукане значення з елементом, розташованим


посередині і в залежності від результату далі розглядається тільки
половина масиву. Потім процес повторюється до співпадіння значень,
або поки не лишиться тільки один елемент. Алгоритм бінарного
пошуку дуже ефективний: якщо для лінійного пошуку в масиві з
1000000 елементів потрібно в середньому 500000 порівнянь, то для
бінарного щонайбільше 20.
Алгоритм бінарного пошуку реалізований у стандартному методі
BinarySearch() класу Array (див. приклад 4.1).

32

You might also like