Heap of data structure (priority queue) c++

Heap of data structure (priority queue) c++

What is a pile?

Heap (priority queue) is a "special" queue. The order in which elements are taken out is based on the priority (keyword) size of elements, not the order in which elements enter the queue.
The heap can be regarded as a complete binary tree. You can use either a linked list or an array. But it is more convenient to use array. It uses an array to implement a heap, as shown in the figure below.

Corresponding array (in the structure with array as storage mode, no data is stored where the index of the array is 0)
Heap can be divided into two types, one is the largest heap and the other is the smallest heap
Maximum heap: the value of the parent node is larger than its two child nodes (if any).
Minimum heap: the value of the parent node is smaller than its two child nodes (if any).

The following describes the structure and operation of the heap:

In order to cope with different data types, we use template classes here,

template <class T>
class Heap
{

public:
//It is convenient for users to choose whether to create a large pile or a small pile
    enum Way
    {
        GREATER,//large
        LESS//Small
    };

private:
    T *array_heap;       //heap
    size_t current_size; //Current capacity
    size_t max_size;     //Maximum capacity
    Way flag;            //Mark of pile (large pile / small pile)

public:
    explicit Heap(const int &Size);
    ~Heap();
    //Output in heap data
    void print();
    //Is the heap empty
    bool empty() const;
    //Is the heap full
    bool full() const;
    //Pile out
    T delHeap();
    //insert data
    void insert(const T &Data, Way way);
    //Construction pile
    void createHeap(const T *Data_Array, const size_t &Size, Way way = Heap<T>::GREATER);

private:
    //less than
    bool less(const T &Left, const T &Right);
    //greater than
    bool greater(const T &Left, const T &Right);
    //compare
    bool compare(const T &Left, const T &Right, Way way);
    //Adjustment reactor
    void adjust();
    //Adjustment reactor
    void adjust(Way way);
public:
    T &operator[](const int &location);
};

Next, we give the definition of some functions (out of class implementation)

template <typename T>
Heap<T>::Heap(const int &Size) : max_size(Size), current_size(0), flag(Heap<T>::GREATER)
{
    //The requested memory location 0 is not used
    this->array_heap = new T[Size + 1];
    //Whether the memory request is successful
    assert(this->array_heap);
    //Initialization data
    for (int i = 0; i < Size; ++i)
    {
        this->array_heap[i] = 0;
    }
};

template <typename T>
Heap<T>::~Heap()
{
    if (this->array_heap)
    {
        delete[] this->array_heap;
    }
    this->array_heap = nullptr;
    this->current_size = this->max_size = 0;
}

//Is the heap empty
template <typename T>
bool Heap<T>::empty() const
{
    return (this->current_size == 0);
}
//Is the heap full
template <typename T>
bool Heap<T>::full() const
{
    return (this->current_size == this->max_size + 1);
}

template <typename T>
T &Heap<T>::operator[](const int &Location)
{
    return (this->array_heap[Location]);
}

//less than
template <typename T>
bool Heap<T>::less(const T &Left, const T &Right)
{
    return (Left < Right);
}
//greater than
template <typename T>
bool Heap<T>::greater(const T &Left, const T &Right)
{
    return (Left > Right);
}

//compare
template <typename T>
bool Heap<T>::compare(const T &Left, const T &Right, Heap<T>::Way way)
{
    if (way == this->GREATER)
    {
        return this->greater(Left, Right);
    }
    else
    {
        return (this->less(Left, Right));
    }
}
//Output in heap data
template <typename T>
void Heap<T>::print()
{
    for (auto i = 1; i <= this->current_size; ++i)
    {
        std::cout << this->array_heap[i] << ' ';
    }
    std::cout << std::endl;
}

Heap construction

We use an array to construct a heap. In order to process multiple data, our construction chooses to accept an array element to initialize our heap (this function is implemented in class)

