概念
满二叉树: 所有的层节点数都是该层所能容纳节点的最⼤数量(满足
2
n
2^n
2n;
n
>
=
0
n > =0
n>=0) ;
完全二叉树: 若⼆叉树的深度为 h ,除了 h 层外,其他层的节点数都是该层所能容纳节点的最⼤数量(满⾜ ),且 h 层都集中在最左侧;
最小堆:
- 是一颗完全二叉树;
- 某一个节点的值总是小于等于它的子节点的值;
- 堆中每个节点的子树都是最小堆;
增加操作
为了满⾜完全⼆叉树定义,往⼆叉树最⾼层沿着最左侧添加⼀个节点;然后考虑是否能上升操作;如果此时添加值为 4 的节点, 4 节点是5节点的左⼦树; 4 ⽐ 5 ⼩, 4 和 5 需要交换位置;
删除操作
删除操作需要先查找是否包含这个节点,最⼩堆的查找效率是
O
(
n
)
O(n)
O(n); 查找之后,交换最后一个节点,先考虑下降操作,如果操作失败则上升操作; 最后删除最后一个节点;
例如:假设删除 1 号节点,则需要下沉操作;假设删除 9 号节点,则需要上升操作;
//minheap.h
#pragma once
#include <vector>
#include <map>
using namespace std;
typedef void (*TimerHandler) (struct TimerNode *node);
struct TimerNode {
int idx = 0;
int id = 0;
unsigned int expire = 0;
TimerHandler cb = NULL;
};
class MinHeapTimer {
public:
MinHeapTimer() {
_heap.clear();
_map.clear();
}
static inline int Count() {
return ++_count;
}
int AddTimer(uint32_t expire, TimerHandler cb);
bool DelTimer(int id);
void ExpireTimer();
private:
inline bool _lessThan(int lhs, int rhs) {
return _heap[lhs]->expire < _heap[rhs]->expire;
}
bool _shiftDown(int pos);
void _shiftUp(int pos);
void _delNode(TimerNode *node);
private:
vector<TimerNode*> _heap; //最小堆的元素使用vector来存储
map<int, TimerNode*>_map; //使用map来进行查找 提高效率
static int _count;
};
int MinHeapTimer::_count = 0;
//minheap.cpp
#include <unistd.h>
#include <time.h>
#include <iostream>
#include "minheap.h"
#include <sys/time.h>
static uint32_t current_time() { //获取当前时间
uint32_t t;
struct timespec ti;
clock_gettime(CLOCK_MONOTONIC, &ti);
t = (uint32_t)ti.tv_sec * 1000;
t += ti.tv_nsec / 1000000;
return t;
}
int MinHeapTimer::AddTimer(uint32_t expire, TimerHandler cb) { //添加定时器 和callback函数
int64_t timeout = current_time() + expire;
TimerNode *node = new TimerNode;
int id = Count(); //添加一个node id就+1
node->id = id;
node->expire = timeout;
node->cb = cb;
node->idx = (int)_heap.size(); //元素在heap的位置
_heap.push_back(node);
_shiftUp((int)(_heap.size() - 1)); //因为插入元素是放在最后一个位置上,所以要进行上升处理
_map.insert(make_pair(id, node)); //同时map进行记录
return id;
}
bool MinHeapTimer::DelTimer(int id) { //删除一个定时器操作
auto iter = _map.find(id);
if(iter == _map.end()) return false;
_delNode(iter->second); //查找到之后删除node
return true;
}
void MinHeapTimer::_delNode(TimerNode *node) { //删除一个节点
int last = (int)_heap.size() - 1; // 删除节点的时候需要和堆中的最后一个节点进行交换
int idx = node->idx;
if(idx != last) {
std::swap(_heap[idx], _heap[last]);
_heap[idx]->idx = idx;
if(!_shiftDown(idx)) //交换完 先进行下沉操作, 下沉失败 在上升处理
_shiftUp(idx);
}
_heap.pop_back();
_map.erase(node->id);
delete node;
}
void MinHeapTimer::ExpireTimer() {
if (_heap.empty()) return;
uint32_t now = current_time();
do{
TimerNode* node = _heap.front();
if( now < node->expire) break;
for(int i =0; i < _heap.size(); i++) { //遍历哪个节点是否到期
std::cout << "touch.....idx: " << _heap[i]->idx
<< " id: " << _heap[i]->id << " expire: "
<< _heap[i]->expire << std::endl;
}
if(node->cb) node->cb(node);
_delNode(node);
}while(!_heap.empty());
}
bool MinHeapTimer::_shiftDown(int pos) { //下沉操作
int last = (int)_heap.size() - 1;
int idx = pos;
for(;;) {
int left = 2 * idx + 1; //左儿子的pos
if((left >= last) || (left < 0)) break;
int min = left;
int right = left + 1; //右儿子
if(right < last && !_lessThan(left, right)){ //查询左右两个儿子的最小值
min = right;
}
if(!_lessThan(min, idx)) //如果idx就是最小的,则不需要交换
break;
std::swap(_heap[idx], _heap[min]);
_heap[idx]->idx = idx;
_heap[min]->idx = min;
idx = min;
}
return idx > pos;
}
void MinHeapTimer::_shiftUp(int pos) //上升操作 和下沉同理
{
for (;;) {
int parent = (pos - 1) / 2; // parent node
if (parent == pos || !_lessThan(pos, parent)) {
break;
}
std::swap(_heap[parent], _heap[pos]);
_heap[parent]->idx = parent;
_heap[pos]->idx = pos;
pos = parent;
}
}
void print_hello(TimerNode *te) {
std::cout << "hello world time = " << te->idx << "\t" << te->id << std::endl;
}
int main() {
MinHeapTimer mht;
mht.AddTimer(0, print_hello);
mht.AddTimer(1000, print_hello);
mht.AddTimer(7000, print_hello);
mht.AddTimer(2000, print_hello);
mht.AddTimer(9000, print_hello);
mht.AddTimer(10000, print_hello);
mht.AddTimer(6000, print_hello);
mht.AddTimer(3000, print_hello);
for (;;) {
mht.ExpireTimer();
usleep(10000);
}
return 0;
}