最小堆c++实现

前言

恰逢春招面试时, 大厂们都会考察对基本数据结构的掌握情况。这里有一个重点就是利用数组实现堆。据说有些面试官会要求白板手写堆。虽然我们在编码过程中可以借助STL的优先队列 priority_queue 来实现堆,但是掌握其原理还是很重要滴。



堆的实现

是时候搬出当年写数据结构的代码了。这里给了一4个最小堆的例子,而最大堆的实现与此例子差不多,故此处就不赘述了。
这里的关键是 siftDown 和 siftUp 函数。

最小堆的定义

//
// Created by Dell on 2019/12/15.
//

#include <iomanip>
#include <iostream>
#include <queue>
using namespace std;
const int DefaultSize = 30;


template<class T>
class MinHeap {
public:
    MinHeap(int sz = DefaultSize);
    MinHeap(T arr[], int n);
    ~MinHeap() { delete[] heap; }
    bool Insert(const T& x);
    bool RemoveMin(T& x);
    bool IsEmpty() const;
    bool IsFull() const;
    void makeEmpty() { currentSize = 0; }
    int GetTreeDepth(int v);
    void PrintHeap();


private:
    T* heap;
    int currentSize;
    int maxHeapSize;
    void siftDown(int start, int m);
    void siftUp(int start);
};



两种构造函数

template<class T>
MinHeap<T>::MinHeap(int sz)
{
    maxHeapSize = (DefaultSize > sz) ? DefaultSize : sz;
    heap = new T[maxHeapSize];
    if (heap == 0)
    {
        cerr << "堆存储分配失败" << endl;
        exit(1);
    }
    currentSize = 0;
}


template<class T>
MinHeap<T>::MinHeap(T arr[], int n)
{
    maxHeapSize = (DefaultSize > n) ? DefaultSize : n;
    heap = new T[maxHeapSize];
    if (heap == 0)
    {
        cerr << "堆存储分配错误" << endl;
        exit(1);
    }
    for (int i = 0; i < n; i++)
        heap[i] = arr[i];
    currentSize = n;
    int currentPos = (currentSize - 2) / 2;
    while (currentPos >= 0) {
        siftDown(currentPos, currentSize - 1);
        currentPos--;
    }
}



最小堆的添加一个元素

template<class T>
bool MinHeap<T>::Insert(const T& x)
{
    if (currentSize == maxHeapSize)
    {
        cerr << "Heap Full" << endl;
        return false;
    }
    heap[currentSize] = x;
    siftUp(currentSize);
    currentSize++;
    return true;
}

其中siftUp函数的实现:

template<class T>
void MinHeap<T>::siftUp(int start)
{
    int j = start, i = (j - 1) / 2;
    T temp = heap[j];
    while (j > 0)
    {
        if (heap[i] <= temp)
            break;
        else
        {
            heap[j] = heap[i];
            j = i;
            i = (i - 1) / 2;
        }
    }
    heap[j] = temp;
}



最小堆删除一个元素

template<class T>
bool MinHeap<T>::RemoveMin(T& x)
{
    if (!currentSize)
    {
        cout << "Heap empty" << endl;
        return false;
    }
    x = heap[0];
    heap[0] = heap[currentSize - 1];
    currentSize--;
    siftDown(0, currentSize - 1);
    return true;
}

其中siftDown的实现:

template<class T>
void MinHeap<T>::siftDown(int start, int m)
{
    int i = start, j = 2 * i + 1;
    T temp = heap[i];
    while (j <= m)
    {
        if (j < m && heap[j] > heap[j + 1])
            j++;
        if (temp < heap[j])
            break;
        else
        {
            heap[i] = heap[j];
            i = j;
            j = 2 * j + 1;
        }
    }
    heap[i] = temp;
}



其他一些函数

template<class T>
bool MinHeap<T>::IsEmpty() const
{
    return currentSize == 0;
}


template<class T>
bool MinHeap<T>::IsFull() const
{
    return currentSize == maxHeapSize;
}


template<class T>
int MinHeap<T>::GetTreeDepth(int v)
{
    int depth = 0;
    while (v < currentSize)
    {
        v = 2 * v + 1;
        depth++;
    }
    return depth;
}


template<class T>
void MinHeap<T>::PrintHeap()
{
    int IsEven= 1;
    queue<int> Q;
    int v;
    Q.push(0);
    while (!Q.empty())
    {
        IsEven = 1;
        int width = Q.size();
        for (int i = 0; i < width; i++)
        {
            v = Q.front();
            Q.pop();
            IsEven = (IsEven+1) % 2;
            cout << setw(4) << heap[v];
            if (IsEven && i != width - 1)
                cout << " , ";
            if (2 * v + 1 < currentSize)
                Q.push(2 * v + 1);
            if (2 * v + 2 < currentSize)
                Q.push(2 * v + 2);
        }
        cout << endl;
    }
    cout << endl << endl << endl;
}

