简体   繁体   English

限制std :: set的大小

[英]limit the size of a std::set

I have a short question about the std::set container. 我有一个关于std :: set容器的简短问题。 Right now I am feeding my set using the pushback function. 现在我正在使用pushback功能来提供我的设置。 Of corse the set becomes larger and larger for every push_back. 对于每个push_back,该集合变得越来越大。 I am only intrested in the latest 30 elements or so... The older elements can be deleted. 我只对最新的30个元素感兴趣......可以删除旧元素。 So my idea is to limit the size of the set to 30 elements or so and by doing so getting rid of the unwanted older elements. 所以我的想法是将集合的大小限制为30个元素左右,并通过这样做摆脱不需要的旧元素。 However the set does not support a limit by default. 但是,默认情况下,该集不支持限制。 I could check the size of the set once in a while and manually delet the excess elements. 我可以偶尔检查一下这个集的大小,然后手动删除多余的元素。 Is there a smarter way ? 有更聪明的方法吗?

Regards Lumpi 关心Lumpi

作为一种解决方案,您可以将set数据结构封装到一个类中,并在该类中控制元素计数。

You'll need to build a LRU structure yourself. 您需要自己构建一个LRU结构。 One way to do this would be to have a std::map and std::list pointing to each other's iterators. 一种方法是使std :: map和std :: list指向彼此的迭代器。 That is: 那是:

struct lru_entry {
    std::list<lru_entry *>::iterator lru_iterator;
    std::map<your_data, lru_entry *>::iterator map_iterator;
};

std::list<lru_entry *> lru;
std::map<your_data, lru_entry *> lookup;

Whenever you look up an entry in the map, move its associated list entry to the start of the list. 每当您在地图中查找条目时,将其关联的列表条目移动到列表的开头。 When adding an entry to the map, create a new lru_entry, add it to both map and list, and update the iterators in the lru_entry structure. 向地图添加条目时,创建一个新的lru_entry,将其添加到map和list中,并更新lru_entry结构中的迭代器。 When the lookup map exceeds 30 entries, you can then use the lru list to quickly find the oldest entry. 当查找映射超过30个条目时,您可以使用lru列表快速查找最旧的条目。

You can find more suggestions on how to build a LRU list in this previous stackoverflow question. 您可以在此前的stackoverflow问题中找到有关如何构建LRU列表的更多建议

The set not only does not support a limit, it also does not tell you the age of the element. 该集合不仅不支持限制,它也不会告诉您元素的年龄。 Create a new class that encapsulates a container. 创建一个封装容器的新类。 That class can then provide methods to enforce the size limit when adding elements or explicitly. 然后,该类可以提供在添加元素时或显式地强制执行大小限制的方法。 A queue would be ideal if removing is done based on when the element was added (it is optimized for operations at both ends). 如果基于添加元素的时间进行删除(它针对两端的操作进行了优化),则队列将是理想的。

Since I had the time, I would do it using a set and a list. 由于我有时间,我会使用集合和列表来完成。 The list just keep track of the last n inserted elements. 该列表只跟踪最后n个插入的元素。 Also implemented a general erase. 还实现了一般擦除。 For better performance (if you are not taking advantage of the fact that set is ordered) you may consider using unordered_set. 为了获得更好的性能(如果您没有利用已订购集合的事实),您可以考虑使用unordered_set。 (replace include <set> with include <unordered_set> as well as std::set with std::unordered_set ) (用include <unordered_set>替换include <set>以及用std::unordered_set替换std::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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM