我正在开发一个项目,我需要在列表中的对象和插入之间进行大量的比较。
基本上我有一个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会做一些优化,但这有些不同!
答案 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个元素)。
不要忘记考虑为两个列表使用两种不同的数据结构。