公司的LRU过于简单,我自己写了一个,需要自己写堆。 // Author: johnhall@126.com // Description: #ifndef LRUCACHE_H_ #define LRUCACHE_H_ #include <vector> #include "util/hash_tables.h" namespace crawl { template <class KeyType, class ValType, class CMP_FUNCTOR=std::less<ValType> > class LRUCache { protected: struct EntryType { KeyType k; ValType v; int heap_pos; EntryType():heap_pos(-1) {} EntryType(KeyType _k, ValType _v, int _heap_pos): k(_k),v(_v),heap_pos(_heap_pos) {} }; typedef std::vector<EntryType*> HeapType; typedef base::hash_map<KeyType, EntryType*> MapType; typedef typename base::hash_map<KeyType, EntryType*>::const_iterator MapItrType; public: LRUCache() {} ~LRUCache() { // not virtual, so only appropriate to use it in terms of "combination" Clear(); } // get non-modifiable elem reference bool GetConstEntry(KeyType k, ValType* v) const { MapItrType itr = map_.find(k); if (itr == map_.end()) { return false; } *v = (itr->second)->v; return true; } // get element count const size_t Count() const { return heap_.size(); } bool IsEmpty() const { return Count() == 0; } // pop specified-key entry bool PopEntry(KeyType k, ValType* v) { // find in hash, get pos in the heap MapItrType itr = map_.find(k); if (itr == map_.end()) { return false; } *v = (itr->second)->v; PopEntry(itr); return true; } // pop the least recent use entry void PopLRUEntry(KeyType* k, ValType* v) { assert(!IsEmpty()); *k = (heap_[0])->k; *v = (heap_[0])->v; MapItrType itr = map_.find(*k); delete itr->second; map_.erase(*k); heap_[0]->heap_pos = Count() - 1; heap_[Count() - 1]->heap_pos = 0; std::swap(heap_[0], heap_[Count() - 1]); heap_.pop_back(); adjust_heap(0); } // push entry into cache void PushEntry(KeyType k, ValType v) { // if the elem with the key exist, pop it, change value, push it again MapItrType itr = map_.find(k); EntryType* entry = new EntryType(k, v, Count()); if (itr != map_.end()) { PopEntry(itr); } map_[k] = entry; heap_.push_back(entry); adjust_heap_from_bottom(); } void Clear() { // delete data first for (int i = 0; i < heap_.size(); ++i) { delete heap_[i]; } heap_.clear(); map_.clear(); } protected: HeapType heap_; MapType map_; void PopEntry(MapItrType itr) { // erase in hash map int pos = (itr->second)->heap_pos; map_.erase(itr->first); // delete original data delete itr->second; // swap the one with the last one in the heap, then erase in the heap // then adjust in the sub heap heap_[pos]->heap_pos = Count() - 1; heap_[Count() - 1]->heap_pos = pos; std::swap(heap_[pos], heap_[Count() - 1]); heap_.pop_back(); adjust_heap(pos); } void adjust_heap(int pos) { // only need to change heap pos additionally int count = Count(); CMP_FUNCTOR func; EntryType* pivot = heap_[pos]; for (int tocmp = pos * 2 + 1; tocmp < count; pos = tocmp, tocmp *= 2, ++tocmp) { if (tocmp + 1 < count && func(heap_[tocmp + 1]->v, heap_[tocmp]->v)) { ++tocmp; } if (func(pivot->v, heap_[tocmp]->v)) { break; } heap_[pos] = heap_[tocmp]; heap_[pos]->heap_pos = pos; } heap_[pos] = pivot; pivot->heap_pos = pos; } void adjust_heap_from_bottom() { // only need to change heap pos additionally CMP_FUNCTOR func; int pos = Count() - 1; EntryType* pivot = heap_[pos]; for (int parent = (pos - 1) / 2; pos > 0 && func(pivot->v, heap_[parent]->v); pos = parent, --parent, parent /= 2) { heap_[pos] = heap_[parent]; heap_[pos]->heap_pos = pos; } heap_[pos] = pivot; pivot->heap_pos = pos; } private: DISALLOW_COPY_AND_ASSIGN(LRUCache); }; } // namespace crawl #endif // LRUCACHE_H_ 测试输入如下: # TESTCASE 1 PUSH 3 -3 PUSH 7 -7 PUSH 1 -1 PUSH 2 -2 PUSH 6 -6 PUSH 8 -8 PUSH 11 -5 PUSH 13 -9 # 此时堆中的(v,k)对为: # (-9,13) # (-8,8) (-7,7) # (-6,6) (-3, 3) (-1,1) (-5,11) # (-2,2) ADD 6 -3 ADD 2 3 POPLRU SIZE ADD 2 -5 # 此时堆中的(v,k)对为: # (-9,6) # (-8,8) (-7,7) # (-5,11) (-3,3) (-1,1) (-4,2) PUSH 7 7 PUSH 5 -4 PUSH 11 -7 PUSH 12 6 PUSH 13 4 PUSH 14 3 PUSH 15 0 POP 1 PUSH 1 -2 POP 2 PUSH 2 -3 POP 3 PUSH 3 -3 PUSH 6 -6 # 此时堆中的(v,k)对为: # (-8,8) # (-7,11) (-6,6) # (-4,5) (0,15) (-3,2) (7,7) # (-2,1) (6,12) (4,13) (3,14) (-3,3) POPLRU POPLRU POPLRU PUSH 8 -4 POPLRU POPLRU POPLRU POPLRU POPLRU SIZE # 此时堆中的(v,k)对为: # (0,15) # (4,13) (3,14) # (6,12) (7,7) CLEAR 输出: # TESTCASE 1 PUSH PUSH PUSH PUSH PUSH PUSH PUSH PUSH TRUE -6 TRUE -2 13 -9 7 TRUE 1 PUSH PUSH PUSH PUSH PUSH PUSH PUSH TRUE -1 PUSH TRUE -4 PUSH TRUE -3 PUSH PUSH 8 -8 11 -7 6 -6 PUSH 5 -4 8 -4 3 -3 2 -3 1 -2 5 Done 没有作bench mark。