Сортировка вставками ( insertion sort)



В данной сортировке мы вставляем каждый новый элемент на то место, чтобы массив был отсортирован. К примеру, есть у нас массив (4) (7) (1) (0) (5) и мы его хотим отсортировать по возрастанию. Создаём новый пустой массив такого же размера и помещаем первый элемент. Далее каждый следующий положим в нужное место:

(4)

(4) (7)

(1) (4) (7)

(0) (1) (4) (7)

(0) (1) (4) (5) (7)

В какое именно место класть, можно понять на примере. У нас есть (0) (1) (4) (7) и надо положить (5). Мы будем проверять (0) > (5) ? нет. И т.д. пока не дойдём до (7) > (5) ? да. Ну тогда ставим перед семёркой. Это был упрощённый пример для понимания принципа.

Ниже код с более совершенным алгоритмом, где левая часть массива будет отсортированной, а из правой части массива мы будем вставлять элементы в левую, таким образом сортируя весь массив:

void insertionsort(int a[], int size) {

int buf; // то что мы будем вставлять

// цикл прохода по исходному массиву

for (int i=1, j; i<size; i++) {

   buf= a[i]; // берём первый левый элемент из неотсортированной части массива

// поиск места куда вставить и сдвиг неотсортированных элементов вправо (по циклу проходимся справа налево)

   for (j= i-1; j>=0 && a[j]>buf; j--) a[j+1]= a[j];

   a[j+1]= buf; // вставка в нужное место

}

}

 

Сортировка Шелла

Это некая модификация сортировки простыми вставками. Алгоритм достаточно сложный, поэтому комментировать и копаться я в нём не буду, это просто для ознакомления, что такой алгоритм вообще есть, и использования. Ниже весь алгоритм:

// вспомогательная функция

int increment(int inc[], int size) {

int p1, p2, p3, s;

p1 = p2 = p3 = 1;

s= -1;

do {

   if (++s % 2) inc[s]= 8*p1 - 6*p2 + 1;

   else {

       inc[s]= 9*p1 - 9*p3 + 1; p2 *= 2; p3 *= 2;

   }

p1*=2;

}

while(3*inc[s] < size); 

return s>0 ? --s : 0;

}

// сама сортировка

void shellsort(int a[], int size) {

int inc, i, j, seq[40];

int s;

s= increment(seq, size);

while (s>=0) {

    inc= seq[s--];        

    for (i=inc; i<size; i++) {

        int temp= a[i];

        for (j=i; (j>=inc) && (temp < a[j-inc]); j-=inc) {

           a[j]= a[j-inc];

        }

        a[j]= temp;

    }

}

}

 

Пирамидальная сортировка

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

// вспомогательная функция

void downHeap(int a[], int k, int n) {

int new_elem;

int child;

new_elem= a[k];

while(k <= n/2) {      

   child= 2*k;

   if (child<n && a[child]<a[child+1]) child++;

   if (new_elem >= a[child]) break;

   a[k] = a[child];

   k = child;

}

a[k] = new_elem;

}

// сама сортировка

void heapSort(int a[], int size) {

int i; int temp;

          for(i= size/2 - 1; i>=0; i--) downHeap(a, i, size-1);

for(i= size-1; i>0; i--) {

   temp= a[i]; a[i]= a[0]; a[0]= temp;

   downHeap(a, 0, i-1);

}

}

Этот алгоритм уже быстрее рассмотренных ранее. Если у "типовых" алгоритмов скорость была O(n*n), то тут уже O(n*log(n))

 

Сортировка слиянием ( merge sort)

Ещё один сравнительно быстрый и рекурсивный алгоритм сортировки наряду с быстрой сортировкой, которую мы выдали ещё в 1-м разделе (или также quick sort, сортировка Хоара)

Сортировка слияния похожа на быструю сортировку. Здесь массив делится на две примерно равные половины, каждая половина сортируется этой же функцией (происходит рекурсия), а потом отсортированные массивы соединяются.

Если сравнивать с быстрой сортировкой, то там тоже происходит рекурсивное деление, но принцип сортировки другой и больше похож на пузырьковый. Только в первую очередь происходят перестановки элементов на наибольшем возможном расстоянии.

Что у быстрой сортировки, то и у сортировки слиянием- скорость алгоритма O(n*log(n)), как и у пирамидальной.

Теперь сам код сортировки слиянием- тут представлен метод нисходящего слияния.

void mergesort(int a[], int l, int r) {

if (l == r) return;

int mid = (l+r) / 2;

mergesort(a, l, mid);

mergesort(a, mid + 1, r);

int i = l; 

int j = mid + 1;

int *tmp = new int [r];

for (int step = 0; step < r - l + 1; step++) {

if ((j > r) || ((i <= mid) && (a[i] < a[j]))) { tmp[step] = a[i]; i++; }

else { tmp[step] = a[j]; j++; }

}

for (int step = 0; step < r - l + 1; step++) a[l + step] = tmp[step];

}

Используется сортировка массива из 11 элементов так: mergeSort(mass,0,10); т.е. указывается левый и правый элемент. Это было нужно для рекурсии. Можно сделать перегрузку чтобы можно было указывать как обычно- добавить ниже ещё 1 доп.функцию:

void mergesort(int a[], int size) {

           mergesort(a,0,size-1);

}

И теперь можно использовать как обычно: mergesort(mass,11);

Ниже другой код сортировки слиянием, он организован без рекурсии. Этот метод называется методом восходящего слияния.

void mergesort(int a[], int size) {

int step = 1; int *temp= new int [size];

while (step<size) {

int index= 0; int l= 0; int m= l+step; int r= l+step*2; 

do {

m= m<size ? m : size;

r= r<size ? r : size;

int i1= l, i2= m;

for (; i1 < m && i2 < r; ) {

if (a[i1]<a[i2]) temp[index++]= a[i1++];

           else temp[index++]= a[i2++];

}

while (i1 < m) temp[index++]= a[i1++];

while (i2 < r) temp[index++]= a[i2++];

l+= step*2; m+= step*2; r+= step*2;

} while (l<size);

for (int i = 0; i < size; i++) a[i]= temp[i];

step*= 2;

}

}

 


Дата добавления: 2018-09-22; просмотров: 308; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!