Структура даних купи: Що таке купа?

⚡ Розумний підсумок

Структура даних купи (Heap Data Structure) — це спеціалізоване повне бінарне дерево, де кожен батьківський вузол підтримує суворий порядок зв'язків зі своїми дочірніми вузлами, що дозволяє виконувати логарифмічні вставки, видалення та операції з пріоритетною чергою під час сортування, планування та роботи з графами.

  • ???? Форма дерева: Купа (Heap) — це повне бінарне дерево, заповнене зліва направо, з унікальними ключами в кожному вузлі для швидкого порівняння.
  • ⬆️ Max-Heap: Кожен батьківський елемент більший або дорівнює своїм дочірнім елементам, тому найбільший елемент завжди знаходиться в корені для доступу O(1).
  • (І.Е. Мін-купа: Кожен батьківський елемент менший або дорівнює своїм дітям, зберігайтеping найменший елемент у корені для пріоритетного пошуку.
  • Core Operaтиони: Пошук, вставка, видалення, додавання купи та об'єднання виконуються за час O(log n), підтримуючи логіку сортування купи та черги пріоритетів.
  • 🧪 Реальне використання: Структура даних купи (Heap Data Structure) забезпечує фільтрацію спаму, графові алгоритми, планування ОС, кодування Хаффмана та евристичний пошук ШІ.

Що таке структура даних купи?

Купа (Heap) — це спеціалізована деревоподібна структура даних. Структура даних купи складається з найвищого вузла, який називається коренем (батьківським вузлом). Його другий вузол є лівим дочірнім вузлом кореня, а третій вузол — правим дочірнім вузлом кореня. Наступні вузли заповнюються зліва направо. Ключ батьківського вузла порівнюється з ключем його нащадка, щоб досягти правильного розташування. Дерево легко візуалізувати, де кожна сутність називається вузлом, і кожен вузол має унікальний ключ для ідентифікації.

Простіше кажучи, купа (Heap) — це повне бінарне дерево, яке задовольняє властивість купи: кожен батьківський елемент упорядкований послідовно відносно своїх дочірніх елементів, що робить його ідеальним для черг за пріоритетом та сортування купою (Heap Sort).

Навіщо вам потрібна структура даних купи?

Ось основні причини використання купи:

  • Структура даних Heap дозволяє видалення та вставку за логарифмічний час – O(log2п).
  • Дані в дереві розташовані в певному порядку. Окрім оновлення або запиту значень, таких як максимум або мінімум, програміст може знаходити зв'язки між батьківськими елементами та елементами-нащадками.
  • Ви можете застосувати концепцію Модель об'єкта документа щоб допомогти вам візуально зрозуміти структуру даних купи.
  • Купи підтримують ефективні операції з чергою пріоритетів, які є критично важливими для графових алгоритмів, таких як найкоротший шлях Дейкстри та мінімальне охоплююче дерево Прима.

Типи куп

Структура даних купи має різні алгоритми для обробки вставки та видалення елементів, включаючи чергу пріоритетів, двійкову купу, біноміальну купу та Сортування купи.

  • Черга пріоритетів: Це пресtracСтруктура даних t, що містить об'єкти з пріоритетом. Кожен об'єкт або елемент має заздалегідь визначений пріоритет. Таким чином, об'єкт або елемент, якому призначено вищий пріоритет, отримує послугу раніше за інших.
  • Бінарна купа: Бінарні купи підходять для простих операцій з купою, таких як видалення та вставки. Вони є реалізацією за замовчуванням для більшості черг пріоритетів стандартних бібліотек.
  • Біноміальна купа: Біноміальна купа складається з серії колекцій біноміальних дерев, які складають купу. Біноміальне дерево купи не є звичайним деревом, оскільки воно суворо визначене. Загальна кількість елементів у біноміальному дереві завжди дорівнює 2.n вузли.
  • Сортування купи: На відміну від більшості алгоритмів сортування, сортування купою використовує простір O(1) для своєї операції сортування. Це алгоритм сортування на основі порівняння, де сортування відбувається у порядку зростання, спочатку перетворюючи вхідні дані на Max-Heap. Ви можете розглядати сортування купою як оновлене двійкове дерево пошуку.

Зазвичай, структура даних типу «купа» використовує дві стратегії. Для вхідних даних 12 – 8 – 4 – 2 та 1:

  • Min-Heap – найменше значення зверху
  • Макс-Хіп – найвище значення зверху

Типи куп

Min-Heap

У структурі Min-Heap кореневий вузол має значення, що дорівнює або менше, ніж значення дочірніх вузлів цього вузла. Таким чином, корінь Min-Heap містить мінімальне значення. Min-Heap також є повним бінарним деревом.

Як тільки у вас є мінімальна купа в дереві, всі листки є життєздатними кандидатами на максимальне значення. Однак, вам потрібно дослідити кожен листок, щоб отримати точне значення максимальної купи.

Приклад мінімальної купи

Приклад мінімальної купи

На діаграмі вище можна помітити чітку послідовність від кореня до найнижчого вузла.

Припустимо, ви зберігаєте елементи в масиві Array_N[12, 2, 8, 1, 4]. Як видно з масиву, кореневий елемент порушує пріоритет Min-Heap. Щоб зберегти властивість Min-Heap, потрібно виконати операції min-heapify для обміну елементами, доки не будуть виконані правила Min-Heap.

Макс-Хіп

У структурі Max-Heap батьківський або кореневий вузол має значення, що дорівнює або більше, ніж у його дочірніх вузлів. Цей вузол містить максимальне значення. Це повне бінарне дерево, тому ви можете побудувати Max-Heap з колекції значень за час O(n).

Ось кілька методів, які зазвичай використовуються під час впровадження Java Max-Heap:

  • Додати (): Розміщує новий елемент у купі. Якщо ви використовуєте масив, об'єкти додаються в кінець масиву, тоді як у бінарному дереві об'єкти додаються зверху вниз, а потім зліва направо.
  • Видалити (): Цей метод дозволяє видалити перший елемент зі списку масиву. Оскільки щойно підвищений елемент більше не є найбільшим, метод Sift-Down завжди переміщує його на нове місце.
  • Просіювання (): Цей метод порівнює кореневий об'єкт з його дочірніми об'єктами, а потім переміщує переміщений вузол на його законну позицію.
  • Просіювання (): Якщо ви використовуєте метод масиву для додавання щойно вставленого елемента до масиву, то метод Sift-Up допомагає щойно доданому вузлу переміститися на правильну позицію. Новий елемент спочатку порівнюється з батьківським, імітуючи структуру даних дерева.

    Застосуйте формулу Parent_Index = Child_Index / 2. Продовжуйте робити це, доки максимальний елемент не опиниться на початку масиву.

Базова купа Operaвих

Щоб знайти найбільше та найменше значення в наборі даних, вам потрібно кілька основних операцій з купою, таких як пошук, вставка та видалення. Оскільки елементи постійно з'являються та зникають, вам слід знати, як:

  • знайти – Шукайте предмет у купі.
  • Insert – Додати нову дитину в купу.
  • видаляти – Видалити вузол із купи.

Створення куп

Процес побудови куп називається створенням куп. Маючи список ключів, програміст створює порожню купу, а потім по черзі вставляє інші ключі, використовуючи основні операції з купою.

Отже, почнемо створювати мініатюрну купу (Min-Heap) за допомогою методу Вільяма, вставляючи значення 12, 2, 8, 1 та 4. Ви можете створити купу з n елементів, почавши з порожньої купи, а потім послідовно заповнюючи її іншими елементами, використовуючи час O(n log n).

Створення куп

  • Хіпіфікація: Процедура вставки, яка допомагає вставляти елементи в купу, зберігаючи при цьому властивість купи.

    Наприклад, операція max-heapify перевіряє, чи значення батьківського елемента більше, ніж значення його нащадка. Потім елементи можна сортувати за допомогою методів, таких як swapping.

  • Об’єднати: Коли у вас є дві купи для об'єднання в одну, використовуйте операцію злиття, щоб об'єднати значення з двох куп. Початкові купи зберігаються.

Огляньте відвали

Перевірка куп означає перевірку кількості елементів у структурі даних купи та перевірку того, чи купа порожня.

Важливо перевіряти купи під час сортування або постановки елементів у чергу. Важливо перевірити наявність елементів для обробки за допомогою Is-Empty(). Розмір купи допоможе знайти корені Max-Heap або Min-Heap, тому вам потрібно знати, скільки елементів слідує за властивістю купи.

  • Розмір – повертає величину або довжину купи. Він показує, скільки елементів зберігається в відсортованому порядку.
  • Пусто – повертає TRUE, якщо купа дорівнює null, інакше повертає FALSE.

Тут ви друкуєте всі елементи в пріоритетQ циклу, а потім перевірити, що priorityQ не порожній.

//print head the head values
       While (!priorityQ.isEmpty()) {
        System.out.print(priorityQ.poll()+" ");

Використання структури даних купи

Структура даних купи корисна в багатьох програмних застосунках у реальному житті, таких як:

  • Допомагає у фільтрації спаму.
  • Реалізація графових алгоритмів, таких як Дейкстра та Прим.
  • Operaбалансування навантаження системи та стиснення даних.
  • Знаходження порядкових статистик, таких як k-й найменший елемент.
  • Реалізація черг пріоритетів, де можна шукати елементи у списку за логарифмічний час.
  • Структура даних купи також використовується для сортування за допомогою сортування купи.
  • Моделювання клієнтів у черзі очікування.
  • Обробка переривань у Operating System.
  • У кодуванні Хаффмана для стиснення даних.
  • Використання пошуку за принципом «спочатку найкращий» та евристики A* у плануванні шляхів за допомогою штучного інтелекту.

Властивості черги пріоритету купи

Наступні властивості описують поведінку черги пріоритетів, побудованої на купі:

  • У купах пріоритетів елементи даних у списку порівнюються один з одним, щоб визначити менший або більший елемент.
  • Елемент поміщається в чергу, а потім видаляється в порядку пріоритетності.
  • Кожен елемент у черзі пріоритетів має унікальний номер, пов'язаний з ним, який позначено як пріоритет.
  • Після виходу з черги пріоритетів, елемент з найвищим пріоритетом виходить першим.

Кроки для реалізації черги пріоритетів купи в Java

Наступна секція переходить у бетон Java реалізація, яка перетворює ці правила на робочий код.

Кроки для впровадження черги пріоритету купи

Купа Сортувати в Java з Code Приклад

import java.util.Arrays;
public class HeapSort {
    public static void main(String[] args) {
        int[] arr = {5, 9, 3, 1, 8, 6};
        // Sort the array using heap sort
        heapSort(arr);
        // Print the sorted array
        System.out.println(Arrays.toString(arr));
    }
    public static void heapSort(int[] arr) {
        // Convert the array into a heap
        for (int i = arr.length / 2 - 1; i >= 0; i--) {
            heapify(arr, arr.length, i);
        }
        // Extract the maximum element from the heap and place it at the end of the array
        for (int i = arr.length - 1; i >= 0; i--) {
            int temp = arr[0];
            arr[0] = arr[i];
            arr[i] = temp;
            heapify(arr, i, 0);
        }
    }
    public static void heapify(int[] arr, int n, int i) {
        int largest = i;
        int left = 2 * i + 1;
        int right = 2 * i + 2;
        // Find the largest element among the root, left child, and right child
        if (left < n && arr[left] > arr[largest]) {
            largest = left;
        }
        if (right < n && arr[right] > arr[largest]) {
            largest = right;
        }
        // If the largest element is not the root, swap and heapify the sub-tree
        if (largest != i) {
            int temp = arr[i];
            arr[i] = arr[largest];
            arr[largest] = temp;
            heapify(arr, n, largest);
        }
    }
}

Вихід

Original Array:

5 9 3 1 8 6

Heap after insertion:

9 8 6 1 5 3

Heap after sorting:

1 3 5 6 8 9

Купа Сортувати в Python з Code Приклад

def heap_sort(arr):
    """
    Sorts an array in ascending order using heap sort algorithm.
    Parameters:
        arr (list): The array to be sorted.
    Returns:
        list: The sorted array.
    """
    n = len(arr)
    # Build a max heap from the array
    for i in range(n // 2 - 1, -1, -1):
        heapify(arr, n, i)
    # Extract elements from the heap one by one
    for i in range(n - 1, 0, -1):
        arr[0], arr[i] = arr[i], arr[0]  # swap the root with the last element
        heapify(arr, i, 0)  # heapify the reduced heap
    return arr
def heapify(arr, n, i):
    """
    Heapifies a subtree with the root at index i in the given array.
    Parameters:
        arr (list): The array containing the subtree to be heapified.
        n (int): The size of the subtree.
        i (int): The root index of the subtree.
    """
    largest = i  # initialize largest as the root
    left = 2 * i + 1  # left child index
    right = 2 * i + 2  # right child index
    # If left child is larger than root
    if left < n and arr[left] > arr[largest]:
        largest = left
    # If right child is larger than largest so far
    if right < n and arr[right] > arr[largest]:
        largest = right
    # If largest is not root
    if largest != i:
        arr[i], arr[largest] = (
            arr[largest],
            arr[i],
        )  # swap the root with the largest element
        heapify(arr, n, largest)  # recursively heapify the affected subtree
arr = [4, 1, 3, 9, 7]
sorted_arr = heap_sort(arr)
print(sorted_arr)

Вихід

[1, 3, 4, 7, 9]

Далі ви дізнаєтесь про Метод розрізу навпіл.

Поширені запитання

Купа гарантує лише впорядкування батьків-дитина, тому корінь є мінімальним або максимальним. Бінарне дерево пошуку гарантує впорядкування за принципом ліве піддерево-менше кореня-менше правого піддерева на кожному вузлі, підтримуючи швидкий обхід у порядку по порядку та пошук за ключем.

Оберіть Max-Heap, коли вашій програмі постійно потрібен найбільший елемент, наприклад, під час планування завдання з найвищим пріоритетом або виконання сортування купи у порядку зростання. Оберіть Min-Heap, коли вам спочатку потрібен найменший елемент, наприклад, найкоротший шлях Дейкстри.

Вставка та видалення в структурі даних купи виконуються за O(log n) через шлях heapify від кореня до листка. Перегляд мінімуму або максимуму виконується за O(1), а побудова купи з n елементів займає O(n).

Сортування купою є на місці, оскільки воно сортує масив, використовуючи O(1) додаткової пам'яті понад вхідні дані. Воно нестабільне, оскільки однакові ключі можуть змінювати відносний порядок під час heapify та ex.tract-max кроки, що використовуються для отримання відсортованого виводу.

Алгоритми пошуку на основі штучного інтелекту, такі як A* та пошук за принципом «найкращий перший», зберігають граничні вузли в міні-купі з евристичною вартістю. Купа гарантує, що наступним розгортається найдешевший кандидат, що критично важливо для швидкого пошуку шляхів, ігрового штучного інтелекту та планувальників робототехніки.

Так. Візуалізатори за допомогою штучного інтелекту можуть генерувати покрокові діаграми вставок, об'єднання змінних у купу та виведення.tract-max операції з вашого коду. Вони також позначають порушення властивостей купи, пропонують виправлення та пояснюють асимптотичну поведінку простою мовою, що пришвидшує навчання та налагодження.

Підсумуйте цей пост за допомогою: