Алгоритъм за сортиране на купчина (с Code in Python намлява C++)

⚡ Умно обобщение

Алгоритъмът за сортиране чрез купчина сортира масив, като изгражда двоичен куп и многократно го обработва.tracдобавяйки коренната му стойност в сортираната секция. Този ресурс обяснява heapify, max и min heap-ове, псевдокод и complete Python намлява C++ реализации с анализ на времевата сложност.

  • 🌳 Основна идея: Сортирането с купчина изгражда пълна двоична купчина, след което многократно се извършваtracts корена, за да се получи сортиран ред.
  • 🔺 Heapify: Операцията heapify възстановява свойството heap чрез swapping родител с по-голямото си дете.
  • 🗃️ Съхранение на масиви: Купът (heap) се съхранява в масив, където възел с индекс i има деца на 2i+1 и 2i+2.
  • Сложност: Сортирането в куп се изпълнява за време O(n log n) във всички случаи и използва O(1) допълнително пространство.
  • 💻 Code При условие: Работа Python намлява C++ програмите демонстрират heapify, heap building и пълно сортиране.

Какво представлява алгоритъмът за сортиране на купчина?

Сортирането по купчина е един от популярните и по-бързи алгоритми за сортиране. Той е изграден върху пълната структура от данни на двоично дърво. Ще търсим максималния елемент и ще го поставяме на върха на максималната купчина. Ще го поставяме в родителския възел на двоичното дърво.

Да кажем, че е даден масив, данни = [10,5, 7, 9, 4, 11, 45, 17, 60].

В масива, ако i-тият (i=0,1,2,3 …) индекс е родителски възел, тогава (2i+1) и (2i+2) ще бъдат левите и десните деца. Създаването на пълно двоично дърво с този масив ще изглежда така:

Алгоритъм за сортиране на купчина

Ще извършим процеса на heapify от началото до края на масива. Първоначално, ако преобразуваме масива в дърво, той ще изглежда като горния. Можем да видим, че не поддържа никакво свойство на купчината (мин. купчина или максимална купчина). Ще получим сортирания масив, като извършим процеса на heapify за всички възли.

Приложение на Heap Sort

Ето малко използване на алгоритъма за сортиране на купчината:

  • Изграждането на „Приоритетни опашки“ изисква сортиране в купчина. Тъй като heapsort поддържа елемента сортиран след всяко вмъкване.
  • Heap Data Structure е ефективна при намирането на kth най-големият елемент в даден масив.
  • Ядрото на Linux използва сортирането на купчина по подразбиране алгоритъм за сортиране тъй като има O (1) пространствена сложност.

Създаване на Heap сортиране с пример

Тук ще конструираме максимална купчина от следното пълно двоично дърво.

Създаване на Heap сортиране с пример

Листовите възли са 17, 60, 4, 11 и 45. Те нямат дъщерни възли. Ето защо те са листни възли. И така, ще стартираме метода heapify от техния родителски възел. Ето стъпките:

Стъпка 1) Изберете най-лявото поддърво. Ако дъщерните възли са по-големи, разменете родителския възел с дъщерния възел.

Тук родителският възел е 9. А дъщерните възли са 17 и 60. Тъй като 60 е най-големият, 60 и 9 ще бъдат разменени, за да се поддържа макс. купчина.

Създаване на Heap сортиране с пример

Стъпка 2) Сега най-лявото поддърво е натрупано. Следващият родителски възел е 7. Този родител има два дъщерни възела, а най-големият е 45. Така че 45 и 7 ще бъдат разменени.

Създаване на Heap сортиране с пример

Създаване на Heap сортиране с пример

Стъпка 3) Възлите 60 и 4 имат родителския възел 5. Тъй като „5“ е по-малък от дъщерния възел 60, той ще бъде разменен.

Създаване на Heap сортиране с пример

Създаване на Heap сортиране с пример

Стъпка 4) Сега възел 5 има дъщерния възел 17,9. Това не е поддържане на свойството за максимална купчина. Така че 5 ще бъде заменено със 17.

