Since I had time, I would do this using a set and a list. The list simply keeps track of the last n items inserted. Also implemented a general deletion. To improve performance (if you are not using the fact that the set is ordered), you can use unordered_set. (replace include <set> with include <unordered_set> , and also std::set with std::unordered_set )
#include <set> #include <list> #include <assert.h> template<typename T> struct setkeepn { std::set<T> mSet; std::list<T> mLast; void insert(T element) { if (mSet.find(element) == mSet.end()) { assert(mSet.size() == mLast.size()); // put your limit of 30 below if (mSet.size() >= 2) { T extra = mLast.back(); mSet.erase(extra); mLast.pop_back(); } mSet.insert(element); mLast.push_front(element); } } void erase(T element) { typename std::set<T>::iterator lToEraseFromSet = mSet.find(element); if (lToEraseFromSet != mSet.end()) { // linear on the number of elements. typename std::list<T>::iterator lToEraseFromList = std::find(mLast.begin(),mLast.end(), element); assert(lToEraseFromList != mLast.end()); mSet.erase(lToEraseFromSet); mLast.erase(lToEraseFromList); } } }; int main(int argc, const char * argv[]) { setkeepn<int> lTest; lTest.insert(1); lTest.insert(2); lTest.insert(2); lTest.insert(3); printf("should see 2 3\n"); for (auto e : lTest.mSet) { // 2,3 printf("elements: %d\n",e); } lTest.insert(4); lTest.erase(3); printf("should see 4\n"); for (auto e : lTest.mSet) { // 4 printf("elements: %d\n",e); } return 0; }
result:
should see 2 3 elements: 2 elements: 3 should see 4 elements: 4
source share