Припустимо, що у вас є масив даних і необхідність знайти у ньому певний елемент. Очевидним рішенням в даній ситуації, буде поступовий перебір кожного елементу масиву і порівняння його з певним еталоном. Цей алгоритм і називається лінійний пошук. Ось приклад реалізації на С++, з використанням циклу з передумовою:
const unsgined int N = 100 ; //розмір масиву даних
char str[N] ; //наш масив даних (в даному випадку масив символів)
//заповнення масиву...
unsigned int i = 0 ; //ітератор для перебору
char c = 'a' ; //еталон пошуку
while ( (i < N) && (str[i] != с) ) //цикл лінійного пошуку з інваріантою
{ i++ ; } //інкремент ітератора
Найперше, що викликає запитання - це визначена кількість ітерацій, тобто тут можна використати наступний цикл.
const unsgined int N = 100 ; //розмір масиву даних
char str[N] ; //наш масив даних (в даному випадку масив символів)
//заповнення масиву...
char c = 'a' ; //еталон пошуку
for (unsigned int i=0; i<N; ++i)
{
if (str[i]==c)
{ break; }
}
Або ж наш цикл можна записати наступним чином:
//...
for (unsigned int i=0; (i<N) && (str[i]!=c); ++i)
{}
А якщо нам необхідно знайти не один, а усі повторення елементу в масиві? Тобто елемент у масиві може повторятися не один раз. Наприклад, в слові "програмування", букви 'р', 'н' і 'а' зустрічаються по два рази. В такому разі ми можемо інжектувати в наш цикл код обробки знайденого елементу:
const unsgined int N = 100 ; //розмір масиву даних
char str[N] ; //наш масив даних (в даному випадку масив символів)
//заповнення масиву...
char c = 'a' ; //еталон пошуку, наприклад буква 'а'
for (unsigned int i=0; i<N; ++i)
{
if (str[i]==c)
{
//код обробки знайденого елементу
}
}
Якщо Ви бажаєте винести алгоритм у функцію чи метод класу, тоді цей метод нам не підійде. Або ж можна оголосити функцію обробки повторення і передавати вказівник на неї функції з алгоритмом пошуку:
void handle (unsigned int pos) //оголошена функція обробки входження з параметром позиції
{
//код обробки
}
void search_algorithm (char* str, //масив даних у якому відбуватиметься пошук
char c, //шуканий елемент масиву
void (*handler)(unsigned int) //функція обробки входження
)
{
unsigned int N = strlen(str) ; //дізнаємося довжину масиву
for (unsigned int i=0; i<N; ++i) //цикл пошуку
{
if (str[i]==c) //перевірка еталону
{
handler(i) ; //якщо справджується умова - виконати обробку
}
}
}
Найпростіша програма з використанням даного методу може виглядати наступним чином:
#include <iostream> //для виводу на екран
#include <string.h> //функція strlen
using namespace std; //використовуємо простір імен std
void handle (unsigned int pos) //оголошена функція обробки входження з параметром позиції
{
std::cout << "знайдено за позицією: " << pos << endl ;
}
void search_algorithm (char* str, //масив даних у якому відбуватиметься пошук
char c, //шуканий елемент масиву
void (*handler)(unsigned int) //функція обробки входження
)
{
unsigned int N = strlen(str) ; //дізнаємося довжину масиву
for (unsigned int i=0; i<N; ++i) //цикл пошуку
{
if (str[i]==c) //перевірка еталону
{
handler(i) ; //якщо справджується умова - виконати обробку
}
}
}
const char* message = "Beatifule world" ; //створений і заповнений масив
int main (int argc, char** argv) //головна функція програми
{
char* str = (char*) message ;
char c = 'd' ; //еталон, себто шуканий елемент в масиві
search_algorithm (str, c, &handle) ; //передаємо управління функції пошуку
return 0 ; //вихід з програми
}
Після виконання її на комп'ютері ми отримаємо наступне:
Але якщо ви не бажаєте працювати з вказівниками функцій або ж бажаєте створити простішу систему, можна організувати функцію пошуку, яка буде повертати замість одного значення індексу входження елемента, цілий масив індексів входжень. Проста програма з використанням даного методу:
#include//вивід на екран #include //функція strlen using namespace std; //використовуємо простір імен з iostream unsigned int* search_algorithm (char* str, char c) //функція пошуку { if (str==NULL) //перевірямо валідність вказівника { return NULL ; } //повертаємо вказівник NULL - ознака помилки unsigned int N = strlen(str) ; //розмір масиву даних /* Масив індексів входжень у масиві даних. Для безпки розглядається найгірша ситуація з точки зору використання пам'яті: у масиві усі елементи являються ідентичними еталону пошуку. */ unsigned int *indexes = new unsigned int [N] ; //записуємо у пам'ять масиву нулі memset (indexes, 0, sizeof(unsigned int)) ; unsigned int ind_pos = 0 ; /* ітератор масиву індексів */ for (unsigned int i=0; i Результат виконання програми:
Якщо ми не бажаємо використовувати усі ці вказівники на масиви і спростити нашу програму, ми можемо реалізувати функцію з лінійним пошуком, яка повертає лиш індекс входження елементу, а саму функцію помістити в цикл, який буде шукати елемент далі після знайденого входження з наступної після нього позиції. Проста програма з використанням даного методу:
#include//вивід на екран #include //тип string using namespace std; //використовуємо стандартний простір імен //проста функція лінійного пошуку повертає найперший індекс входження //якщо виникла помилка, або елемент не знайдено - повертає //значення менше від нуля int search_algorithm (string str, //наші дані int pos, //позиція, з якої починати пошук char c //еталон пошуку ) { if (str.size()<1) //перевіряємо заповненість масиву { return (-1) ; } //повертаємо значення (-1) - ознака помилки unsigned int N = str.size() ; //розмір масиву даних for (int i=pos; i = 0) //виконуємо пошук { //виводимо повідомлення cout << "елемент '" << c << "' знайдено у позиції " << pos << endl ; } } while ( (pos>=0) && (pos Результат виконання програми:
Час виконання даного алгоритму залежить від місця знаходження шуканого елементу і в найгіршому випадку, алгоритм буде перебирати увесь масив даних.
У бібліотеці STL існує реалізований алгоритм пошуку одного елемента в послідовності даних, у вигляді шаблонної функції. Вона знаходиться в заголовковому файлі algorithm і називається std::find.


