堆Heap

Heap

Heap: 堆。一般也称作Priority Queue(即优先队列)

堆我们一般用一个二叉树来表示。即一个非叶子节点有至多2个子节点。

堆一般分为大堆和小堆。大堆的意思是,对任意一个非叶子节点,它的值大于它的子节点的值。此时,root(堆顶)的值是整棵树最大的值。小堆的意思刚好想法,对任意一个非叶子节点,它的值小于它的子节点的值。此时root的值是整棵树的最小值。

堆可以用来排序,也可以按优先级来存储数据。

c++中有std::priority_queue

下面是我自己的一个简单实现:

// .h
#ifndef AGORITHM_PRIORITYQUEUE_H
#define AGORITHM_PRIORITYQUEUE_H


#include <cstdint>
#include <vector>
#include <functional>

class PriorityQueue {
public:
    using ValueType = int;
    using CmpFunc = std::function<bool(ValueType, ValueType)>;

    virtual ~PriorityQueue() = default;

    explicit PriorityQueue();

    explicit PriorityQueue(uint32_t initialCap);

    explicit PriorityQueue(uint32_t initialCap, const CmpFunc &func);

    virtual void Push(int value);

    virtual int Pop();

    virtual int Top() const;

    bool Empty() const;

    uint32_t Size() const;

    bool IsLeaf(uint32_t pos);

    int DeleteNodeAt(uint32_t pos);

    ValueType ValueAt(uint32_t pos);

    static const int INITIAL_CAP = 8;

    static const int FIRST_POS = 1;

protected:
    CmpFunc GetCmpFunc() const;

    static uint32_t bubbleDown(std::vector<int> &heap, uint32_t heapSize, uint32_t position, const CmpFunc &cmpFunc);

    static int bubbleUp(std::vector<int> &heap, uint32_t root, uint32_t heapSize, uint32_t position,
                        const CmpFunc &cmpFunc);

private:
    std::vector<int> mHeap;
    CmpFunc mCmpFunc = nullptr;
    uint32_t mHeapSize = 0;
};

#endif //AGORITHM_PRIORITYQUEUE_H


// .cpp


PriorityQueue::PriorityQueue() : PriorityQueue(INITIAL_CAP, nullptr) {
}

PriorityQueue::PriorityQueue(uint32_t initialCap) : PriorityQueue(initialCap, nullptr) {
}

PriorityQueue::PriorityQueue(uint32_t initialCap, const CmpFunc &func)
        : mHeap(initialCap), mCmpFunc(func) {
    if (!mCmpFunc) {
        mCmpFunc = [](ValueType v1, ValueType v2) -> bool {
            return v1 <= v2;
        };
    }
}

void PriorityQueue::Push(int value) {
    if (mHeapSize + 1 >= mHeap.size()) {   // enlarge heap
        mHeap.resize(mHeapSize * 2);
    }
    mHeap[++mHeapSize] = value;
    bubbleUp(mHeap, FIRST_POS, mHeapSize, mHeapSize, mCmpFunc);
}

int PriorityQueue::Pop() {
    if (Empty()) {
        throw std::out_of_range("queue empty");
    }

    int value = mHeap[FIRST_POS];

    std::swap(mHeap[FIRST_POS], mHeap[mHeapSize--]);
    bubbleDown(mHeap, mHeapSize, FIRST_POS, mCmpFunc);
    return value;
}

int PriorityQueue::Top() const {
    return mHeap[FIRST_POS];
}

bool PriorityQueue::Empty() const {
    return mHeapSize == 0;
}

uint32_t PriorityQueue::bubbleDown(std::vector<int> &heap, uint32_t heapSize, uint32_t position,
                                   const CmpFunc &cmpFunc) {
    if (heapSize <= 1) {
        return heapSize;
    }

    int value = heap[position];

    uint32_t j = position;

    while (j * 2 <= heapSize) {
        uint32_t child = j * 2;
        if (child + 1 <= heapSize && cmpFunc(heap[child + 1], heap[child])) {
            child++;
        }
        if (!cmpFunc(value, heap[child])) { // value > head[child]
            std::swap(heap[j], heap[child]);
            j = child;
        } else {
            break;
        }
    }
    heap[j] = value;
    return j;
}