Създаване на Heap сортиране с пример

Стъпка 5) Възел 10 ще бъде разменен с 60, след това с 17. Процесът ще изглежда по следния начин.

Създаване на Heap сортиране с пример

Създаване на Heap сортиране с пример

Стъпка 6) До стъпка 5 създадохме максималната купчина. Всеки родителски възел е по-голям от неговите дъщерни възли. Основният възел има максималната стойност (60).

Забележка: За да създадем сортирания масив, трябва да заменим възела с максимална стойност с неговия наследник.

Този процес се нарича „extract макс.”. Тъй като 60 е максималният възел, ние ще фиксираме позицията му към 0-ия индекс и ще създадем купчината без възел 60.

Създаване на Heap сортиране с пример

Създаване на Heap сортиране с пример

Стъпка 7) След като 60 се премахне, следващата максимална стойност е 45. Ще извършим процеса „Extrac„t Max“ отново от възел 45.

Този път ще получим 45 и ще заменим основния възел с неговия наследник 17.

Трябва да изпълним "Extract Max”, докато всички елементи бъдат сортирани.

След като направим тези стъпки, докато неtract всички максимални стойности, ще получим следния масив.

Създаване на Heap сортиране с пример

Какво е Binary Heap?

Двоичната купчина е един вид пълна двоично дърво структура на данните. В този вид дървовидна структура родителският възел е или по-голям, или по-малък от дъщерните възли. Ако родителският възел е по-малък, тогава купчината се нарича „Минимална купчина“, а ако родителският възел е по-голям, купчината се нарича „Максимална купчина“.

Ето примери за min heap и max heap.

Минимална купчина и максимална купчина
Минимална купчина и максимална купчина

На фигурата по-горе, ако забележите „Минимална купчина“, родителският възел винаги е по-малък от неговите дъщерни възли. В началото на дървото можем да намерим най-малката стойност 10.

По същия начин, за „Max Heap“ родителският възел винаги е по-голям от дъщерните възли. Максималният елемент присъства в главния възел за „Максимална купчина“.

Какво е „Heapify“?

„Heapify“ е принципът на купчината, който осигурява позицията на възела. В Heapify максималната купчина винаги поддържа връзка с родител и дете и това е, че родителският възел ще бъде по-голям от дъщерните възли.

Например, ако се добави нов възел, трябва да променим формата на купчината (heap). Възможно е обаче да се наложи да променим или разменим възлите или да пренаредим масива. Този процес на преформулиране...ping Купчината се нарича „heapify“ (натрупване на купчина).

Ето пример за това как работи heapify:

Добавяне на нов възел и Heapify
Добавяне на нов възел и heapify

Ето стъпките за heapify:

Стъпка 1) Добавен е възел 65 като дясно дете на възел 60.

Стъпка 2) Проверете дали новодобавеният възел е по-голям от родителския.

Стъпка 3) Тъй като е по-голям от родителския възел, сменихме дясното дете с неговия родител.

Как да изградим Купчината

Преди да изградим купчината или да натрупаме дърво, трябва да знаем как ще го съхраняваме. Тъй като купчината е цялостно двоично дърво, по-добре е да използвате an масив за съхранение на данните от купчината.

Да кажем, че един масив съдържа общо n елемента. Ако “i”-ият индекс е родителски възел, тогава левият възел ще бъде в индекса (2i+1), а десният възел ще бъде на индекс (2i+2). Приемаме, че индексът на масива започва от 0.

Използвайки това, нека съхраним максимален обем в подобен на масив след:

Базирано на масив представяне на максималната купчина
Базирано на масив представяне на максималната купчина

Алгоритъмът за heapify поддържа свойството heap. Ако родителят няма екстремната стойност (по-малка или по-голяма), той ще бъде разменен с най-крайния дъщерен възел.

Ето стъпките за натрупване на максимална купчина:

Стъпка 1) Започнете от листовия възел.

Стъпка 2) Намерете максимума между родител и деца.

Стъпка 3) Разменете възлите, ако дъщерният възел има по-голяма стойност от родителския.

Стъпка 4) Отидете едно ниво нагоре.

Стъпка 5) Следвайте стъпки 2,3,4, докато достигнем индекс 0 или сортираме цялото дърво.

Ето псевдокода за рекурсивна heapify (максимална купчина):

def heapify():
  input→ array, size, i
  largest = i
  left = 2*i + 1
  right = 2*i + 2
if left<n and array[largest ] < array[left]:
  largest = left
if right<n and array[largest ] < array[right]:
  largest = right
If largest not equals i:
  swap(array[i],array[largest])
  heapify(array,n,largest)

Прякор Code за сортиране по купчина

Ето псевдокода за алгоритъма за сортиране на купчина:

Heapify(numbers as an array, n as integer, i as integer):
  largest = i
  left = 2i+1
  right= 2i+2
if(left<=n) and (numbers[i]<numbers[left])
  largest=left
if(right<=n) and (numbers[i]<numbers[right])
  largest=right
if(largest  != i)
  swap(numbers[i], numbers[largest])
  Heapify(numbers,n,largest)
HeapSort(numbers as an array):
  n= numbers.size()
for i in range n/2 to 1
  Heapify(numbers,n,i)
for i in range n to 2
  Swap numbers[i] with numbers[1]
  Heapify(numbers,i,0)

Пример за сортиране в купчина Code in C++

#include <iostream>
using namespace std;
void display(int arr[], int n)
{
    for (int i = 0; i < n; i++)
    {
        cout << arr[i] << "\t";
    }
    cout << endl;
}
void heapify(int numbers[], int n, int i)
{
    int largest = i;
    int left = 2 * i + 1;
    int right = 2 * i + 2;
    if (left < n && numbers[left] < numbers[largest])
    {
        largest = left;
    }
    if (right < n && numbers[right] < numbers[largest])
    {
        largest = right;
    }
    if (largest != i)
    {
	//uncomment the following line to see details in output
        //cout<<"Swapping "<< numbers[i]<< " and "<<numbers[largest]<<endl;
        swap(numbers[i], numbers[largest]);
        heapify(numbers, n, largest);
    }
}
void heapSort(int numbers[], int n)
{
    for (int i = n/2 - 1; i >= 0; i--)
    {
        heapify(numbers, n, i);
//uncomment the following line to see details in output
 //cout<<"Heapify:\t";
  //display(numbers,n);
    }
    for (int i = n - 1; i >= 0; i--)
    {
        swap(numbers[0], numbers[i]);
        heapify(numbers, i, 0);
    }
}
int main()
{
    int numbers[] = { 10,5, 7, 9, 4, 11, 45, 17, 60};
    int size = sizeof(numbers) / sizeof(numbers[0]);
    cout<<"Initial Array:\t";
    display(numbers,size);
    heapSort(numbers, size);
    cout<<"Sorted Array (descending order):\t";
    display(numbers, size);
}

Изход:

Initial Array:  10      5       7       9       4       11      45      17      60
Sorted Array (descending order):  60      45      17      11      10      9       7       5       4

Пример за сортиране в купчина Code in Python

def display(arr):
    for i in range(len(arr)):
    print(arr[i], end = "\t")
print()
def heapify(numbers, n, i):
    largest = i
left = 2 * i + 1
right = 2 * i + 2
if left < n and numbers[left] < numbers[largest]:
    largest = left
if right < n and numbers[right] < numbers[largest]:
    largest = right
if largest != i:
    numbers[i], numbers[largest] = numbers[largest], numbers[i]
