Реализация двоичной кучи методом динамических структур C++

Есть задание по реализации двоичной кучи через динамические структуры (не классы, никакого ООП). Я примерно понимаю алгоритм и код для случая, когда двоичная куча является по сути своей массивом, но никак не могу додуматься до моего случая. В хэдере я создал две структуры:

struct hNode
{
    //UPD (22.05.2022 17.35):
    int index;
    double value;
    hNode* parent = nullptr;
    hNode* left_child = nullptr;
    hNode* right_child = nullptr;
};

struct heap
{
    int size = 0;
    hNode* root = nullptr;
};

Было решено разделить процесс заполнения кучи значениями и её упорядочивание в две разные функции, но не одну из этих функций я так реализовать и не смог. Самая главная для меня проблема - понять, в какой момент алгоритм должен стать рекурсивным. Все, что я успел наработать, так это:

void addItem(heap* heap, double value, int ind)
{
    if (heap->root == nullptr)
    {
        auto node = new hNode();
        node->value = value;
        node->index = 0;
        heap->root = node;
        ind++;
    }
    else
    {
        while (ind <= heap->size-1)
        {

        }
    }
    
}

void heapifyMax(heap* heap)
{

}

Буду благодарен любой помощи: готовому коду, описанию алгоритма, ссылке на любую литературу или похожий тред.


Ответы (1 шт):

Автор решения: DmitryK

Как вариант для добавления элемента в дерево:

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

В любом случае, есть формулы, по которым вычисляется индекс потомка, по ним же можно вычислить индекс предка.

Остался один вопрос - зачем??? Ведь весь смысл кучи в том, что в памяти её проще всего хранить в массиве, ведь оно полное, пока не заполнен уровень, элементы на следующий уровень не добавляются. В вашем варианте происходит перерасход памяти на хранение кучи, перерасход процессорного времени на операции с узлами (добавление, поиск, удаление, упорядочивание и т.д.)
Все структуры данных делаются для того, чтобы оптимизировать ресурсы. Например массив - самый оптимальный по расходу памяти, дерево - очень быстрый поиск, список - быстрая вставка элементов в любое место и т.д. Зачем реализовывать хранение кучи в памяти через дерево, если оптимальнее всего хранить её в виде массива?

→ Ссылка