1. 程式人生 > >C++實現最大堆和最小堆

C++實現最大堆和最小堆

堆資料結構是一種陣列物件,它可以被視為一顆完全二叉樹結構(或者也有可能是滿二叉樹)

最大堆:

任一結點的關鍵碼均大於等於它的左右孩子的關鍵碼,其中堆頂的元素最大。(任一路徑中的元素升序排列)

最小堆:

任一結點的關鍵碼均小於等於它的左右孩子的關鍵碼,其中堆頂的元素最小。(任一路徑中的元素升序排列)

已知父節點:

左孩子節點 = 2*父節點+1
右孩子節點 = 2*父節點+2

已知孩子節點:

父節點 = (孩子節點-1)/ 2

堆的應用

  1. 優先順序佇列
  2. 堆排序
  3. 100W個數中找出最大(最小)的前K個數

最大堆和最小堆的實現

Heap.h

#pragma once
#include<iostream>
#include<assert.h>
#include<vector>
using namespace std;

template<class T>
struct Less
{
    bool operator()(const T& left, const T& right) const
    {
        return left < right;
    }
};

template<class T>
struct Greater
{
    bool
operator()(const T& left, const T& right) const { return left > right; } }; template<class T, class Compare=Less<T>> class Heap { public: Heap()//無參的建構函式(系統不會給無參建構函式),開始堆是空的不需要做什麼事 {} Heap(T* a, size_t n) { _a.reserve(n);//開空間 for
(size_t i = 0; i < n; ++i) { _a.push_back(a[i]); } //建堆,找最後一個非葉子節點 for (int i = (_a.size() - 2) / 2; i >= 0; --i)//不用size_t,因為i在這可能等於0,用size_t會死迴圈 { AdjustDown(i); } } //向下調整 void AdjustDown(int root) { Compare com; int parent = root; size_t child = parent * 2 + 1;//預設為左孩子 while (child < _a.size()) { //選出小孩子 //if (child+1 > _a.size() && _a[child + 1]< _a[child]) if (child + 1 < _a.size() && com(_a[child + 1], _a[child])) { ++child; } //if (_a[child] < _a[parent]) if (com(_a[child], _a[parent])) { swap(_a[child], _a[parent]);//交換值 parent = child; child = parent * 2 + 1; } else { break; } } } //向上調整 void AdjustUp(int child) { Compare com; int parent = (child - 1) / 2; while (parent >= 0) { //if (_a[child] < _a[parent]) if (com(_a[child], _a[parent])) { swap(_a[parent], _a[child]); child = parent; parent = (child - 1) / 2; } else { break; } } } //最後插入 void Push(const T&x) { _a.push_back(x); AdjustUp(_a.size() - 1); } //刪除最大數 void Pop() { assert(!_a.empty()); swap(_a[0], _a[_a.size() - 1]); _a.pop_back(); AdjustDown(0); } //取頂元素 T& Top() { assert(!_a.empty()); return _a[0]; } size_t Size() { return _a.size(); } bool Empty() { return _a.empty(); } private: vector<T> _a; };

test.cpp

#include <iostream>
#include "Heap.h"
using namespace std;

int main()
{
    int a[] = {10,11,13,12,16,18,15,17,14,19};
    // Heap<int,Greater<int>> hp1(a,sizeof(a)/sizeof(a[0])); 最大堆
    // Heap<int,Less<int>> hp1(a,sizeof(a)/sizeof(a[0])); 最小堆
    Heap<int> hp1(a,sizeof(a)/sizeof(a[0])); // 預設,最小堆
    hp1.Push(15);
    return 0;
}

執行結果:

測試最大堆:

這裡寫圖片描述

測試最小堆:

這裡寫圖片描述