heap 8.1 堆 - Hello 算法 (hello-algo.com)
这里使用小根堆来实现计时器。
时间堆通常用于优先队列(priority queue)的实现,其中每个元素都包含一个时间戳,并且堆的根节点总是具有最小时间戳的元素。
当剩余时间耗尽时,执行任务。
heaptimer.h 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 #ifndef HEAP_TIMER_H #define HEAP_TIMER_H #include <cstddef> #include <queue> #include <unordered_map> #include <algorithm> #include <chrono> #include <functional> #include <arpa/inet.h> #include <assert.h> #include <time.h> #include <vector> #include "../log/log.h" using TimeoutCallBack = std::function<void ()>;using Clock = std::chrono::high_resolution_clock;using MS = std::chrono::milliseconds;using TimeStamp = Clock::time_point;struct TimerNode { int id; TimeStamp expires; TimeoutCallBack cb; bool operator <(const TimerNode &t) { return expires < t.expires; } bool operator >(const TimerNode &t) { return expires > t.expires; } }; class HeapTimer {public : HeapTimer (); ~HeapTimer (); void adjust (int id, int newExpires) ; void add (int id, int timeOus, const TimeoutCallBack &cb) ; void doWork (int id) ; void clear () ; void tick () ; void pop () ; int GetNextTick () ; private : void del_ (size_t i) ; void siftup_ (size_t i) ; bool siftdown_ (size_t index, size_t n) ; void SwapNode_ (size_t i, size_t j) ; std::vector<TimerNode> heap_; std::unordered_map<int , size_t > ref_; }; #endif
heaptimer.cpp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 #include "heaptimer.h" HeapTimer::HeapTimer () { heap_.reserve (64 ); } HeapTimer::~HeapTimer () { clear (); } void HeapTimer::adjust (int id, int timeout) { assert (!heap_.empty () && ref_.count (id) > 0 ); heap_[ref_[id]].expires = Clock::now () + MS (timeout); siftdown_ (ref_[id], heap_.size ()); } void HeapTimer::add (int id, int timeOut, const TimeoutCallBack &cb) { assert (id >= 0 ); if (ref_.count (id) == 0 ) { size_t i = heap_.size (); ref_[id] = i; heap_.push_back ({id,Clock::now ()+ MS (timeOut),cb}); siftup_ (i); } else { size_t i = ref_[id]; heap_[i].expires = Clock::now () + MS (timeOut); heap_[i].cb = cb; if (!siftdown_ (i, heap_.size ())) siftup_ (i); } } void HeapTimer::doWork (int id) { if (heap_.empty () || ref_.count (id)==0 ) return ; size_t i = ref_[id]; TimerNode node = heap_[i]; node.cb (); del_ (i); } void HeapTimer::clear () { ref_.clear (); heap_.clear (); } void HeapTimer::tick () { if (heap_.empty ()) return ; while (!heap_.empty ()) { TimerNode node = heap_.front (); if (std::chrono::duration_cast <MS>(node.expires - Clock::now ()).count () > 0 ) break ; node.cb (); pop (); } } void HeapTimer::pop () { assert (!heap_.empty ()); del_ (0 ); } int HeapTimer::GetNextTick () { tick (); int res = -1 ; if (!heap_.empty ()) { res =std::chrono::duration_cast <MS>(heap_.front ().expires - Clock::now ()).count (); if (res < 0 ) { res = 0 ; } } return res; } void HeapTimer::del_ (size_t index) { assert (!heap_.empty () && index >= 0 && index< heap_.size ()); size_t i = index; size_t n = heap_.size ()- 1 ; assert (i<=n); if (i < n) { SwapNode_ (i, n); if (!siftdown_ (i, n)) { siftup_ (i); } } ref_.erase (heap_.back ().id); heap_.pop_back (); } void HeapTimer::siftup_ (size_t i) { assert (i >= 0 && i < heap_.size ()); size_t j = (i-1 )/2 ; while (j >= 0 ) { if (heap_[i] > heap_[j]) break ; SwapNode_ (i, j); i = j; j = (i-1 ) /2 ; } } bool HeapTimer::siftdown_ (size_t index, size_t n) { assert (index >= 0 && index < heap_.size ()); assert (n >= 0 && n <= heap_.size ()); size_t i = index; size_t j = 2 *i + 1 ; while (j < n) { if (j+1 < n && heap_[j+1 ] < heap_[j]) j++; if (heap_[i] < heap_[j]) break ; SwapNode_ (i,j); i = j; j = 2 *i + 1 ; } return i > index; } void HeapTimer::SwapNode_ (size_t i, size_t j) { assert (i >= 0 && i < heap_.size ()); assert (j >= 0 && j < heap_.size ()); std::swap (heap_[i],heap_[j]); ref_[heap_[i].id] = i; ref_[heap_[j].id] = j; }