我有一个节点类,它只包含值类型属性和一个引用类型:它的父节点。执行树搜索时,这些节点会在很短的时间内创建并销毁数十万次。
public class Node
{
public Node Parent { get; set; }
public int A { get; set; }
public int B { get; set; }
public int C { get; set; }
public int D { get; set; }
}
树搜索看起来像这样:
public static Node GetDepthFirstBest(this ITree tree, Node root)
{
Node bestNode = root;
float bestScore = tree.Evaluate(root);
var stack = new Stack<Node>();
stack.Push(root);
while(stack.Count > 0)
{
var current = stack.Pop();
float score = tree.Evaluate(current);
if (score > bestScore)
{
bestNode = current;
bestScore = score;
}
var children = tree.GetChildren(current);
foreach(var c in children) { stack.Push(c); }
}
return bestNode;
}
因为这是在具有非常旧的GC的Mono运行时中完成的,所以我想尝试汇集节点对象。但是,我对如何知道节点对象何时安全返回池感到茫然,因为仍在使用的其他节点可能会将其作为父节点引用。在搜索结束时,返回最佳节点,并通过返回其祖先形成节点列表。我完全可以控制如何在树中创建节点,如果这有用的话。
我可以尝试和实施哪些选项?
答案 0 :(得分:0)
所以,幸运的是,如果您正在进行深度优先搜索,这看起来很简单。无论何时到达叶节点,都有两种可能:叶节点是当前最深树的一部分,或者不是。
如果不是,那意味着将此节点返回池是安全的。如果是,那意味着我们可以将旧树中的任何节点返回到我们的池中,这些节点不在我们自己的祖先链中。
现在,如果我们不是一个叶子节点,我们不知道在我们检查完孩子之前我们是否可以被释放。然后,一旦我们所有的孩子都接受了检查,我们就会发现我们的孩子是否认为他们是目前最好的孩子。如果是这样,我们保持自己
这确实意味着我们正在做更多的检查。
这是一些sudo代码:
List bestNodes;
bool evalNode(node, score)
{
if (childCount == 0)
{
if (score > bestScore)
{
bestScore = score;
bestNode = node;
bestNodes.Add(node);
return true;
}
else
{
freeNode(this);
return false;
}
}
else
{
bool inLongest = false;
foreach (child in children)
{
inLongest = evalNode(child, score + 1) || inLongest;
}
if (!inLongest)
{
freeNode(node);
}
else
{
free(bestNodes[score]);
bestNodes[score] = node;
}
return inLongest;
}
}
答案 1 :(得分:-1)
如果您的节点是结构,请尝试使用ref关键字,这样可以避免每次将节点传递给函数时复制节点。
因此:
struct Node
{
object obj;
Node children;
}
public void DoStuffWithNode(ref Node pNode){...Logic...}