//Construction pile
    void createHeap(const T *Data_Array, const size_t &Size, Way way = Heap<T>::GREATER)
    {
        this->flag = way; //Identification heap
        if (Size > this->max_size)
        {
            return;
        }
        for (auto i = 0; i < Size; ++i)
        {
            this->insert(Data_Array[i], way);
        }
    }

Heap insertion

You should have noticed that the core operation of our heap construction function is actually insertion,
***Note: * * * when inserting elements into the heap, the nature of the heap cannot be changed.
Insert operation:
Insert the element into the heap. First, we insert the element into the next position of the last element of the array (assuming the subscript is i). Next, we need to adjust the heap.

Let's take a lot of data as an example. Suppose that the data we want to insert is 10, as shown in the figure:


We put 10 at the end of the array. We can see that at this time, 10 > 9, which must have violated the nature of a lot, so we need to adjust it. The adjustment method is to compare 10 with its parent node. If the value is greater than the parent node, we will exchange the node with the parent node, and then continue to compare with its parent node, Until ordered (Note: during the adjustment process, the subscript of the parent node cannot reach zero, i.e. > 1). (the calculation formula of parent node subscript is: parent node subscript = current subscript / 2)

At this time, we find that 10 < 16 (parent node), and the heap is in order, so there is no need to adjust it

Let's look at the code implementation of the insert operation:

 //insert data
    void insert(const T &Data, Way way)
    {
        //Is the heap full
        if (this->full())
        {
            return;
        }
        //Insert data to the end
        this->array_heap[++this->current_size] = Data;
        //Adjustment reactor
        this->adjust(way);
    }

The following is the core of the insertion operation, that is, adjusting the heap to make the heap orderly,

//Adjustment reactor
    void adjust(Way way)
    {
        auto curPos = this->current_size;    // curPos points to the location of the last node in the heap
        auto max = this->array_heap[curPos]; //Save current node data
          // Curpos > 1 prevents access to position 0
        while (curPos > 1 && this->compare(max, this->array_heap[curPos / 2], way))
        {
            this->array_heap[curPos] = this->array_heap[curPos / 2]; //Filter down node
            curPos = curPos / 2;
        }
        //Insert original data into
        this->array_heap[curPos] = max;
    }

Here, in order to improve efficiency, we do not use the way of exchanging two data elements

This way of adjusting the heap is also called downward filtering node

Deletion of heap

The deletion operation is aimed at the opposite top element, that is, the root node. The deletion method we adopt is to remove the root node and put the end node on the original root node, as shown in the figure:

At this time, we find that the value of the root node is significantly smaller than that of its left and right child nodes (1 < 16,1 < 12), which does not meet the nature of a pile. At this time, we need to adjust the of the pile to make it orderly.
At this time, the adjustment method we use is different from that during insertion
This time, we will compare the value of the root node with its child nodes and adjust it downward, that is
Compare the root node with the left and right child nodes, and move the large value upward until the heap is in order (child node subscript = parent node subscript * 2)
As shown in the figure:



At this time, the heap has been adjusted

Let's look at the code implementation

//Pile out
template <typename T>
T Heap<T>::delHeap()
{
    //Determine whether the heap is empty
    if(this->empty())
    {
        return false;
    }
    //Save root node element
    auto item = this->array_heap[1];
    //Put the end element on the root node and reduce the size of the heap by one
    this->array_heap[1] = this->array_heap[this->current_size--] ;
    //Adjustment reactor
    this->adjust();
    //Returns the root node element
    return item;
}

The following is the code implementation of adjusting heap

//Adjustment reactor
template <typename T>
void Heap<T>::adjust()
{
    //Record the subscript positions of parent and child nodes
    size_t parent, child;
//Save root node element
    auto item=this->array_heap[1];
    
   for(parent=1;parent*2<this->current_size;parent=child)
   {
       child=parent*2;
       //Compare left and right node sizes
       if(child<this->current_size&&this->compare(this->array_heap[child+1],this->array_heap[child],this->flag))
       {
           ++child;
       }
       //Filter down node
        if(this->compare(this->array_heap[child],item,this->flag))
        {
            this->array_heap[parent]=this->array_heap[child];
        }
   }
   //insert data
   this->array_heap[parent]=item;
    

}

