- •Понятие алгоритма и его свойства
- •Оценка порядка (временная оценка)
- •Общий случай определения сложности
- •Виды функций оценки сложности алгоритмов
- •Экспериментальный метод оценки трудоемкости (сложности) алгоритма
- •Оценка пространственной (емкостной) сложности
- •Классификация структур данных
- •Линейные структуры данных
- •Иерархические структуры данных
- •Сетевые структуры данных
- •Табличные структуры данных
- •Сложность типовых операций при работе с линейными структурами данных
- •Представление данных в памяти эвм
- •Базовые алгоритмы обработки данных
- •1. Алгоритмы поиска
- •1.1. Алгоритм линейного поиска
- •1.2. Алгоритм дихотомического поиска
- •3. Алгоритмы сортировки
- •3.1. Основные определения и классы алгоритмов
- •Классификация алгоритмов сортировки
- •Наиболее распространенные простые алгоритмы внутренней сортировки (массивов)
- •Сортировка вставками
- •Сортировка выбором
- •3.2.3. Сортировка обменом (Пузырьковая сортировка)
- •3.2.4.Сортировка Шейкером
- •Эффективные методы внутренней сортировки
- •Сортировка Шелла
- •3.3.2. Быстрая сортировка
- •Алгоритмы внешней сортировки
- •Простая сортировка слиянием
- •Сортировка с помощью естественных слияний
- •3.4.3. Сортировка Боуза - Нельсона
Базовые алгоритмы обработки данных
Эти алгоритмы являются результатом исследований и разработок, проводившихся на протяжении десятков лет. Они продолжают играть важную роль в решении реальных задач. К базовым алгоритмам структурного программирования можно отнести следующие.
Алгоритмы поиска, предназначенные для поиска конкретных элементов в больших коллекциях (массивах). К ним относятся основные и расширенные методы с использованием деревьев и преобразований цифровых ключей, в том числе деревья цифрового поиска, сбалансированные деревья, а также методы для работы с очень большими файлами.
Алгоритмы обработки строк, которые включают в себя ряд методов обработки длинных последовательностей символов. Наиболее распространенными являются задачи поиска подстроки в строке.
Алгоритмы сортировки, предназначенные для упорядочения массивов и файлов. К ним относятся задачи упорядочения слов (списков, строк) по алфавиту, любых сложных типов по значениям ключей и т.д.
Алгоритмы на деревьях, которые используются при решении ряда важных задач. Одной из основных задач является поиск и сортировка на двоичных и В - деревьях. Эти структуры позволяют существенно упростить решение таких задач.
1. Алгоритмы поиска
Процедуры поиска широко используются в информационно-справочных системах (базах и банках данных), при разработке синтаксических анализаторов и компиляторов (поиск служебных слов, команд и т.п. в таблицах). В простейшем случае считается, что исходными данными для этой процедуры являются массив (чисел, слов и т.д.) и некоторое значение, которое принято называть аргументом поиска.
В процессе поиска всегда используется таблица (массив) эталонов, которые могут иметь сложную структуру, но характеризуются неповторяющимися значениями некоторых ключей. Искомый элемент сравнивается с каждым из этих ключей. Если они совпадают, то элемент найден. Результат поиска может быть булевский (элемент есть в таблице или нет) или числовой (номер ключа в таблице).
Наиболее сложным является случай, когда аргумента поиска нет в таблице. Суждение об этом можно сделать только по окончании просмотра всего массива.
Поскольку в процессе поиска участвуют только ключи, а информационная часть элементов не важна, в дальнейшем будем рассматривать только алгоритмы поиска ключей, значения которых обычно являются целыми числами.
Общий алгоритм поиска ключа можно представить так.
1. Ввести исходный массив (ключей).
2. Повторять
ввести аргумент поиска и вывести результат
пока не надоест.
3. Закончить.
Предположим в дальнейшем, что для окончания работы с программой (когда искать надоело) необходимо ввести отрицательное число (несуществующий ключ).
Наиболее распространенными являются три алгоритма поиска:
Линейный;
Дихотомический:
Интерполирующий.
1.1. Алгоритм линейного поиска
В соответствии с этим алгоритмом эталонный массив просматривается последовательно от первого до последнего элемента. Наиболее сложным, как уже отмечалось, является случай, когда ключа нет в таблице (не найден).
Уточненный алгоритм будет таким.
1. Ввести исходный массив (ключей).
2. Выполнять
2. 1. Ввести аргумент поиска (целое число);
2. 2. Если аргумент поиска больше или равен нулю,
Результат (номер в массиве, num) = - 1 (не найден, такого номера нет);
Для индекса массива (i) от 0 до Длина.массива
Если аргумент поиска = ключ[i],
номер в массиве (num) = i;
Если номер 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 = 1; 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 в рассмотренном выше алгоритме следующим образом.
Ускорение линейного поиска
2. Выполнять
2. 1. Ввести аргумент поиска (целое число);
2. 2. Если аргумент поиска больше или равен нулю,
Результат (num) = - 1 (не найден);
Начальный индекс, i=0;
2.2.3. Пока (num=-1) и (i<=n – Длины.массива)
Если аргумент поиска = ключ[i],
номер в массиве (num) = i;
i=i + 1
Если номер num = - 1,
вывести: «Такого ключа в массиве нет»,
Иначе
вывести: «Ключ num найден».
пока будет аргумент поиска больше или равен нулю.
Соответствующий фрагмент программы, в котором используются те же обозначения, что и в предыдущем, будет иметь вид, приведенный ниже.
// Ускорение линейного поиска }
do{
int arg,num,i;
System.out.println("\n Введите аргумент поиска – искомый ключ");
arg=sc.nextInt();
if (arg>=0){
num=-1;
int i=0;
while ((num=-1) && (i < key.length)) {
if (arg==key [i])
num=i;
i++;
}
if (num =-1)
System.out.println("Такого ключа нет");
else
System.out.println("Ключ"+num+” найден“);
} while (arg>=0);
}
Трудоемкость (временная сложность) алгоритма линейного поиска определяется числом операций сравнения, выполняемых при просмотре таблицы эталонов. В лучшем случае количество таких операций равно 1, в худшем – n, а в среднем, если возможные значения ключей равновероятны, - n / 2. Таким образом, асимптотическая оценка О(n) = n.
