920 likes | 1.15k Views
Алгоритмы сортировки. Задача сортировки. Для заданной последовательности a 1 , a 2 , … , a n найти перестановку её элементов в таком порядке a ' 1 ,a ' 2 , … ,a ' n , что при заданной функции f справедливо отношение: f(a ' 1 ) f(a ' 2 ) … f(a ' n )
E N D
Задача сортировки • Для заданной последовательности a1, a2, …, an найти перестановку её элементов в таком порядке a'1,a'2, … ,a'n, что при заданной функции f справедливо отношение: f(a'1) f(a'2) … f(a'n) • Функция упорядочивания f(x) не вычисляется, а содержится в каждом элементе в виде явной компоненты. Её значение называют ключом элемента.
Типы сортировки • Внутренний • все элементы находятся в памяти машины • Внешний • массив данных настолько велик, что в ОЗУ машины может храниться только лишь часть данных • Устойчивая сортировка • сохраняет относительный порядок размещения элементов в массиве, содержащем дублированные ключи
Основные характеристики • Время – характеристика вызывающая наибольший интерес • Дополнительный объем оперативной памяти, используемый алгоритмом • In place (без привлечения дополнительной памяти; • С использованием места для размещения указателей или индексов массивов; • Требующие память для размещения еще одной копии массива.
Управляющая и вспомогательные программы #include <iostream.h> #include <stdlib.h> template <class Item> void exch(Item& A, Item& B){Item t=A; A=B; B=t;} template <class Item> int compexch(Item& A, Item& B) {if(B<A) { exch(A,B); return 1; } else return 0; } void main(int argc, char* argv[]) { int i, N=atoi(argv[1]); int* a=new int[N]; for(i=0;i<N;i++) a[i]=random(1000); sort(a,0,N-1); for(i=0;i<N;i++) cout << a[i] << ' '; cout << endl; }
Сортировка вставками template <class Item>void sort(Item a[], int l, int r){ for(int i=l+1;i<=r;i++)for(int j=i;j>l;j--)compexch(a[j-1],a[j]);} • l,r – индексы начального и конечного элементов сортируемого массива • i – номер первого не отсортированного элемента • j – номер текущей позиции в отсортированной части массива
Сортировка вставками template <class Item>void sort(Item a[], int l, int r){ for(int i=l+1;i<=r;i++)for(int j=i;j>l;j--)compexch(a[j-1],a[j]);} 103 335 33 355 217 536 310335 33 355 217 536 3 1033533 355 217 536 3 1033335355 217 536 3 10 33335355217 536 3 10 33217335 355536 3 10 33 217 335 355536 • Среднее число операций на i шаге: • (0+i-1)*i/2/i = (i-1)/2 • Всего: • (i-1)/2=(n-2)(n-1)/2= O(n2)
Сортировка вставками template <class Item>void sort(Item a[], int l, int r){ for(int i=l+1;i<=r;i++)for(int j=i;j>l;j--)compexch(a[j-1],a[j]);} • Поскольку левый подмассив отсортирован, внутренний цикл можно завершить раньше
Сортировка вставками template <class Item>void sort(Item a[], int l, int r){ for(int i=l+1;i<=r;i++)for(int j=i;j>l;j--) if(!compexch(a[j-1],a[j])) break;} 2. Операцию обмена во внутреннем цикле следует заменить на операции сдвига.
Сортировка выбором template <class Item> void slct(Item a[],int l,int r) {for(int i=l;i<r;i++) { int min=i; for(int j=i+1;j<=r;j++) if(a[j]<a[min]) min=j; exch(a[i],a[min]); } } • i – первый несортированный элемент • j – номер текущей позиции в несортированной части массива
Сортировка выбором template <class Item> void slct(Item a[],int l,int r) {for(int i=l;i<r;i++) { int min=i; for(int j=i+1;j<=r;j++) if(a[j]<a[min]) min=j; exch(a[i],a[min]); } } 195 700 949 274 444 108 698 108 700 949 274 444 195 698 108195 949 274 444 700 698 108 195274 949 444 700 698 108 195 274444 949 700 698 108 195 274 444698 700 949 108 195 274 444 698700 949 Число сравнений: (n-1)+…+2+1= = n*(n-1)/2 Пересылок (n-1) O(n2)
Сортировка методом «пузырька» template <class Item> void bubble(Item a[], int l, int r) { for(int i=l; i<r; i++) for(int j=r; j>i; j--) compexch(a[j-1],a[j]); } 56441 165 815 685 764 827
Сортировка методом «пузырька» template <class Item> void bubble(Item a[], int l, int r) { for(int i=l; i<r; i++) for(int j=r; j>i; j--) compexch(a[j-1],a[j]); } 564 41 165 815 685 764 827 41 564 165685 815 764 827 41 165 564 685 764 815827 41 165 564 685 764 815 827 41 165 564 685 764 815 827 41 165 564 685 764 815 827 41 165 564 685 764 815 827 Число операций: n*(n-1)/2
Сортировка методом «пузырька» template <class Item> void bubble(Item a[], int l, int r) { for(int i=l; i<r; i++) for(int j=r; j>i; j--) compexch(a[j-1],a[j]); } • Выход из внешнего цикла можно производить при отсутствии обменов во внутреннем цикле • Не эффективна в работе с уже частично упорядоченными массивами 5 1 2 3 4
Шейкер-сортировка template <class Item>void shaker(Item a[], int l, int r) {int j,k=r; do { for(j=r;j>l;j--) if(compexch(a[j-1],a[j])) k=j; l=k; for(j=l+1;j<=r;j++) if(compexch(a[j-1],a[j])) k=j; r=k-1;} while(l<r); } Число пересылок O(n2) 6 5 4 3 2 1 0 05 4 3 2 16 0 14 3 25 6 0 1 2 3 4 5 6
Сортировка методом Шелла template <class Item> void shell(Item a[], int l, int r) { for(int h=1; h<=(r-l)/3; h=3*h+1); for(;h>0; h/=3) for(int i=l+h;i<=r;i++) { int j=i; Item v=a[i]; while( j>=l+h && v<a[j-h] ) { a[j]=a[j-h]; j-=h; } a[j]=v; } } h=3*h+1 1 4 13 40 121 364 1093 3280 9841 … O(N3/2)
Сортировка методом Шелла 4i+1 + 3*2i+1: 1 8 23 77 281 1073 4193 … O(N4/3) 2i: 1 2 4 16 32 64 128 … O(N2)
Быстрая сортировка Хора • l,r – левая и правая границы • I,j – левый и правый указатели • x = a[r] – разделяющий элемент
Быстрая сортировка Хора template <class Item> void quicksort(Item a[], int l, int r) { int i=l-1,j=r; Item x=a[r]; for(;;) { while(a[++i]<x) ; while(x<a[--j]) if(j==l) break; if(i>=j)break; exch(a[i],a[j]); } exch(a[i],a[r]); if(l<i-1) quicksort(a,l,i-1); if(i+1>r) quicksort(a,i+1,r); }
Быстрая сортировка Хора template <class Item> void quicksort(Item a[], int l, int r) { int i=l-1,j=r; Item x=a[r]; for(;;) { while(a[++i]<x) ; while(x<a[--j]) if(j==l) break; if(i>=j)break; exch(a[i],a[j]); } exch(a[i],a[r]); if(l<i-1) quicksort(a,l,i-1); if(i+1>r) quicksort(a,i+1,r); } 623 3 787 268 461 386 376 581 603 279
Быстрая сортировка Хора template <class Item> void quicksort(Item a[], int l, int r) { int i=l-1,j=r; Item x=a[r]; for(;;) { while(a[++i]<x) ; while(x<a[--j]) if(j==l) break; if(i>=j)break; exch(a[i],a[j]); } exch(a[i],a[r]); if(l<i-1) quicksort(a,l,i-1); if(i+1>r) quicksort(a,i+1,r); } 268 3 787 623 461 386 376 581 603 279
Быстрая сортировка Хора template <class Item> void quicksort(Item a[], int l, int r) { int i=l-1,j=r; Item x=a[r]; for(;;) { while(a[++i]<x) ; while(x<a[--j]) if(j==l) break; if(i>=j)break; exch(a[i],a[j]); } exch(a[i],a[r]); if(l<i-1) quicksort(a,l,i-1); if(i+1>r) quicksort(a,i+1,r); } 268 3 279 623 461 386 376 581 603 787
Быстрая сортировка Хора template <class Item> void quicksort(Item a[], int l, int r) { int i=l-1,j=r; Item x=a[r]; for(;;) { while(a[++i]<x) ; while(x<a[--j]) if(j==l) break; if(i>=j)break; exch(a[i],a[j]); } exch(a[i],a[r]); if(l<i-1) quicksort(a,l,i-1); if(i+1>r) quicksort(a,i+1,r); } 3 268 279 623 461 386 376 581 603 787
Быстрая сортировка Хора template <class Item> void quicksort(Item a[], int l, int r) { int i=l-1,j=r; Item x=a[r]; for(;;) { while(a[++i]<x) ; while(x<a[--j]) if(j==l) break; if(i>=j)break; exch(a[i],a[j]); } exch(a[i],a[r]); if(l<i-1) quicksort(a,l,i-1); if(i+1>r) quicksort(a,i+1,r); } 3 268 279 623 461 386 376 581 603 787
Быстрая сортировка Хора template <class Item> void quicksort(Item a[], int l, int r) { int i=l-1,j=r; Item x=a[r]; for(;;) { while(a[++i]<x) ; while(x<a[--j]) if(j==l) break; if(i>=j)break; exch(a[i],a[j]); } exch(a[i],a[r]); if(l<i-1) quicksort(a,l,i-1); if(i+1>r) quicksort(a,i+1,r); } 3 268 279 581 461 386 376 623 603 787
Быстрая сортировка Хора template <class Item> void quicksort(Item a[], int l, int r) { int i=l-1,j=r; Item x=a[r]; for(;;) { while(a[++i]<x) ; while(x<a[--j]) if(j==l) break; if(i>=j)break; exch(a[i],a[j]); } exch(a[i],a[r]); if(l<i-1) quicksort(a,l,i-1); if(i+1>r) quicksort(a,i+1,r); } 3 268 279 581 461 386 376 603 623 787
Быстрая сортировка Хора template <class Item> void quicksort(Item a[], int l, int r) { int i=l-1,j=r; Item x=a[r]; for(;;) { while(a[++i]<x) ; while(x<a[--j]) if(j==l) break; if(i>=j)break; exch(a[i],a[j]); } exch(a[i],a[r]); if(l<i-1) quicksort(a,l,i-1); if(i+1>r) quicksort(a,i+1,r); } 3 268 279 376 461 386 581 603 623 787
Быстрая сортировка Хора template <class Item> void quicksort(Item a[], int l, int r) { int i=l-1,j=r; Item x=a[r]; for(;;) { while(a[++i]<x) ; while(x<a[--j]) if(j==l) break; if(i>=j)break; exch(a[i],a[j]); } exch(a[i],a[r]); if(l<i-1) quicksort(a,l,i-1); if(i+1>r) quicksort(a,i+1,r); } 3 268 279 376 386 461 581 603 623 787
Оценки производительности • Наихудший случай (например, файл уже отсортирован): выполняет примерно О(N2/2) сравнений • Первый шаг: N сравнений и вызов для N-1 элемента • Второй шаг: N-1 сравнение и т.д. • Всего N + (N-1) + … + 1 = N(N+1)/2
Оценки производительности • Наилучший случай: на каждой стадии разбиения файл делится пополам: CN = 2CN/2 + N = N + 2(2CN/4 + N/2) = N + N + 4(2CN/8 + N/4) = = O(NlgN)
Оценки производительности • В среднем: • на каждой стадии разбиения файл делится на две части:
Оценки производительности • В среднем:
Нисходящая сортировка слиянием template <class Item> void merge(Item a[], int l, int m, int r) { int i,j; static Item aux[maxN]; for(i=m+1;i>l;i--) aux[i-1]=a[i-1]; for(j=m;j<r;j++) aux[r+m-j]=a[j+1]; for(int k=l;k<=r;k++) a[k]=aux[j]<aux[i]?aux[j--]:aux[i++]; } template <class Item> void mergesort(Item a[], int l, int r) { if(r<=l) return; int m=(r+l)/2; mergesort(a,l,m); mergesort(a,m+1,r); merge(a,l,m,r); } O(N log N)
Нисходящая сортировка слиянием template <class Item> void mergesort(Item a[], int l, int r) { if(r<=l) return; int m=(r+l)/2; mergesort(a,l,m); mergesort(a,m+1,r); merge(a,l,m,r); }
Нисходящая сортировка слиянием template <class Item> void merge(Item a[], int l, int m, int r) { int i,j; static Item aux[maxN]; for(i=m+1;i>l;i--) aux[i-1]=a[i-1]; for(j=m;j<r;j++) aux[r+m-j]=a[j+1]; for(int k=l;k<=r;k++) a[k]=aux[j]<aux[i]?aux[j--]:aux[i++]; }
Нисходящая сортировка слиянием template <class Item> void merge(Item a[], int l, int m, int r) { int i,j; static Item aux[maxN]; for(i=m+1;i>l;i--) aux[i-1]=a[i-1]; for(j=m;j<r;j++) aux[r+m-j]=a[j+1]; for(int k=l;k<=r;k++) a[k]=aux[j]<aux[i]?aux[j--]:aux[i++]; }
Нисходящая сортировка слиянием template <class Item> void merge(Item a[], int l, int m, int r) { int i,j; static Item aux[maxN]; for(i=m+1;i>l;i--) aux[i-1]=a[i-1]; for(j=m;j<r;j++) aux[r+m-j]=a[j+1]; for(int k=l;k<=r;k++) a[k]=aux[j]<aux[i]?aux[j--]:aux[i++]; }
Нисходящая сортировка слиянием template <class Item> void merge(Item a[], int l, int m, int r) { int i,j; static Item aux[maxN]; for(i=m+1;i>l;i--) aux[i-1]=a[i-1]; for(j=m;j<r;j++) aux[r+m-j]=a[j+1]; for(int k=l;k<=r;k++) a[k]=aux[j]<aux[i]?aux[j--]:aux[i++]; }
Нисходящая сортировка слиянием template <class Item> void merge(Item a[], int l, int m, int r) { int i,j; static Item aux[maxN]; for(i=m+1;i>l;i--) aux[i-1]=a[i-1]; for(j=m;j<r;j++) aux[r+m-j]=a[j+1]; for(int k=l;k<=r;k++) a[k]=aux[j]<aux[i]?aux[j--]:aux[i++]; }
Нисходящая сортировка слиянием template <class Item> void merge(Item a[], int l, int m, int r) { int i,j; static Item aux[maxN]; for(i=m+1;i>l;i--) aux[i-1]=a[i-1]; for(j=m;j<r;j++) aux[r+m-j]=a[j+1]; for(int k=l;k<=r;k++) a[k]=aux[j]<aux[i]?aux[j--]:aux[i++]; }
Нисходящая сортировка слиянием template <class Item> void merge(Item a[], int l, int m, int r) { int i,j; static Item aux[maxN]; for(i=m+1;i>l;i--) aux[i-1]=a[i-1]; for(j=m;j<r;j++) aux[r+m-j]=a[j+1]; for(int k=l;k<=r;k++) a[k]=aux[j]<aux[i]?aux[j--]:aux[i++]; }
Нисходящая сортировка слиянием template <class Item> void merge(Item a[], int l, int m, int r) { int i,j; static Item aux[maxN]; for(i=m+1;i>l;i--) aux[i-1]=a[i-1]; for(j=m;j<r;j++) aux[r+m-j]=a[j+1]; for(int k=l;k<=r;k++) a[k]=aux[j]<aux[i]?aux[j--]:aux[i++]; }
Нисходящая сортировка слиянием template <class Item> void merge(Item a[], int l, int m, int r) { int i,j; static Item aux[maxN]; for(i=m+1;i>l;i--) aux[i-1]=a[i-1]; for(j=m;j<r;j++) aux[r+m-j]=a[j+1]; for(int k=l;k<=r;k++) a[k]=aux[j]<aux[i]?aux[j--]:aux[i++]; }
Нисходящая сортировка слиянием template <class Item> void merge(Item a[], int l, int m, int r) { int i,j; static Item aux[maxN]; for(i=m+1;i>l;i--) aux[i-1]=a[i-1]; for(j=m;j<r;j++) aux[r+m-j]=a[j+1]; for(int k=l;k<=r;k++) a[k]=aux[j]<aux[i]?aux[j--]:aux[i++]; }