Базовые алгоритмы обработки данных
Эти алгоритмы являются результатом исследований и разработок, проводившихся на протяжении десятков лет. Они продолжают играть важную роль в решении реальных задач. К базовым алгоритмам структурного программирования можно отнести следующие.
1) Алгоритмы поиска, предназначенные для поиска конкретных элементов в больших коллекциях (массивах). К ним относятся основные и расширенные методы с использованием деревьев и преобразований цифровых ключей, в том числе деревья цифрового поиска, сбалансированные деревья, а также методы для работы с очень большими файлами.
2) Алгоритмы обработки строк, которые включают в себя ряд методов обработки длинных последовательностей символов. Наиболее распространенными являются задачи поиска подстроки в строке.
3) Алгоритмы сортировки, предназначенные для упорядочения массивов и файлов. К ним относятся задачи упорядочения слов (списков, строк) по алфавиту, любых сложных типов по значениям ключей и т.д.
4) Алгоритмы на деревьях, которые используются при решении ряда важных задач. Одной из основных задач является поиск и сортировка на двоичных и В - деревьях. Эти структуры позволяют существенно упростить решение таких задач.
АЛГОРИТМЫ ПОИСКА
Процедуры поиска широко используются в информационно-справочных системах (базах и банках данных), при разработке синтаксических анализаторов и компиляторов (поиск служебных слов, команд и т.п. в таблицах). В простейшем случае считается, что исходными данными для этой процедуры являются массив (чисел, слов и т.д.) и некоторое значение, которое принято называть аргументом поиска.
В процессе поиска всегда используется таблица (массив) эталонов, которые могут иметь сложную структуру, но характеризуются неповторяющимися значениями некоторых ключей. Искомый элемент сравнивается с каждым из этих ключей. Если они совпадают, то элемент найден. Результат поиска может быть булевский (элемент есть в таблице или нет) или числовой (номер ключа в таблице).
Наиболее сложным является случай, когда аргумента поиска нет в таблице. Суждение об этом можно сделать только по окончании просмотра всего массива.
Поскольку в процессе поиска участвуют только ключи, а информационная часть элементов не важна, в дальнейшем будем рассматривать только алгоритмы поиска ключей, значения которых обычно являются целыми числами.
В общем случае для выполнения этой операции могут использоваться различные условия. В зависимости от способа их задания и организации поиска различают большое количество видов таких операций. Наибольшее распространение получили следующие виды поиска по простому условию:
a) совпадению,
b) близости снизу
c) близости сверху.
Первый вид предполагает нахождение элемента с заданным значением ключа К. Если такого ключа нет, то операция закончилась безуспешно.
При поиске по близости операция всегда заканчивается успешно. Если он выполняется снизу, то результатом будет элемент, ключ которого является ближайшим меньшим искомого. При поиске по близости сверху результат представляет собой элемент с ключом, ближайшим большим искомого.
Мы рассмотрим только алгоритмы поиска по совпадению, а по близости наиболее просто реализуются с помощью двоичных деревьев, которые будут изучаться позднее.
Общий алгоритм поиска по совпадению ключа можно представить так.
1. Ввести исходный массив (ключей).
2. Повторять
ввести аргумент поиска и вывести результат
пока не надоест.
3. Закончить.
Предположим в дальнейшем, что для окончания работы с программой (когда искать надоело) необходимо ввести отрицательное число (несуществующий ключ).
Наиболее распространенными являются три алгоритма поиска:
1) Линейный;
2) Дихотомический:
3) Интерполирующий.
1.1. Алгоритм линейного поиска
В соответствии с этим алгоритмом эталонный массив просматривается последовательно от первого до последнего элемента. Наиболее сложным, как уже отмечалось, является случай, когда ключа нет в таблице (не найден).
Уточненный алгоритм будет таким.
1. Ввести исходный массив (ключей).
2. Выполнять
2. 1. Ввести аргумент поиска (целое число);
2. 2. Если аргумент поиска больше или равен нулю,
2.2.1. Результат (номер в массиве, num) = - 1 (не найден, такого номера нет);
2.2.2. Для индекса массива (i) от 0 до Длина.массива
Если аргумент поиска = ключ[i],
номер в массиве (num) = i;
2.2.3. Если номер num = - 1,
вывести: «Такого ключа в массиве нет»,
Иначе
вывести: «Ключ найден под номером num».
пока будет аргумент поиска больше или равен нулю.
3. Закончить.
Обозначим массив ключей key, а аргумент поиска - arg. Тогда соответствующий фрагмент программы линейного поиска будет иметь вид, приведенный ниже.
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n;
System.out.print("Введите количество элементов массива => ");
n=sc.nextInt();
System.out.println("\tВведите элементы массива ");
int key[]=new int[n];
for (int i = 0; i < key.length;i++)
key[i]=sc.nextInt();
System.out.println("\n Поиск ключа");
do{
int arg,num;
System.out.println("\n Введите аргумент поиска – искомый ключ");
arg=sc.nextInt();
if (arg>=0){
num=-1;
for (int i = 0; i < key.length; i++)
if (arg==key [i])
num=i;
if (num ==-1)
System.out.println("Такого ключа нет");
else
System.out.println("Ключ найден под номером “+ num);
} while (arg>=0);
}
Основной недостаток алгоритма линейного поиска – большое время. При использовании оператора For для поиска ВСЕГДА выполняется ровно n операций сравнения, не зависимо от того, найден ключ или нет. Поэтому программа, обнаружив аргумент в начале массива, продолжает его просмотр до конца, т.е. выполняет бесполезную работу. Время поиска может быть существенно сокращено, если обеспечить его прекращение, когда ключ найден. При равномерном распределении элементов в таблице эталонов (ключей) среднее время поиска может стать пропорциональным величине n / 2.
Этого можно достичь, изменив пункт 2 в рассмотренном выше алгоритме следующим образом.