heapify(numbers, n, largest)
def heapSort(items, n):
    for i in range(n //2,-1,-1):
        heapify(items, n, i) for i in range(n - 1, -1, -1):
        items[0], items[i] = items[i], items[0] heapify(items, i, 0) numbers = [10, 5, 7, 9, 4, 11, 45, 17, 60] print("Initial List:\t", end = "") display(numbers) print("After HeapSort:\t", end = "") heapSort(numbers, len(numbers)) display(numbers)

Изход:

Initial List:   10      5       7       9       4       11      45      17      60
After HeapSort: 60      45      17      11      10      9       7       5       4

Времеви и пространствен анализ на сложността на Heap Sort

Има времева сложност и пространствена сложност, които можем да анализираме за груповото сортиране. За времева сложност имаме следните случаи:

  1. Най -добрият случай
  2. Среден случай
  3. Най-лошия случай

Купчината е имплементирана върху цялостно двоично дърво. Така че на най-долното ниво на двоичното дърво ще има максимален брой възли. Ако долното ниво има n възли, тогава горното ниво ще има n/2 възела.

Анализ на времевата и пространствената сложност

В този пример ниво 3 има четири елемента, ниво 2 има два елемента, а ниво 1 има един елемент. Ако има общо n на брой елементи, ще бъде височината или общото ниво Вход2(н). Така че вмъкването на един елемент може да отнеме максимум Log(n) итерации.

Когато искаме да вземем максималната стойност от купчината, ние просто вземаме основния възел. След това отново стартирайте heapify. Всеки heapify взема Вход2(П) време. ИзвънtracДостигането на максимума отнема O(1) време.

Най-добър случай на времева сложност за алгоритъм за сортиране на купчина

Когато всички елементи вече са сортирани в масива, изграждането на купчината ще отнеме O(n) време. Защото, ако списъкът е сортиран, тогава вмъкването на елемент ще отнеме постоянното време, което е O(1).

Така че ще отнеме O(n) време за създаване на max-heap или min-heap в най-добрия случай.

Средна времева сложност на случая за алгоритъм за сортиране на купчина

Вмъкване на елемент или експозицияtracПостигането на максимум струва O(log(n)) време. Така че, средната времева сложност за алгоритъма за сортиране на heap е O(n log(n)).

Времева сложност в най-лошия случай за алгоритъм за сортиране на купчина

Подобно на средния случай, в най-лошия сценарий можем да извършим heapify n пъти. Всяко heapify ще струва O(log(n)) време. Така че в най-лошия случай времевата сложност ще бъде O(n log(n)).

Пространствена сложност за алгоритъм за сортиране на купчина

Heap sort е алгоритъм, проектиран на място. Това означава, че не е необходима допълнителна или временна памет за изпълнение на задачата. Ако видим изпълнението, ще забележим, че сме използвали swap (), за да извършим обмена на възлите. Не беше необходим друг списък или масив. И така, пространствената сложност е O(1).

Въпроси и Отговори

Сортирането с купчина не е стабилен алгоритъм за сортиране, защото изграждането иtracИзвличането от хепа може да пренареди равни елементи. Ако запазването на оригиналния ред на равните ключове е важно, стабилен алгоритъм като сортиране чрез сливане е по-добър избор.

Сортирането с купчина гарантира време от O(n log n) във всички случаи и използва O(1) допълнително пространство. Бързото сортиране обикновено е по-бързо на практика, но може да се влоши до O(n²) при лоши pivot-и. Сортирането с купчина жертва известна скорост за надежден най-лош случай.

Както сортирането чрез heap, така и сортирането чрез merge се изпълняват за време O(n log n). Сортирането чрез heap сортира на място с O(1) допълнително пространство, но е нестабилно. Сортирането чрез сливане е стабилно, но се нуждае от O(n) допълнително пространство за сливане.

ИИ преподавателите могат да анимират процеса на heapify, да покажат как се формира максималният heap и tracвсеки бившtract-max стъпка. Тази визуална, интерактивна помощ улеснява начинаещите да разберат как сортирането в heap подрежда масив.

Да. Асистентите за кодиране с изкуствен интелект могат да превеждат имплементация на сортиране на купчина между езици като например C++, Python, и Java докато кееping логиката е непокътната. Все пак трябва да компилирате и тествате конвертирания код, за да потвърдите правилния изход.

Обобщете тази публикация с: