2012-04-09 95 views
4
public List<Location2D> Path(Location2D start, Location2D goal) 
{ 
    openset = new List<NodeInfo>(); // The set of tentative nodes to be evaluated, initially containing the start node. 
    closedset = new List<NodeInfo>(); // The set of nodes already evaluated. 
    path = new List<Location2D>(); // The path result. 
    came_from = new Dictionary<Location2D, Location2D>(); 

    NodeInfo Start = new NodeInfo(); 
    Start.SetLoction(start.X, start.Y); 
    Start.H = GetHValue(start, goal); 
    openset.Add(Start); 

    while (openset.Count > 0) { // while openset is not empty 
     NodeInfo current = CheckBestNode(); //the node in openset having the lowest f_score[] value 

     if (current.Location.Equals(goal)) { 
      ReconstructPathRecursive(current.Location); 
      return path; 
     } 

     for (int i = 0; i < 8; i++) { // neighbor nodes. 
      NodeInfo neighbor = new NodeInfo(); 
      neighbor.SetLoction((ushort)(current.Location.X + ArrayX[i]), (ushort)(current.Location.Y + ArrayY[i])); 

      bool tentative_is_better = false; 

      if (closedset.Contains(neighbor)) 
       continue; 
      if (!map.Cells[neighbor.Location.X, neighbor.Location.Y].Walkable) { closedset.Add(neighbor); continue; } 

      Double tentative_g_score = current.G + DistanceBetween(current.Location, neighbor.Location); 

      if (!openset.Contains(neighbor)) { 
       openset.Add(neighbor); 
       neighbor.H = GetHValue(neighbor.Location, goal); 
       tentative_is_better = true; 
      } else if (tentative_g_score < neighbor.G) { 
       tentative_is_better = true; 
      } else { 
       tentative_is_better = false; 
      } 

      if (tentative_is_better) { 
       came_from[neighbor.Location] = current.Location; 
       neighbor.G = tentative_g_score; 
      } 
     } 
    } 
    return null; 
} 

private void ReconstructPathRecursive(Location2D current_node) 
{ 
    Location2D temp; 
    if (came_from.TryGetValue(current_node, out temp)) { 
     path.Add(temp); 
     ReconstructPathRecursive(temp); 
    } else { 
     path.Add(current_node); 
    } 
} 

所以我实现A *算法,当它发现目标就转到ReconstructPathRecursive ,然后应用程序崩溃,并抛出该异常An unhandled exception of type 'System.StackOverflowException' occurred in mscorlib.dll A *算法System.StackOverflowException

This thread is stopped with only external code frames on the call stack. External code frames are typically from framework code but can also include other optimized modules which are loaded in the target process.

idk有什么问题!

+3

某处可能会出现无限递归,请检查您的基本情况。 – jli 2012-04-09 19:59:18

+0

'came_from.TryGetValue(current_node,out temp))'总是返回true吗?如果是这样,你肯定会有堆栈溢出。检查你的路径是否有环路。 – Msonic 2012-04-09 20:01:05

+1

无穷递归的原因可能是图中的一个循环;您可以通过使用调试器逐步完成代码,很快就可以识别问题。 – phoog 2012-04-09 20:04:10

回答

1

我固定它通过添加NodeInfo Parent {get; set; }作为该NodeInfo类中提交,我添加新List<NodeInfo>称为Nodes时试探性更好: -

if (tentative_is_better) { 
         neighbor.Parent = current; 
         nodes.Add(neighbor); 
         neighbor.G = tentative_g_score; 
        } 

那么当它发现目标: -

if (current.Location.Equals(goal)){ 
        ReconstructPath(current); 
        path.Reverse(); 
        return path; 
       } 

其中ReconstructPath: -

private void ReconstructPath(NodeInfo current) { 
      if (current.Parent == null) return; 
      path.Add(current.Parent.Location); 
      ReconstructPath(current.Parent); 
     } 

现在它工作正常。

1

它并不一定是递归的,因为它是尾递归的。所以,你可以把它改写这样的:

private void ReconstructPathIterative(Location2D current_node) 
{ 
    Location2D temp; 
    while (came_from.TryGetValue(current_node, out temp)) 
    { 
     path.Add(temp); 
     current_node = temp; 
    } 
    path.Add(current_node); 
} 

这不仅有利于如果路径只是太长,不适合在堆栈上,而不是是否是无限的。

+0

第一,它需要大量的时间和CPU使用量,然后它会中断并抛出相同的例外,路径中就有500k个元素! – Abanoub 2012-04-09 20:46:31

+0

@MixedCoder这个代码不能自己抛出一个StackOverflowException,因为它只使用一个不变的少量堆栈空间。它应该处理500k节点没问题。是path.Add破坏? – harold 2012-04-10 09:44:35

+0

它就像一个无限循环不断增加的路径,这里是一个图片来显示你的错误http://i44.tinypic.com/20zd66f.jpg – Abanoub 2012-04-10 10:04:24