Uploaded by Евгений Чуриков

Laba 1

advertisement
Липецкий государственный технический университет
Лабораторная работа
по дисциплине «Структуры и алгоритмы обработки данных»
на тему: «Реализация и изучение алгоритмов внутренней сортировки»
Студент
___________
Чуриков Е.В.
подпись, дата
фамилия, инициалы
Группа З-УТ-20-1
Руководитель
к.т.н. доцент
___________
Батищев Р.В.
ученая степень, ученое звание
подпись, дата
фамилия, инициалы
Липецк 2023г.
Сортировка
массива -
это
процесс
распределения
всех
элементов массива в определенном порядке. Очень часто это бывает
полезным. Например, в вашем почтовом ящике электронные письма
отображаются в зависимости от времени получения; новые письма считаются
более релевантными, чем те, которые вы получили полчаса, час, два или день
назад; когда вы переходите в свой список контактов, имена обычно находятся
в алфавитном порядке, потому что так легче что-то найти. Все эти случаи
включают в себя сортировку данных перед их фактическим выводом.
Как работает сортировка?
Сортировка данных может сделать поиск внутри массива более
эффективным не только для людей, но и для компьютеров. Например,
рассмотрим случай, когда нам нужно узнать, отображается ли определенное
имя в списке имен. Чтобы это узнать, нужно проверить каждый элемент
массива на соответствие нашему значению. Поиск в массиве с множеством
элементов может оказаться слишком неэффективным (затратным).
Однако, предположим, что наш массив с именами отсортирован в
алфавитном порядке. Тогда наш поиск начинается с первой буквы нашего
значения и заканчивается буквой, которая идет следующей по алфавиту. В
таком случае, если мы дошли до этой буквы и не нашли имя, то точно знаем,
что оно не находится в остальной части массива, так как в алфавитном порядке
нашу букву мы уже прошли!
Не секрет, что есть алгоритмы поиска внутри отсортированных
массивов и получше. Применяя простой алгоритм, мы можем искать
определенный элемент в отсортированном массиве, содержащем 1 000 000
элементов, используя всего лишь 20 сравнений! Недостатком, конечно же,
является то, что сортировка массива с таким огромным количеством
элементов — дело сравнительно затратное, и оно точно не выполняется ради
одного поискового запроса.
В некоторых случаях сортировка массива делает поиск ненужным.
Например, мы ищем наилучший результат прохождения теста среди
студентов. Если массив не отсортирован, то нам придется просмотреть
каждый элемент массива, чтобы найти наивысшую оценку. Если же массив
отсортирован, то наивысшая оценка будет находиться либо на первой
позиции, либо на последней (в зависимости от метода сортировки массива: в
порядке возрастания или в порядке убывания), поэтому нам не нужно искать
вообще!
Сортировка обычно выполняется путем повторного сравнения пар
элементов массива и замены значений, если они отвечают заданным
критериям. Порядок, в котором эти элементы сравниваются, зависит от того,
какой алгоритм сортировки используется. Критерии определяют, как будет
сортироваться массив (например, в порядке возрастания или в порядке
убывания).
Чтобы
поменять
два
элемента
местами,
мы
можем
использовать функцию std::swap() из Стандартной библиотеки C++, которая
определена в заголовочном файле algorithm. В C++11 функция std::swap()
была перенесена в заголовочный файл utility:
Для сортировки
массива
методом
выбора
от
наименьшего
до
наибольшего элемента выполняются следующие шаги:
1. Начиная с элемента под индексом 0, ищем в массиве наименьшее
значение.
2. Найденное значение меняем местами с нулевым элементом.
3. Повторяем шаги №1 и №2 уже для следующего индекса в массиве
(отсортированный элемент больше не трогаем).
Другими словами, мы ищем наименьший элемент в массиве и
перемещаем его на первое место. Затем ищем второй наименьший элемент и
перемещаем его уже на второе место после первого наименьшего элемента.
Этот процесс продолжается до тех пор, пока в массиве не закончатся
неотсортированные элементы.
Вот пример работы этого алгоритма в массиве с 5-ю элементами:
{ 30, 50, 20, 10, 40 }
Сначала ищем наименьший элемент, начиная с индекса 0:
{ 30, 50, 20, 10, 40 }
Затем меняем местами наименьший элемент с элементом под индексом
0:
{ 10, 50, 20, 30, 40 }
Теперь, когда первый элемент массива отсортирован, мы его
игнорируем. Ищем следующий наименьший элемент, но уже начиная с
индекса 1:
{ 10, 50, 20, 30, 40 }
И меняем его местами с элементом под индексом 1:
{ 10, 20, 50, 30, 40 }
Теперь мы игнорируем первые два элемента. Ищем следующий
наименьший элемент, начиная с индекса 2:
{ 10, 20, 50, 30, 40 }
И меняем его местами с элементом под индексом 2:
{ 10, 20, 30, 50, 40 }
Ищем следующий наименьший элемент, начиная с индекса 3:
{ 10, 20, 30, 50, 40 }
И меняем его местами с элементом под индексом 3:
{ 10, 20, 30, 40, 50 }
Ищем следующий наименьший элемент, начиная с индекса 4:
{ 10, 20, 30, 40, 50 }
И меняем его местами с элементом под индексом 4 (выполняется
самозамена, т.е. ничего не делаем):
{ 10, 20, 30, 40 50 }
Готово!
{ 10, 20, 30, 40, 50 }
Обратите внимание, последнее сравнение всегда будет одиночным (т.е.
самозамена), что является лишней операцией, поэтому, фактически, мы можем
остановить выполнение сортировки перед последним элементом массива.
Сортировка массивов методом выбора в C++
Вот как этот алгоритм реализован в C++:
#include <iostream>
#include <algorithm> // для std::swap. В C++11 используйте заголовок <utility>
int main()
{
const int length = 5;
int array[length] = { 30, 50, 20, 10, 40 };
// Перебираем каждый элемент массива (кроме последнего, он уже будет отсортирован к
тому времени, когда мы до него доберемся)
for (int startIndex = 0; startIndex < length - 1; ++startIndex)
{
// В переменной smallestIndex хранится индекс наименьшего значения, которое мы
нашли в этой итерации.
// Начинаем с того, что наименьший элемент в этой итерации - это первый элемент
(индекс 0)
int smallestIndex = startIndex;
// Затем ищем элемент поменьше в остальной части массива
for (int currentIndex = startIndex + 1; currentIndex < length; ++currentIndex)
{
// Если мы нашли элемент, который меньше нашего наименьшего элемента,
if (array[currentIndex] < array[smallestIndex])
// то запоминаем его smallestIndex = currentIndex;
}
// smallestIndex теперь наименьший элемент.
// Меняем местами наше начальное наименьшее число с тем, которое мы обнаружили
std::swap(array[startIndex], array[smallestIndex]);
}
// Теперь, когда весь массив отсортирован - выводим его на экран
for (int index = 0; index < length; ++index)
std::cout << array[index] << ' ';
return 0;
}
Для того, что бы программа выполняла сортировку в порядке убывания
требуется изменить if (array[currentIndex] < array[smallestIndex]) на if
(array[currentIndex]
>
array[smallestIndex]).
А
так
же
переименовать
smallestIndex на largestIndex.
Быстрая сортировка.
Включает в себя два основных этапа:
1. Разбиение массива относительно опорного элемента;
2. Рекурсивная сортировка каждой части массива.
Разбиение массива.
Еще раз об опорном элементе. Его выбор не влияет на результат, и
поэтому может пасть на произвольный элемент. Тем не менее, как было
замечено выше, наибольшая эффективность алгоритма достигается при
выборе опорного элемента, делящего последовательность на равные или
примерно равные части. Но, как правило, из-за нехватки информации не
представляется возможности наверняка определить такой элемент, поэтому
зачастую приходиться выбирать опорный элемент случайным образом.
Рекурсивное доупорядочивание
Если в какой-то из получившихся в результате разбиения массива частей
находиться больше одного элемента, то следует произвести рекурсивное
упорядочивание этой части, то есть выполнить над ней операцию разбиения,
описанную выше. Для проверки условия «количество элементов > 1», нужно
действовать примерно по следующей схеме:
Имеется массив Mas[L..R], где L и R – индексы крайних элементов этого
массива. По окончанию разбиения, указатели first и last оказались примерно в
середине последовательности, тем самым образуя два отрезка: левый
от L до last и правый от first до R. Выполнить рекурсивное упорядочивание
левой части нужно в том случае, если выполняется условие L<last. Для правой
части условие аналогично: first<R.
Реализации алгоритма быстрой сортировки:
Код программы на C++:
#include "stdafx.h"
#include <iostream>
#include <ctime>
using namespace std;
const int n=7;
int first, last;
//функция сортировки
void quicksort(int *mas, int first, int last)
{
int mid, count;
int f=first, l=last;
mid=mas[(f+l) / 2]; //вычисление опорного элемента
do
{
while (mas[f]<mid) f++;
while (mas[l]>mid) l--;
if (f<=l) //перестановка элементов
{
count=mas[f];
mas[f]=mas[l];
mas[l]=count;
f++;
l--;
}
}
while (f<l);
if (first<l) quicksort(mas, first, l);
if (f<last) quicksort(mas, f, last);
}
//главная функция
void main()
{
setlocale(LC_ALL,"Rus");
int *A=new int[n];
srand(time(NULL));
cout<<"Исходный массив: ";
for (int i=0; i<n; i++)
{
A[i]=rand()%10;
cout<<A[i]<<" ";
}
first=0; last=n-1;
quicksort(A, first, last);
cout<<endl<<"Результирующий массив: ";
for (int i=0; i<n; i++) cout<<A[i]<<" ";
delete []A;
system("pause>>void");
}
Стоит
отметить,
что быстрая
сортировка может
оказаться
малоэффективной на массивах, состоящих из небольшого числа элементов,
поэтому при работе с ними разумнее отказаться от данного метода. В целом
алгоритм
неустойчив,
а
также
использование
рекурсии
в
неверно
составленном коде может привести к переполнению стека. Но, несмотря на эти
и некоторые другие минусы, быстрая сортировка все же является одним из
самых эффективных и часто используемых методов.
Download