完整代码

//
// Created by Dell on 2019/12/15.
//

#include <iomanip>
#include <iostream>
#include <queue>
using namespace std;
const int DefaultSize = 30;


template<class T>
class MinHeap {
public:
    MinHeap(int sz = DefaultSize);
    MinHeap(T arr[], int n);
    ~MinHeap() { delete[] heap; }
    bool Insert(const T& x);
    bool RemoveMin(T& x);
    bool IsEmpty() const;
    bool IsFull() const;
    void makeEmpty() { currentSize = 0; }
    int GetTreeDepth(int v);
    void PrintHeap();


private:
    T* heap;
    int currentSize;
    int maxHeapSize;
    void siftDown(int start, int m);
    void siftUp(int start);
};


template<class T>
MinHeap<T>::MinHeap(int sz)
{
    maxHeapSize = (DefaultSize > sz) ? DefaultSize : sz;
    heap = new T[maxHeapSize];
    if (heap == 0)
    {
        cerr << "堆存储分配失败" << endl;
        exit(1);
    }
    currentSize = 0;
}


template<class T>
MinHeap<T>::MinHeap(T arr[], int n)
{
    maxHeapSize = (DefaultSize > n) ? DefaultSize : n;
    heap = new T[maxHeapSize];
    if (heap == 0)
    {
        cerr << "堆存储分配错误" << endl;
        exit(1);
    }
    for (int i = 0; i < n; i++)
        heap[i] = arr[i];
    currentSize = n;
    int currentPos = (currentSize - 2) / 2;
    while (currentPos >= 0) {
        siftDown(currentPos, currentSize - 1);
        currentPos--;
    }
}


template<class T>
void MinHeap<T>::siftDown(int start, int m)
{
    int i = start, j = 2 * i + 1;
    T temp = heap[i];
    while (j <= m)
    {
        if (j < m && heap[j] > heap[j + 1])
            j++;
        if (temp < heap[j])
            break;
        else
        {
            heap[i] = heap[j];
            i = j;
            j = 2 * j + 1;
        }
    }
    heap[i] = temp;
}


template<class T>
void MinHeap<T>::siftUp(int start)
{
    int j = start, i = (j - 1) / 2;
    T temp = heap[j];
    while (j > 0)
    {
        if (heap[i] <= temp)
            break;
        else
        {
            heap[j] = heap[i];
            j = i;
            i = (i - 1) / 2;
        }
    }
    heap[j] = temp;
}


template<class T>
bool MinHeap<T>::Insert(const T& x)
{
    if (currentSize == maxHeapSize)
    {
        cerr << "Heap Full" << endl;
        return false;
    }
    heap[currentSize] = x;
    siftUp(currentSize);
    currentSize++;
    return true;
}




template<class T>
bool MinHeap<T>::RemoveMin(T& x)
{
    if (!currentSize)
    {
        cout << "Heap empty" << endl;
        return false;
    }
    x = heap[0];
    heap[0] = heap[currentSize - 1];
    currentSize--;
    siftDown(0, currentSize - 1);
    return true;
}





template<class T>
bool MinHeap<T>::IsEmpty() const
{
    return currentSize == 0;
}







template<class T>
bool MinHeap<T>::IsFull() const
{
    return currentSize == maxHeapSize;
}





template<class T>
int MinHeap<T>::GetTreeDepth(int v)
{
    int depth = 0;
    while (v < currentSize)
    {
        v = 2 * v + 1;
        depth++;
    }
    return depth;
}

template<class T>
void MinHeap<T>::PrintHeap()
{
    int IsEven= 1;
    queue<int> Q;
    int v;
    Q.push(0);
    while (!Q.empty())
    {
        IsEven = 1;
        int width = Q.size();
        for (int i = 0; i < width; i++)
        {
            v = Q.front();
            Q.pop();
            IsEven = (IsEven+1) % 2;
            cout << setw(4) << heap[v];
            if (IsEven && i != width - 1)
                cout << " , ";
            if (2 * v + 1 < currentSize)
                Q.push(2 * v + 1);
            if (2 * v + 2 < currentSize)
                Q.push(2 * v + 2);
        }
        cout << endl;
    }
    cout << endl << endl << endl;
}



int main()
{
    MinHeap<int> a;

    a.Insert(53);
    //a.PrintHeap();
    a.Insert(65);
    //a.PrintHeap();
    a.Insert(27);
    //a.PrintHeap();
    a.Insert(56);
    //a.PrintHeap();
    a.Insert(39);
    //a.PrintHeap();
    a.Insert(58);
    //a.PrintHeap();
    a.Insert(100);
    //a.PrintHeap();
    a.Insert(18);
    a.PrintHeap();
    a.Insert(569);
    a.Insert(47);
    a.Insert(93);
    a.Insert(24);
    a.Insert(66);
    a.Insert(78);
    a.Insert(134);
    a.PrintHeap();


    cout << endl;
}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值