更高效的数据结构

时间:2014-10-26 13:07:57

标签: c++ list data-structures

我正在开发一个项目,我需要在列表中的对象和插入之间进行大量的比较。
基本上我有一个Board类型的对象,我执行以下操作:

if(!(seenStates.contains(children[i])))
{
    statesToExpand.addToListOrderly(children[i]);

    seenStates.insertHead(children[i]);
}

其中statesToExpand和seenStates是我用这种方式定义的两个列表:

typedef struct t_Node
{
    Board *board;
    int distanceToGoal;
    t_Node *next;
} m_Node;

typedef m_Node* m_List;

class ListOfStates {
...

一切正常但我做了一些分析,发现几乎99%的时间用于操作这些列表,因为我必须扩展,比较,插入等近20000个州。

我的问题是:我是否可以使用更有效的数据结构来减少该部分代码的执行时间?

更新

所以我尝试使用std::vector并且它有点糟糕(使用我的旧列表15秒而不是13秒)。可能我做错了...通过一些更多的分析,我发现在向量中搜索元素花了大约13.5秒。这是我正在使用的代码:

bool Game::vectorContains(Board &b)
{
    clock_t stop;
    clock_t start = clock();
    if(seenStates.size() == 0)
    {
        stop = clock();
        clock_counter += (stop-start);
        return false;
    }

    for(vector<m__Node>::iterator it = seenStates.begin(); it != seenStates.end(); it++)
    {
        if( /* condition */ )
        {
            stop = clock();
            clock_counter += (stop - start);
            return true;
        }
    }
    stop = clock();
    clock_counter += (stop - start);
    return false;
}

我可以在这里做些更好的事情,还是应该继续使用其他数据结构(可能是unordered_set,如下所示)?

还有一次更新

我在发布模式下尝试了完全相同的代码,整个算法只需1.2秒即可执行 我不知道Debug和Release之间可能存在如此大的差异。我知道Release会做一些优化,但这有些不同!

4 个答案:

答案 0 :(得分:0)

如果我理解正确,您的数据结构类似于单链表。因此,您可以尝试使用

,而不是使用自己的实现
std::slist<Board*>

或者可能更好用

std::slist<std::unique_ptr<Board> >

如果您还需要对前一个元素的引用,请使用标准std::list。两者都会给你不断的插入,但只能进行线性查找(至少如果你不知道在哪里搜索)。

或者,您可以考虑使用std::map<std::unique_ptr<Board> >来提供对数插入和查找,但不需要进一步努力就会丢失有关后继者的信息。

编辑std::vector似乎没有对您的要求有良好的选择。据我所知,您需要快速搜索和快速插入。两者都是向量的O(n)。改为使用std::map,其中两者都是O(log n)。 [但请注意,使用后者并不意味着您将直接获得更快的执行时间,因为这取决于元素的数量]

答案 1 :(得分:0)

这部分:

if(!(seenStates.contains(children[i])))

对于链表来说会非常慢。虽然算法时间是O(n),与std::vector<Node>相同,但是你走过的记忆将遍布整个地方...所以你要招致随着容器变大,大量缓存未命中。过了一会儿,你的时间将被那些缓存未命中所控制。因此std::vector可能会表现得更好。

那就是说,如果你做了很多find()类型的操作,你应该考虑使用一个设置得很快的容器......也许是std::unordered_set

答案 2 :(得分:0)

使用列表最后会有O(n)时间来搜索元素。你可以考虑使用更有效的lookßup数据结构,例如std :: map,std :: unordered_map,有序向量,其他树结构。有许多数据结构。哪一个最好取决于您的算法设计。

答案 3 :(得分:0)

确实,您不希望在您的案例中使用链接列表。在链表O(n)中查找特定值(即contains())非常慢。

因此,使用数组列表(例如std :: vector)或二进制搜索树会更聪明,contains()的复杂度将平均变为O(log n)。

但是,如果您担心经常扩展数组列表,则可能会在创建数组时占用大量空间(例如20 000个元素)。

不要忘记考虑为两个列表使用两种不同的数据结构。