Скачать презентацию Алгоритмы сортировки Параметры алгоритмов сортировки Время Скачать презентацию Алгоритмы сортировки Параметры алгоритмов сортировки Время

Алгоритмы сортировки.pptx

  • Количество слайдов: 48

Алгоритмы сортировки Алгоритмы сортировки

Параметры алгоритмов сортировки • Время сортировки - основной параметр, характеризующий быстродействие алгоритма. • Память Параметры алгоритмов сортировки • Время сортировки - основной параметр, характеризующий быстродействие алгоритма. • Память - ряд алгоритмов требует выделения дополнительной памяти под временное хранение данных. • Устойчивость - устойчивая сортировка не меняет взаимного расположения равных элементов. Такое свойство может быть очень полезным, если они состоят из нескольких полей, а сортировка происходит по одному из них.

 • Естественность поведения - эффективность метода при обработке уже отсортированных, или частично отсортированных • Естественность поведения - эффективность метода при обработке уже отсортированных, или частично отсортированных данных. Алгоритм ведет себя естественно, если учитывает эту характеристику входной последовательности и работает лучше. Виды сортировок: • внутренние сортировки работают с данным в оперативной памяти с произвольным доступом; • внешние сортировки упорядочивают информацию, расположенную на внешних носителях. Это накладывает некоторые дополнительные ограничения на алгоритм: – доступ к носителю осуществляется последовательным образом: в каждый момент времени можно считать или записать только элемент, следующий за текущим – объем данных не позволяет им разместиться в ОЗУ

