【问题标题】:optimizing searching through memory优化内存搜索
【发布时间】:2014-11-20 20:26:20
【问题描述】:

我有 4096 个项目的多个实例。我需要定期搜索并找到一个项目,我想对其进行优化。由于并非所有 4096 项都可以使用,我认为,加快速度的一种方法是使用链表而不是数组。每当我必须搜索一个项目时,一旦找到它,我就会将它放在列表的顶部,这样下次它出现时,我只需要做最少的搜索(循环)工作。这听起来对吗?

EDIT1 我不认为二叉搜索树的想法真的是我可以使用的,因为我已经订购了数据,就像一个数组,即前一个节点之后的每个节点都更大,这违背了目的,不是吗?

我试图解决我的缓存问题并想出了这样的事情:

pending edit

但我得到的输出表明它不像我希望的那样工作:

关于如何改进这一点有什么建议吗?

【问题讨论】:

标签: arrays performance loops optimization linked-list


【解决方案1】:

在性能方面,只有一条重要规则:衡量它!

在您的情况下,您可以有两个不同的考虑因素,一个理论运行时分析和一台机器上的实际情况。两者都在很大程度上取决于您的 4096 项目的特性。如果您的数据已排序,则可以进行 O(log n) 搜索,如果未排序,则最坏情况为 O(n) 等。

关于您对链表的想法,您可能会有更多的硬件缓存未命中,因为数据不再存储在一起(空间局部性),即使您的理论考虑是正确的,最终也会导致实现速度变慢。

如果您对此类问题感兴趣,我推荐 GoingNative 2013 的这个很酷的演讲 http://channel9.msdn.com/Events/GoingNative/2013/Writing-Quick-Code-in-Cpp-Quickly

【讨论】:

    【解决方案2】:

    在最坏的情况下,除非您像 Brett 建议的那样对数组或列表进行排序,否则您的搜索仍然是 O(N)。因此,使用排序列表会增加插入的复杂性(插入有序),但搜索速度会快得多。您的建议几乎就像“缓存”。如果不知道在短期内再次搜索找到的项目的频率,我们很难说这会有多大用处。显然,缓存有好处,这就是为什么我们在内存中拥有整个 L1、L2、L3 架构的原因。但它是否对你有用还不确定。

    【讨论】:

    • 请参阅上面的EDIT1
    【解决方案3】:

    如果你的数据可以放入二叉搜索树:http://en.wikipedia.org/wiki/Binary_search_tree

    然后您可以使用一种称为 Splay 树的数据结构:“Splay 树是一种自我调整的二叉搜索树,具有最近访问的元素可以快速再次访问的附加属性”http://en.wikipedia.org/wiki/Splay_tree

    【讨论】:

    • 请参阅上面的 EDIT1
    【解决方案4】:

    回复 Edit1: 我认为如果您的数据元素不大,例如只有几个字节甚至几十个字节,则可以将其中的 4096 个放入内存中。在这种情况下,您需要的是一个哈希表。在 C++ 中,您使用 unordered_map。例如,您可以定义unorderedmap<int, ptr_to_your_node_type>,如果您的键类型为int,则可以获取O(1) 中的元素。

    如果你能很好地设计你的哈希,最快的搜索可能是O(1),最坏的情况可能是O(n)。如果这些项目很大并且无法放入内存中,您可以使用所谓的最近最少使用缓存algorithm 来节省内存。

    LRU 缓存的示例代码

    template <typename K>
    class Key_Age{
    list<K> key_list;
    unordered_map<K, typename list<K> :: iterator> key_pos;
    public:
    void access(K key){
        key_list.erase(key_pos[key]);
        insert_new(key);
    }
    
    void insert_new(K key){
        key_list.push_back(key);
        key_pos[key] = --key_list.end();
    }
    
    K pop_oldest(){
        K t = key_list.front();
        key_list.pop_front();
        return t;
    }
    };
    
    class LRU_Cache{
    int capacity;
    Key_Age<int> key_age;
    unordered_map<int, int> lru_cache;
    
    public:
    LRU_Cache(int capacity): capacity(capacity) {
    }
    
    int get(int key) {
        if (lru_cache.find(key) != lru_cache.end()) {
            key_age.access(key);
            return lru_cache[key];
        }
        return -1;
    }
    
    void set(int key, int value) {
        if (lru_cache.count(key) < 1) {
            if (lru_cache.size() == capacity) {
                int oldest_key = key_age.pop_oldest();
                lru_cache.erase(oldest_key);
            }
            key_age.insert_new(key);
            lru_cache[key] = value;
            return;
        }
    
        key_age.access(key);
        lru_cache[key] = value;
    }
    

    };

    【讨论】:

    • 请参阅上面的EDIT1
    猜你喜欢
    • 2013-11-05
    • 2014-09-01
    • 1970-01-01
    • 2020-10-20
    • 2012-05-05
    • 1970-01-01
    • 2015-07-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多