最佳排序的c ++容器

时间:2014-01-07 03:31:58

标签: c++ stl chess

我正在用c ++编写一个国际象棋引擎,并且我正在努力制作尽可能干净和正确的代码,因为这是一个学习练习。 目前,我有一个移动类,它定义了一个可能的移动。然后,AI会对每一个可能的行动进在数据结构中将移动得分与移动本身配对的最佳方法是什么?

每个分数必须有多个动作(两个动作都可以得到735分)。我认为排除std :: map?

它也应该可以快速排序,所以我可以向前看并递归地执行此操作以获得最佳动作。

任何帮助将不胜感激,包括链接。谢谢!

3 个答案:

答案 0 :(得分:3)

你的问题并不完全清楚。一方面,你说你想要一个已排序的容器,但另一方面,你谈论事物的方式是你将生成移动,将它们放入容器中,然后根据它们进行排序根据您的AI定义的标准。

让我们分开考虑一下。首先,我们假设您希望将分数用作关键,并查找具有特定分数的移动。在这种情况下,您将生成一个移动,AI将对该移动进行评分,然后您将存储移动,其得分为关键。由于您可以使用相同的分数进行多次移动(即等效键),因此本案例所需的数据结构为std::multimap

另一种可能性是你生成所有动作,将它们全部放入数据结构中,对它们进行全部评分,然后按分数对它们进行排序。对于此方案,您可能希望使用std::vector<std::pair<score_type, move>>。在这种情况下,当您生成每个移动时,您可能会为其分配类似0的分数。然后,您将遍历向量并让AI为每个移动生成分数。然后你使用只考虑得分的比较函数对它们进行排序。

其中任何一个都可行。最好的一个取决于具体情况。使用向量可能会最大限度地减少开销 - 也就是说,它会使用最少的内存和最少的CPU时间从原始移动到向量,并且所有移动都按排序顺序存储。

std::multiset的优势在于它始终保持排序状态。例如,如果您希望生成移动直到达到某个时间限制,它将让您非常干净地完成移动 - 生成移动,对其进行评分,将其插入到多集中。无论你何时停止,你所生成的所有动作都已经排序,所以(例如)如果与你的程序对战的人可以迫使AI立即行动,那么AI总是有最好的记录移动它的发现,所以它可以立即做出“认为”最好的举动。

另一种可能性是使用优先级队列。在一个典型的国际象棋案例中,你要做的一件事就是生成(比方说)几十个或可能的下一步动作。然后你将挑选最好的那些,并对那些可能的反击进行评分。然后你将挑选最好的那些并将计数器评分为这些动作,依此类推,直到你得分(比方说)4或5个完整动作为止。

为此,你并不真正关心按顺序所有移动 - 你只是希望能够快速检索N个最佳动作。对于这种情况,优先级队列工作得很好。您可以检索N个最佳动作,然后忽略其余动作。这意味着您只需对N个最佳动作(您关心的动作)进行完全排序,并最大限度地减少其余部分的开销,但只做足够的工作来验证它们的分数较低。

我还应该提一下,如果这是你真正想要的,你可以在数组的情况下完成同样的事情。您可以使用nth_element仅查找N个最佳分数,而不是使用sort来按分数对所有移动进行排序。 nth_element将数组/向量排列成两组:那些将在某个选定元素之前排序的组,然后是所选元素,然后是在所选元素之后排序的元素。例如,给定100个移动,你想要保持前5个移动,你可以使用nth_element将它们排列成95个较小的移动,95 th 元素,然后另一个4.虽然没有尝试订购每组内的物品。

这样做的好处是它可以在O(N)时间内完成,而不是完整排序所需的O(N log N)。

在这两种可能性(priority_queuenth_element)之间,我们在set::multisetstd::vectorstd::sort之间获得了相同的权衡:{{ 1}}始终保持其顺序。即使您或多或少地随意混合插入和移除,它仍然非常有效。使用priority_queuestd::vector,您通常需要插入所有元素,然后调用std::nth_element,然后考虑顶部项目。如果你要混合两个(插入一些元素,然后删除一些最好的,插入一些,删除一些,等等)你每次从插入转换时都必须调用nth_element去除,这可能会很快杀死效率。

答案 1 :(得分:1)

听起来你正在寻找的是优先队列。

它们通常使用Heap(Fibonacci堆,如果你想要效率)来实现。堆本身并没有完全排序,但在任何特定时刻,您都可以保证在顶部获得最佳移动。

Boost有一个Fibonacci堆实现。

您可以查看this问题。该问题中的MyType可以是DataPriority

的std ::对

答案 2 :(得分:0)

std :: set可以满足您的需求。 std :: set&gt;其中X是分数,Y是类对象,或者您可以定义自己的自定义比较器。看到这个:Using custom std::set comparator