Устойчивые алгоритмы сортировки • Сортировка пузырьком (англ. Bubble sort ) — сложность алгоритма: O(n Устойчивые алгоритмы сортировки • Сортировка пузырьком (англ. Bubble sort ) — сложность алгоритма: O(n 2); для каждой пары индексов производится обмен, если элементы расположены не по порядку. • Сортировка перемешиванием (Шейкерная, Cocktail sort, bidirectional bubble sort) — Сложность алгоритма: O(n 2) • Сортировка вставками (Insertion sort) — Сложность алгоритма: O(n 2); определяем где текущий элемент должен находиться в упорядоченном списке и вставляем его туда • Блочная сортировка (Корзинная сортировка, Bucket sort) — Сложность алгоритма: O(n); требуется O(k) дополнительной памяти и знание о природе сортируемых данных, выходящее за рамки функций "переставить" и "сравнить". • Сортировка подсчётом (Counting sort) — Сложность алгоритма: O(n+k); требуется O(n+k) дополнительной памяти

Алгоритмы неустойчивой сортировки • Сортировка выбором (Selection sort) — Сложность алгоритма: O(n 2); поиск Алгоритмы неустойчивой сортировки • Сортировка выбором (Selection sort) — Сложность алгоритма: O(n 2); поиск наименьшего или наибольшего элемента и помещения его в начало или конец упорядоченного списка • Сортировка Шелла (Shell sort) — Сложность алгоритма: O(n log 2 n); попытка улучшить сортировку вставками • Пирамидальная сортировка (Сортировка кучи, Heapsort) — Сложность алгоритма: O(n log n); превращаем список в кучу, берём наибольший элемент и добавляем его в конец списка • Быстрая сортировка (Quicksort), в варианте с минимальными затратами памяти — Сложность алгоритма: O(n log n) — среднее время, O(n 2) — худший случай; широко известен как быстрейший из известных для упорядочения больших случайных списков; с разбиением исходного набора данных на две половины так, что любой элемент первой половины упорядочен относительно любого элемента второй половины; затем алгоритм применяется рекурсивно к каждой половине. При использовании O(n) дополнительной памяти, можно сделать сортировку устойчивой.

Временная сложность алгоритма • Временная сложность алгоритма (в худшем случае) — это функция размера Временная сложность алгоритма • Временная сложность алгоритма (в худшем случае) — это функция размера входных и выходных данных, равная максимальному количеству элементарных операций, проделываемых алгоритмом для решения экземпляра задачи указанного размера. • Во многих задачах размер выхода не превосходит или пропорционален размеру входа — в этом случае можно рассматривать временную сложность как функцию размера только входных данных.

O-нотация • Для оценки временной сложности алгоритмов применяется O-нотация, которая позволяет осуществить оценку порядка O-нотация • Для оценки временной сложности алгоритмов применяется O-нотация, которая позволяет осуществить оценку порядка роста времени работы алгоритма в зависимости от объема входных данных. • Запись вида O(N 2) говорит о времени выполнения алгоритма, пропорциональном квадрату количества входных данных • Обозначение пошло от немецкого слова «Ordnung» (порядок).

O-нотация • Обычно говорят о времени выполнения алгоритма в худшем, среднем и лучшем случаях. O-нотация • Обычно говорят о времени выполнения алгоритма в худшем, среднем и лучшем случаях. В лучшем случае В среднем В худшем Пузырьковая O(N 2) Выбора O(N 2) Вставками O(N) O(N 2) Быстрая сортировка O(N log 2 N) O(N 2)

3 случая сложности алгоритма 3 случая сложности алгоритма

Асимптотическое представление Асимптотическое представление

Порядок сложности алгоритма • Если в алгоритме переменная i меняется в цикле от 1 Порядок сложности алгоритма • Если в алгоритме переменная i меняется в цикле от 1 до N и при каждом изменении i переменная j тоже меняется от 1 до N, то общее количество итераций внутреннего цикла равно N*N. Это определяет сложность алгоритма O(N 2). for ( i = 0; i < N; i ++ ) for ( j = 0; j < N; j ++ ) sum += A[i]; При увеличении массива в 10 раз время увеличивается в 100 раз

Порядок сложности алгоритма • Оценивая порядок сложности алгоритма, необходимо использовать только ту часть, которая Порядок сложности алгоритма • Оценивая порядок сложности алгоритма, необходимо использовать только ту часть, которая возрастает быстрее всего. Предположим, что рабочий цикл описывается выражением N 3+N. В таком случае его сложность будет равна O(N 3). • Рассмотрение быстро растущей части функции позволяет оценить поведение алгоритма при увеличении N. Например, при N=100 разница между N 3+N и N 3 равна всего лишь 100, что составляет 0. 01%.

Скорость роста для разных функций в микросекундах Для n=1 048 476 O(Nlog. N)=20 микрсек, Скорость роста для разных функций в микросекундах Для n=1 048 476 O(Nlog. N)=20 микрсек, а для O(N 2)=12 дней

Время выполнения алгоритмов • Компьютер, осуществляющий миллион операций в секунду, будет выполнять некоторые медленные Время выполнения алгоритмов • Компьютер, осуществляющий миллион операций в секунду, будет выполнять некоторые медленные алгоритмы

Графики функций O(5 N) O(N 2) O(N Log(N)) O(N 1/2) O(Log(N)) O(C) Графики функций O(5 N) O(N 2) O(N Log(N)) O(N 1/2) O(Log(N)) O(C)

Время сортировки в секундах для Pentium 120 Время сортировки в секундах для Pentium 120

Как измерить время выполнения программы? • Для того, чтобы найти время работы программы, нужно Как измерить время выполнения программы? • Для того, чтобы найти время работы программы, нужно воспользоваться функцией clock(). • Прототип функции clock() находится в заголовочном файле , который нужно подключить. • Функция clock() возвращает значение времени в миллисекундах (1 с = 1000 млс). Причём отсчёт времени начинается с момента запуска программы. Если надо измерить работу всей программы, то в конце программы, перед оператором return 0, нужно запустить функцию clock(), которая покажет рабочее время.

Как измерить время выполнения программы? // Как найти время работы фрагмента кода? // заголовочный Как измерить время выполнения программы? // Как найти время работы фрагмента кода? // заголовочный файл с прототипом функции clock() #include // . . . unsigned int start_time = clock(); // начальное время // здесь должен быть фрагмент кода, время выполнения которого нужно измерить • • unsigned int end_time = clock(); // конечное время • unsigned int search_time = end_time - start_time; // искомое время • •

clock() • Разработаем программу, в которой с помощью функции clock() вычислим время работы программы. clock() • Разработаем программу, в которой с помощью функции clock() вычислим время работы программы. Программа ищет минимальное значение в массиве размером в 200000 элементов. Размер массива специально выбран большим, для того. чтобы было заметно, как работает программа. Так как числа генерируются случайно, то при каждом запуске получается новый случай, и время может не совпадать. К тому же время выполнения программы зависит от того, насколько загружен компьютер и от того, какая у компьютера вычислительная мощность. На разных машинах поразному будет затрачиваться время на выполнение программы, на более мощных компьютерах затрачиваемое время будет меньше и наоборот.

Время работы программы // runtime. cpp: определяет точку входа для консольного приложения. // Как Время работы программы // runtime. cpp: определяет точку входа для консольного приложения. // Как найти время работы программы? #include "stdafx. h" #include #include using namespace std; int main(int argc, char* argv[]) { srand(time(0)); const int array_size = 200000; // размер одномерного массива int array 1[array_size]; // объявление одномерного массива for (int counter = 0; counter < array_size; counter++)

Время работы программы { array 1[counter] = rand() % 50 - rand() % 50; Время работы программы { array 1[counter] = rand() % 50 - rand() % 50; // заполняем массив случайными значениями в диапазоне от -49 до 49 включительно cout << array 1[counter] << " "; // печать элементов одномерного массива array 1 } int min = array 1[0]; // переменная для хранения минимального значения for (int counter = 1; counter < array_size; counter++) { if ( min > array 1[counter] ) // поиск минимального значения в одномерном массиве min = array 1[counter]; } cout << "nmin = " << min << endl; cout << "runtime = " << clock()/1000. 0 << endl; // время работы программы system("pause"); return 0; }

Результат Результат

Сложность алгоритма • Кроме временной сложности говорят также о пространственной и интеллектуальной сложности алгоритма. Сложность алгоритма • Кроме временной сложности говорят также о пространственной и интеллектуальной сложности алгоритма. • Пространственная сложность – это объем памяти, необходимый для выполнения программы • При анализе интеллектуальной сложности алгоритма исследуется понятность алгоритмов и сложность их разработки

Сравнение времени сортировок Сравнение времени сортировок

Сортировка перемешиванием (шейкерсортировка) — разновидность пузырьковой сортировки. Отличается тем, что просмотры элементов выполняются один Сортировка перемешиванием (шейкерсортировка) — разновидность пузырьковой сортировки. Отличается тем, что просмотры элементов выполняются один за другим в противоположных направлениях, при этом большие элементы стремятся к концу массива, а маленькие — к началу. • Лучший случай для этой сортировки — отстортированный массив (О(n)), худший — отсортированный в обратном порядке (O(n²)).

Сортировка перемешиванием Хотя легкий пузырек снизу поднимется наверх за один проход, тяжелые пузырьки опускаются Сортировка перемешиванием Хотя легкий пузырек снизу поднимется наверх за один проход, тяжелые пузырьки опускаются с минимальной скоростью: один шаг за итерацию. Так что массив 2 3 4 5 6 1 будет отсортирован за 1 проход, а сортировка последовательности 6 1 2 3 4 5 потребует 5 проходов. Чтобы избежать подобного эффекта, можно менять направление следующих один за другим проходов.

 • • • • template<class T> void shaker. Sort(T a[], long size) { • • • • template void shaker. Sort(T a[], long size) { long j, k = size-1; long lb=1, ub = size-1; // границы неотсортированной части массива T x; do { // проход снизу вверх for( j=ub; j>0; j-- ) { if ( a[j-1] > a[j] ) { x=a[j-1]; a[j-1]=a[j]; a[j]=x; k=j; } } lb = k+1; // проход сверху вниз for (j=1; j<=ub; j++) { if ( a[j-1] > a[j] ) { x=a[j-1]; a[j-1]=a[j]; a[j]=x; k=j; } } ub = k-1; } while ( lb < ub ); }

Сортировка Шелла • Сортировка Шелла (англ. Shell sort) — алгоритм сортировки, являющийся усовершенствованным вариантом Сортировка Шелла • Сортировка Шелла (англ. Shell sort) — алгоритм сортировки, являющийся усовершенствованным вариантом сортировки вставками. Идея метода Шелла состоит в сравнении элементов, стоящих не только рядом, но и на определённом расстоянии друг от друга. Иными словами — это сортировка вставками с предварительными «грубыми» проходами.

Сортировка Шелла • Рассмотрим следующий алгоритм сортировки массива a[0]. . a[15]. • 1. Вначале Сортировка Шелла • Рассмотрим следующий алгоритм сортировки массива a[0]. . a[15]. • 1. Вначале сортируем простыми вставками каждые 8 групп из 2 -х элементов (a[0], a[8[), (a[1], a[9]), . . . , (a[7], a[15]). • 2. Потом сортируем каждую из четырех групп по 4 элемента (a[0], a[4], a[8], a[12]), . . . , (a[3], a[7], a[11], a[15]).

Сортировка Шелла • В нулевой группе будут элементы 4, 12, 13, 18, в первой Сортировка Шелла • В нулевой группе будут элементы 4, 12, 13, 18, в первой - 3, 5, 8, 9 и т. п. • 3. Далее сортируем 2 группы по 8 элементов, начиная с (a[0], a[2], a[4], a[6], a[8], a[10], a[12], a[14]) • 4. В конце сортируем вставками все 16 элементов.

Сортировка Шелла • Очевидно, лишь последняя сортировка необходима, чтобы расположить все элементы по своим Сортировка Шелла • Очевидно, лишь последняя сортировка необходима, чтобы расположить все элементы по своим местам. Так зачем нужны остальные ? • Hа самом деле они продвигают элементы максимально близко к соответствующим позициям, так что в последней стадии число перемещений будет весьма невелико. Последовательность и так почти отсортирована. Ускорение подтверждено многочисленными исследованиями и на практике оказывается довольно существенным.

Сортировка Шелла • Сортировка Шелла была названа в честь её изобретателя — Дональда Шелла, Сортировка Шелла • Сортировка Шелла была названа в честь её изобретателя — Дональда Шелла, который опубликовал этот алгоритм в 1959 году. В некоторых старых пособиях этот алгоритм назывался Сортировка Шелл-Мецнер, в честь Марлен Мецнер-Нортон. Однако, впоследствии, сама Мецнер опровергла это: «Я не имею ничего общего с этой сортировкой, и моё имя никогда не должно связываться с ней»

Поиск элемента массива Поиск элемента массива

Двоичный поиск • • • • { int L = 0, R = N-1, Двоичный поиск • • • • { int L = 0, R = N-1, m, A[N], flag = 0; //здесь надо ввести массив и отсортировать его printf( «Введите искомый элемент"); scanf( "%d", &x ); while ( L <= R ) { m = (L + R) / 2; if ( A[m] == x ) { flag = 1; break; } if ( x < A[m] ) R = m - 1; // сужаем границы области поиска else L = m + 1; }

Сортировка массива записей по ключу #include <stdio. h> const int N = 20; struct Сортировка массива записей по ключу #include const int N = 20; struct Book { char author[40]; char title[80]; int year; int pages; }; typedef Book *PBook; main() { //Здесь нужно заполнить структуры Book B[N]; PBook p[N];

Сортировка массива записей по ключу • • for ( i = 0; i < Сортировка массива записей по ключу • • for ( i = 0; i < N; i ++ ) p[i] = &B[i]; Sort. Year ( p, N ); for ( i = 0; i < N; i ++ ) printf("%d: %sn", p[i]->year, p[i]->title); }

Сортировка массива записей по ключу • • • • void Sort. Year ( PBook Сортировка массива записей по ключу • • • • void Sort. Year ( PBook p[], int n ) { int i, j; PBook temp; for ( i = 0; i < n-1; i ++ ) for ( j = n-2; j >= i; j -- ) if ( p[j+1]->year < p[j]->year ) { temp = p[j]; p[j] = p[j+1]; p[j+1] = temp; } }

Считываем данные из файла в массив структур • • • • Book *p; FILE Считываем данные из файла в массив структур • • • • Book *p; FILE *fp; p = new Book; printf( «Автор: "); gets ( p->author ); printf( «Введите название"); gets ( p->title ); printf( «Введите год издания, количествостраниц"); scanf("%d%d", &p->year, &p->pages); fp = fopen("books. txt", "a"); fprintf("%sn%d %dn", p->author, p->title, p->year, p->pages); fclose ( fp ); delete p;

Рекурсия • Это определение объекта через самого себя Рекурсия • Это определение объекта через самого себя

Рекурсивные процедуры и функции Рекурсивными называют процедуры и функции, вызывающие сами себя int Factorial Рекурсивные процедуры и функции Рекурсивными называют процедуры и функции, вызывающие сами себя int Factorial ( int n ) { if ( n <= 0 ) return 1; else return n*Factorial(n-1); }

Факториал void Factorial ( int n, int &fact ) { if ( n == Факториал void Factorial ( int n, int &fact ) { if ( n == 0 ) fact = 1; else { Factorial(n-1, fact); (n-1)! fact *= n; // n! = n*(n-1)! } }

Косвенная рекурсия Косвенная рекурсия

Вычисление факториала без рекурсии • • int Factorial ( int n ) { int Вычисление факториала без рекурсии • • int Factorial ( int n ) { int i, fact = 1; for ( i = 2; i <= n; i ++ ) fact *= i; return fact; }

Quick. Sort Метод основан на подходе Quick. Sort Метод основан на подходе "разделяй-и-властвуй". Общая схема такова: 1. из массива выбирается некоторый опорный элемент a[i], 2. запускается процедура разделения массива, которая перемещает все ключи, меньшие, либо равные a[i], влево от него, а все ключи, большие, либо равные a[i] - вправо, 3. теперь массив состоит из двух подмножеств, причем левое меньше, либо равно правого, 4. 5. для обоих подмассивов: если в подмассиве более двух элементов, рекурсивно запускаем для него ту же процедуру. В конце получится полностью отсортированная последовательность.

Quick. Sort Quick. Sort

Quick. Sort Quick. Sort

void Quick. Sort ( int A[], int from, int to ) { int x, void Quick. Sort ( int A[], int from, int to ) { int x, i, j, temp; if ( from >= to ) return; i = from; j = to; x = A[(from+to)/2]; while ( i <= j ) { while ( A[i] < x ) i ++; while ( A[j] > x ) j --; if ( i <= j ) { temp = A[i]; A[i] = A[j]; A[j] = temp; i ++; j --; } } Quick. Sort ( A, from, j ); Quick. Sort ( A, i, to ); }