【发布时间】:2014-02-18 07:21:24
【问题描述】:
我正在尝试遍历一棵树,以访问 4x4 滑动拼图的所有可能状态。我写的算法最初是递归的,但由于(显然)非常深的树,这被证明是不可能的。它崩溃并报告了一个段错误。然后我决定重写算法以迭代地完成它的工作,据我所见,它工作得很好。但是,一段时间后,由于交换,它开始显着减慢。我做了一些计算,但无法弄清楚所有这些内存使用的来源......
代码贴在下面,但这里有一些重要的功能:
std::stack<char, std::vector<char>> stack-
std::map<unsigned long long, int> distanceTable
假设stack 的内存占用与其拥有的元素数量成正比,并假设map(其中元素是pair<unsigned long long, int>)相同,我打印出预期的内存占用:
cout << (stack.size() * sizeof(char) +
distanceTable.size() * sizeof(pair<unsigned long long, int>))/(1<<20) << "MB\n";
并将输出与top 的输出进行比较。当我自己的程序报告大约 500MB 时,top 报告说它使用了我所有内存(4GB)的一半以上。这是我的推理无法解释的因素 4。我在这里错过了什么?
代码:
#include <iostream>
#include <map>
#include <stack>
#include <vector>
#include <sstream>
#include "slider.h"
using namespace std;
typedef Slider<4> Slider4;
typedef Slider4::Move Move;
typedef map<unsigned long long, int> Map;
typedef stack<char, std::vector<char>> Stack;
Move const moves[] = {Slider4::N, Slider4::S, Slider4::E, Slider4::W};
Move const opposite[] = {Slider4::S, Slider4::N, Slider4::W, Slider4::E};
int const moveIdx[] = {0, 1, 2, 3};
int const oppositeIdx[] = {1, 0, 3, 2};
Map generateDistanceTable()
{
// non-recursive tree-walker to generate the distance-table
Map distanceTable;
Stack stack;
Slider4 slider;
unsigned long long depth = 1;
stack.push(-1);
distanceTable[slider.hash()]= depth;
while (depth != 0)
{
cout << (stack.size() * sizeof(char) +
distanceTable.size() * sizeof(pair<unsigned long long, int>))/(1ULL<<20) << "MB\n";
int currentMove = stack.top() + 1;
// find next move
while (currentMove != 4)
{
// Try the move
if (!slider.move(moves[currentMove]))
{
++currentMove;
continue;
}
// Check the current state of the puzzle
auto &d = distanceTable[slider.hash()];
if (d != 0)
{ // already encountered this state -> move back
int undoMove = oppositeIdx[currentMove];
slider.moveUnsafe(moves[undoMove]);
++currentMove; // try next move
continue;
}
stack.push(currentMove);
d = ++depth;
currentMove = 0;
}
if (currentMove == 4)
{
int undoMove = oppositeIdx[stack.top()];
slider.moveUnsafe(moves[undoMove]);
--depth;
stack.pop();
}
}
}
int main()
{
Map table = generateDistanceTable();
}
【问题讨论】:
-
您在输出中交换了大小 - 这只是复制和粘贴错误,还是您的代码中也有。
-
distanceTable.size() * sizeof(char)=> 这是如何准确估计地图大小的?它与实际大小有一个恒定的因子差异,这正是您所报告的。 -
@Angew 我的错误,复制粘贴错误。已在帖子中修复它,所有报告的结果仍然有效。
-
您可以使用function 来防止此类错误;-)
-
@Angew 在您的估计中
log(N)来自哪里?二叉树具有线性大小。用 boost::flat_map 或 std::unordered_map 替换 std::map 通常是一种胜利。