Let's test:

int main()
{

    int arr[10] = {1,3,2,5,4,6,7,9,8,10};
    Heap<int> heap1(10);
    std::cout<<"Maximum heap"<<std::endl;
    //Maximum heap
    heap1.createHeap(arr,10,Heap<int>::GREATER);
    std::cout<<"In heap element"<<std::endl;
    heap1.print();
    //delete
    heap1.delHeap();
    std::cout<<"In heap elements after deletion"<<std::endl;
    heap1.print();
    //insert
    heap1.insert(20,Heap<int>::GREATER);
     std::cout<<"In heap elements after insertion"<<std::endl;
    heap1.print();

    Heap<int>heap2(10);
    std::cout<<"Minimum heap"<<std::endl;
    //Minimum heap
    heap2.createHeap(arr,10,Heap<int>::LESS);
     std::cout<<"In heap element"<<std::endl;
    heap2.print();
    //delete
    heap2.delHeap();
    std::cout<<"In heap elements after deletion"<<std::endl;
    heap2.print();
    //insert
    heap2.insert(20,Heap<int>::LESS);
     std::cout<<"In heap elements after insertion"<<std::endl;
    heap2.print();

    return 0;
}

This is the output

Finally, this is the complete code (sub file)
Header file

#ifndef HEAP_H_
#define HEAP_H_
#include <assert.h>
#include <iostream>

template <class T>
class Heap
{

public:
    enum Way
    {
        GREATER,
        LESS
    };

private:
    T *array_heap;       //heap
    size_t current_size; //Current capacity
    size_t max_size;     //Maximum capacity
    Way flag;            //Representation of heap (large / small heap)

public:
    explicit Heap(const int &Size);
    ~Heap();
    //Output in heap data
    void print();
    //Is the heap empty
    bool empty() const;
    //Is the heap full
    bool full() const;
    //Pile out
    T delHeap();

    //insert data
    void insert(const T &Data, Way way)
    {
        if (this->full())
        {
            return;
        }
        //Insert data to the end
        this->array_heap[++this->current_size] = Data;
        //Adjustment reactor
        this->adjust(way);
    }

    //Construction pile
    void createHeap(const T *Data_Array, const size_t &Size, Way way = Heap<T>::GREATER)
    {
        this->flag = way; //Identification heap
        if (Size > this->max_size)
        {
            return;
        }
        for (auto i = 0; i < Size; ++i)
        {
            this->insert(Data_Array[i], way);
        }
    }

private:
    //less than
    bool less(const T &Left, const T &Right);
    //greater than
    bool greater(const T &Left, const T &Right);
    //compare
    bool compare(const T &Left, const T &Right, Way way);
    //Adjustment reactor
    void adjust();
    //Adjustment reactor
    void adjust(Way way)
    {
        auto curPos = this->current_size;    // curPos points to the location of the last node in the heap
        auto max = this->array_heap[curPos]; //Save current node data
                                             // Curpos > 1 prevents access to position 0
        while (curPos > 1 && this->compare(max, this->array_heap[curPos / 2], way))
        {
            this->array_heap[curPos] = this->array_heap[curPos / 2]; //Filter down node
            curPos = curPos / 2;
        }
        //Insert original data into
        this->array_heap[curPos] = max;
    }

public:
    T &operator[](const int &location);
};

template <typename T>
Heap<T>::Heap(const int &Size) : max_size(Size), current_size(0), flag(Heap<T>::GREATER)
{
    //The requested memory location 0 is not used
    this->array_heap = new T[Size + 1];
    //Whether the memory request is successful
    assert(this->array_heap);
    //Initialization data
    for (int i = 0; i < Size; ++i)
    {
        this->array_heap[i] = 0;
    }
};

template <typename T>
Heap<T>::~Heap()
{
    if (this->array_heap)
    {
        delete[] this->array_heap;
    }
    this->array_heap = nullptr;
    this->current_size = this->max_size = 0;
}

//Is the heap empty
template <typename T>
bool Heap<T>::empty() const
{
    return (this->current_size == 0);
}
//Is the heap full
template <typename T>
bool Heap<T>::full() const
{
    return (this->current_size == this->max_size + 1);
}

template <typename T>
T &Heap<T>::operator[](const int &Location)
{
    return (this->array_heap[Location]);
}

//less than
template <typename T>
bool Heap<T>::less(const T &Left, const T &Right)
{
    return (Left < Right);
}
//greater than
template <typename T>
bool Heap<T>::greater(const T &Left, const T &Right)
{
    return (Left > Right);
}

//compare
template <typename T>
bool Heap<T>::compare(const T &Left, const T &Right, Heap<T>::Way way)
{
    if (way == this->GREATER)
    {
        return this->greater(Left, Right);
    }
    else
    {
        return (this->less(Left, Right));
    }
}

//Pile out
template <typename T>
T Heap<T>::delHeap()
{
    //Determine whether the heap is empty
    if(this->empty())
    {
        return false;
    }
    //Save root node element
    auto item = this->array_heap[1];
    //Put the end element on the root node and reduce the size of the heap by one
    this->array_heap[1] = this->array_heap[this->current_size--] ;
    //Adjustment reactor
    this->adjust();
    //Returns the root node element
    return item;
}

//Adjustment reactor
template <typename T>
void Heap<T>::adjust()
{
    //Record the subscript positions of parent and child nodes
    size_t parent, child;
//Save root node element
    auto item=this->array_heap[1];
    
   for(parent=1;parent*2<this->current_size;parent=child)
   {
       child=parent*2;
       //Compare left and right node sizes
       if(child<this->current_size&&this->compare(this->array_heap[child+1],this->array_heap[child],this->flag))
       {
           ++child;
       }
       //Filter down node
        if(this->compare(this->array_heap[child],item,this->flag))
        {
            this->array_heap[parent]=this->array_heap[child];
        }
   }
   //insert data
   this->array_heap[parent]=item;
    

}

//Output in heap data
template <typename T>
void Heap<T>::print()
{
    for (auto i = 1; i <= this->current_size; ++i)
    {
        std::cout << this->array_heap[i] << ' ';
    }
    std::cout << std::endl;
}

#endif

main file

#include<iostream>
#include "heap.h"

int main()
{

    int arr[10] = {1,3,2,5,4,6,7,9,8,10};
    Heap<int> heap1(10);
    std::cout<<"Maximum heap"<<std::endl;
    //Maximum heap
    heap1.createHeap(arr,10,Heap<int>::GREATER);
    std::cout<<"In heap element"<<std::endl;
    heap1.print();
    //delete
    heap1.delHeap();
    std::cout<<"In heap elements after deletion"<<std::endl;
    heap1.print();
    //insert
    heap1.insert(20,Heap<int>::GREATER);
     std::cout<<"In heap elements after insertion"<<std::endl;
    heap1.print();

    Heap<int>heap2(10);
    std::cout<<"Minimum heap"<<std::endl;
    //Minimum heap
    heap2.createHeap(arr,10,Heap<int>::LESS);
     std::cout<<"In heap element"<<std::endl;
    heap2.print();
    //delete
    heap2.delHeap();
    std::cout<<"In heap elements after deletion"<<std::endl;
    heap2.print();
    //insert
    heap2.insert(20,Heap<int>::LESS);
     std::cout<<"In heap elements after insertion"<<std::endl;
    heap2.print();

    return 0;
}

Well, this is all the contents of the above data structure pile. I hope you like it.
If you like it, please praise it~

Keywords: C++ Algorithm data structure

Added by journy101 on Sat, 05 Mar 2022 08:19:16 +0200