int PriorityQueue::bubbleUp(std::vector<int> &heap, uint32_t root, uint32_t heapSize, uint32_t position,
                            const CmpFunc &cmpFunc) {
    if (heapSize <= 1) {
        return heapSize;
    }

    int value = heap[position];

    int j = position;
    while (j / 2 >= root) {
        int parent = j / 2;
        if (cmpFunc(value, heap[parent])) {    // value < heap[parent]
            std::swap(heap[j], heap[parent]);
            j /= 2;
        } else {
            break;
        }
    }
    heap[j] = value;

    return j;
}

uint32_t PriorityQueue::Size() const {
    return mHeapSize;
}

bool PriorityQueue::IsLeaf(uint32_t pos) {
    return (pos * 2) > Size();
}

int PriorityQueue::DeleteNodeAt(uint32_t pos) {
    if (pos > Size() || pos == 0) {
        throw std::out_of_range("HeapSize: " + std::to_string(mHeapSize) + ", pos: " + std::to_string(pos));
    }

    if (pos == Size()) {
        mHeapSize--;
        return mHeap[pos];
    }

    int value = mHeap[pos];

    mHeap[pos] = mHeap[mHeapSize];
    mHeapSize--;

    bubbleDown(mHeap, mHeapSize, pos, mCmpFunc);

    return value;
}

PriorityQueue::ValueType PriorityQueue::ValueAt(uint32_t pos) {
    if (pos > Size() || pos == 0) {
        throw std::out_of_range("HeapSize: " + std::to_string(mHeapSize) + ", pos: " + std::to_string(pos));
    }
    return mHeap[pos];
}

PriorityQueue::CmpFunc PriorityQueue::GetCmpFunc() const {
    return mCmpFunc;
}

对Heap抽象一个iterator不是现实的。

下面是一个固定大小的堆。它可以用来从一列数中找出最小的n个数。存储空间是O(1)。时间复杂度是O(n)

//.h

#ifndef AGORITHM_FIXEDSIZEPRIORITYQUEUE_H
#define AGORITHM_FIXEDSIZEPRIORITYQUEUE_H


#include "PriorityQueue.h"

// FixedPriorityQueue

// insertion time: if Size() > fixedSize: O(fixedSize) else: O(log(fixedSize))

class FixedPriorityQueue : public PriorityQueue {
public:
    explicit FixedPriorityQueue(uint32_t fixedSize);

    FixedPriorityQueue(uint32_t fixedSize, const CmpFunc &func);

    void Push(int value) override;

private:
    uint32_t mFixedSize = 0;
};


#endif //AGORITHM_FIXEDSIZEPRIORITYQUEUE_H

// .cpp
#include <iostream>
#include "FixedPriorityQueue.h"

FixedPriorityQueue::FixedPriorityQueue(uint32_t fixedSize) : FixedPriorityQueue(fixedSize, nullptr) {
}

FixedPriorityQueue::FixedPriorityQueue(uint32_t fixedSize, const PriorityQueue::CmpFunc &func)
        : PriorityQueue(fixedSize + 1, func) {
    mFixedSize = fixedSize;
}

void FixedPriorityQueue::Push(int value) {
    PriorityQueue::Push(value);

    const uint32_t N = Size();
    if (N > mFixedSize) {
        auto cmp = GetCmpFunc();
        auto minValue = ValueAt(N);
        uint32_t j = N - 1;
        uint32_t minPos = j;
        for (; j >= FIRST_POS && IsLeaf(j); j--) {  // find the minimum value
            auto curr = ValueAt(j);
            if (cmp(minValue, curr)) {
                minPos = j;
                minValue = curr;
            }
        }

        if (minPos >= FIRST_POS) {
            DeleteNodeAt(minPos);
        }
    }
}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容

  • “text segment ”是应用程序运行时应用程序代码存在的内存段。每一个指令,每一个单个函数、过程、方法和执...
    紫云夕月阅读 7,286评论 4 20
  • 一:堆的介绍 Heap是一种数据结构具有以下的特点:1)完全二叉树;2)heap中存储的值是偏序; Min-hea...
    梦工厂阅读 2,350评论 2 7
  • 操作系统iOS中应用程序使用的计算机内存不是统一分配空间,运行代码使用的空间在三个不同的内存区域,分成三个段:“t...
    六月的叶子vip阅读 1,092评论 0 4
  • 优先队列(Priority Queue):特殊队列,取出元素的顺序是依照元素的优先权(关键字)大小,而不是元素进入...
    日常表白结衣阅读 890评论 0 0
  • 你的眼泪 流在往事的风里 每一滴都会折射出 一场幸福雨 在那些没有惆怅的日子里 在那开满鲜花的草地 (华晨宇:哎呀...
    浅得塾心灵文画阅读 155评论 9 6