一、堆的基本概念
【含义】:如果有一个关键码的集合K={k0,k1,k2, … ,k(n-1)},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:ki <= k2*i+1 且 ki <= k2*i+2(ki >= k2*i+1 且 ki >= k2*i+2 )i=0,1,2 … ,则称这个堆为最小堆(或最大堆)。
【最小堆】:任一节点的关键码均小于等于它的左右孩子的关键码,位于堆顶节点的关键码最小。
【最大堆】:任一节点的关键码均大小于等于它的左右孩子的关键码,位于堆顶节点的关键码最大。
【堆序】:在堆中,所有的记录具有称之为堆序的关系。
【堆的规律】:
- 具有最小堆序的节点(除没有孩子的节点)之间存在小于或等于关系,从根节点到每个节点的路径上数组元素组成的序列都是递增的。
- 具有最大堆序的节点(除没有孩子的节点)之间存在大于或等于关系,从根节点到每个节点的路径上数组元素组成的序列都是递减的。
堆存储在下标为0开始计数的数组中,因此在堆中给定下标为i的节点时:
- 如果i=0,节点i是根节点,没有双亲节点;否则节点i的双亲节点为节点(i-1)/2;
- 如果2*i+1 > n-1,则节点i无左孩子,否则节点i的左孩子为节点2*i+1;
- 如果2*i+2 > n-1,则节点i无右孩子,否则节点i的右孩子为节点2*i+2;
二、堆的创建&插入&删除
源码:
Heap.h
#pragma once
#ifndef __HEAP_H__
#define __HEAP_H__
#include<iostream>
#include<vector>
using namespace std;
template<class T>
class Less
{
public:
bool operator()(T& left, T& right){
return left < right;
}
};
template<class T>
class Greater
{
public:
bool operator()(T& left, T& right){
return left>right;
}
};
template<class T,class Compare = Greater<T>>
class Heap
{
public:
//无参构造
Heap()
{}
//带参构造
Heap(T* arr, const T size){
_v.reserve(size);
for (int i = 0; i < size; ++i){
_v.push_back(arr[i]);
}
//建堆
for (int j = (_v.size() - 2) >> 1; j >= 0; --j){
//向下调整
_AdjustDown(j);
}
}
void Push(const T& data){
_v.push_back(data);
_AdjustUp(_v.size() - 1);
}
void Pop(){
//交换堆顶元素与堆底元素
size_t size = _v.size();
swap(_v[0], _v[size - 1]);
//删除堆底元素
_v.pop_back();
//向下调整
_AdjustDown(0);
}
size_t Size(){
return _v.size();
}
bool Empty(){
return _v.empty();
}
//打印堆
void Print(){
for (size_t i = 0; i < _v.size(); ++i){
cout << _v[i] << " ";
}
cout << endl;
}
T Top()const
{
return _v.front();
}
T Back()const
{
return _v.back();
}
//析构
~Heap(){
_v.~vector();
}
protected:
//向下调整
void _AdjustDown(size_t root){
size_t parent = root;
size_t min_child = parent * 2 + 1;
while (min_child < _v.size()){
if ((min_child + 1 < _v.size()) && (Compare()(_v[min_child + 1],_v[min_child])))
min_child += 1;
if (Compare()(_v[min_child],_v[parent])){
swap(_v[parent], _v[min_child]);
parent = min_child;
min_child = parent * 2 + 1;
}
else{
break;
}
}
}
//向上调整
void _AdjustUp(size_t index){
size_t child = index;
size_t parent = (child - 1) >> 1;
while (child){
if (Compare()(_v[parent],_v[child])){
break;
}
else{
swap(_v[parent], _v[child]);
child = parent;
parent = (child - 1) >> 1;
}
}
}
private:
vector<T> _v;
};
#endif //__HEAP_H__
test.cpp
#include"Heap.h"
#include<iostream>
#include<stdio.h>
#include<Windows.h>
using namespace std;
void test(){
int arr[] = { 53, 17, 78, 9, 45, 65, 87, 23 };
Heap<int,Less<int>> hp(arr, sizeof(arr) / sizeof(arr[0]));
//此处传的是小堆Less<int>,若要大堆可传Greater<int>
hp.Push(80);
hp.Pop();
cout << hp.Size() << endl;
cout << hp.Front() << endl;
cout << hp.Back() << endl;
}
int main(){
test();
system("pause");
return 0;
}
程序运行结果:
【说明】:测试例子用的是小堆,大堆同理。
建堆:
插入元素:
删除元素:
堆元素的个数&堆头元素&堆尾元素
三、堆的应用:
优先级队列:
topK(海量数据处理):