广度优先搜索算法在无限循环中不起作用
Breadth First Search Algorithm Does Not Work Results in Infinite Loop
我正在尝试进行 BFS 搜索,在搜索状态 Space 时动态创建图形的节点。我遵循了这本书,但它不起作用边界保持 运行 并且探索集仅保持在起始值。请帮助,我已经被困在这里4天了。还是个初级程序员。
问题Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Test
{
internal class Problem
{
public State start { get; set; }
public State end { get; set; }
public string[] action = { "UP", "LEFT", "DOWN", "RIGHT" };
public Problem(State x, State y)
{
start = x;
end = y;
}
public State Result(State s , string a)
{
State up;
if (a == "UP" && s.X - 1 >= 0)
{
up = new State(s.X - 1, s.Y);
}
else if (a == "LEFT" && s.Y - 1 >= 0)
{
up = new State(s.X, s.Y-1);
}
else if (a == "DOWN" && s.X + 1 < 5)
{
up = new State(s.X, s.Y+1);
}
else if( a == "RIGHT" && s.Y + 1 < 11)
{
up = new State(s.X + 1, s.Y);
}
return up;
}
public bool GoalTest(Node<State> goal)
{
if (goal.Data.Equals(end))
{
return true;
}
return false;
}
}
}
搜索Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Test
{
internal class Search
{
public void BFS(Problem p)
{
Queue<Node<State>> frontier = new Queue<Node<State>>();
HashSet<string> explored = new HashSet<string>();
List<Node<State>> nNodes = new List<Node<State>>();
Node<State> root = new Node<State>() {Data = p.start,};
frontier.Enqueue(root);
while(frontier.Count > 0)
{
Node<State> next = frontier.Dequeue();
if(!explored.Add(next.Data.Data)) continue;
next.Children = new List<Node<State>>();
foreach(string action in p.action)
{
next.Children.Add(new Node<State>() { Data = p.Result(next.Data, action), Parent = next });
}
for(int i = 0; i < next.Children.Count; i++)
{
if (p.GoalTest(next.Children[i]) == true)
{
//Solution(next.Children[i]);
break;
}
frontier.Enqueue(next.Children[i]);
}
}
}
public void Solution(Node<State> n)
{
while(n.Parent != null)
{
Console.WriteLine(n.Parent.Data);
}
}
}
}
节点Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Test
{
internal class Node<T>
{
public T Data { get; set; }
public Node<T>? Parent { get; set; }
public List<Node<T>> Children { get; set; }
}
}
状态Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Test
{
internal class State
{
public int X { get; set; }
public int Y { get; set; }
public string Data { get; }
public State(int x, int y)
{
X = x;
Y = y;
Data = $"{X}-{Y}";
}
}
}
主程序
using Test;
State start = new State(0, 1);
State end = new State(3, 7);
Problem p = new Problem(start, end);
Search s = new Search();
s.BFS(p);
这实际上是我的作业,因此我将其命名为测试。
我正在尝试从这里实现伪代码:(第 82 页)
https://zoo.cs.yale.edu/classes/cs470/materials/aima2010.pdf
更新
它现在没有卡住,但是在循环运行后它没有向控制台输入任何内容它应该通过 "Parent 属性"[= 获取目标节点和起始节点之间的链接42=].
您永远不会检查节点是否已被探索,因此您可能会进入无限循环:
explored.Add(next.Data.Data);
应该是
if(!explored.Add(next.Data.Data)) continue;
但是代码可能还有其他问题。我强烈建议阅读 Eric Lipperts 的文章 How to debug small programs,因为在调试器的帮助下,这样的问题应该很容易找到并自行修复。学习如何使用调试器是一项非常宝贵的技能,它将使故障排除变得更加容易。
我还建议从您的程序中删除所有字符串。相反,您应该创建表示坐标的类型,即 Point 或 vector2Int。我建议将其设为只读结构,并添加 ToString
重载、IEquality<Point>
实现、加减运算符、相等性等。此类型可用于表示状态和表示偏移量.这样的类型将可重复用于各种不同的项目。
我正在尝试进行 BFS 搜索,在搜索状态 Space 时动态创建图形的节点。我遵循了这本书,但它不起作用边界保持 运行 并且探索集仅保持在起始值。请帮助,我已经被困在这里4天了。还是个初级程序员。
问题Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Test
{
internal class Problem
{
public State start { get; set; }
public State end { get; set; }
public string[] action = { "UP", "LEFT", "DOWN", "RIGHT" };
public Problem(State x, State y)
{
start = x;
end = y;
}
public State Result(State s , string a)
{
State up;
if (a == "UP" && s.X - 1 >= 0)
{
up = new State(s.X - 1, s.Y);
}
else if (a == "LEFT" && s.Y - 1 >= 0)
{
up = new State(s.X, s.Y-1);
}
else if (a == "DOWN" && s.X + 1 < 5)
{
up = new State(s.X, s.Y+1);
}
else if( a == "RIGHT" && s.Y + 1 < 11)
{
up = new State(s.X + 1, s.Y);
}
return up;
}
public bool GoalTest(Node<State> goal)
{
if (goal.Data.Equals(end))
{
return true;
}
return false;
}
}
}
搜索Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Test
{
internal class Search
{
public void BFS(Problem p)
{
Queue<Node<State>> frontier = new Queue<Node<State>>();
HashSet<string> explored = new HashSet<string>();
List<Node<State>> nNodes = new List<Node<State>>();
Node<State> root = new Node<State>() {Data = p.start,};
frontier.Enqueue(root);
while(frontier.Count > 0)
{
Node<State> next = frontier.Dequeue();
if(!explored.Add(next.Data.Data)) continue;
next.Children = new List<Node<State>>();
foreach(string action in p.action)
{
next.Children.Add(new Node<State>() { Data = p.Result(next.Data, action), Parent = next });
}
for(int i = 0; i < next.Children.Count; i++)
{
if (p.GoalTest(next.Children[i]) == true)
{
//Solution(next.Children[i]);
break;
}
frontier.Enqueue(next.Children[i]);
}
}
}
public void Solution(Node<State> n)
{
while(n.Parent != null)
{
Console.WriteLine(n.Parent.Data);
}
}
}
}
节点Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Test
{
internal class Node<T>
{
public T Data { get; set; }
public Node<T>? Parent { get; set; }
public List<Node<T>> Children { get; set; }
}
}
状态Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Test
{
internal class State
{
public int X { get; set; }
public int Y { get; set; }
public string Data { get; }
public State(int x, int y)
{
X = x;
Y = y;
Data = $"{X}-{Y}";
}
}
}
主程序
using Test;
State start = new State(0, 1);
State end = new State(3, 7);
Problem p = new Problem(start, end);
Search s = new Search();
s.BFS(p);
这实际上是我的作业,因此我将其命名为测试。
我正在尝试从这里实现伪代码:(第 82 页)
https://zoo.cs.yale.edu/classes/cs470/materials/aima2010.pdf
更新
它现在没有卡住,但是在循环运行后它没有向控制台输入任何内容它应该通过 "Parent 属性"[= 获取目标节点和起始节点之间的链接42=].
您永远不会检查节点是否已被探索,因此您可能会进入无限循环:
explored.Add(next.Data.Data);
应该是
if(!explored.Add(next.Data.Data)) continue;
但是代码可能还有其他问题。我强烈建议阅读 Eric Lipperts 的文章 How to debug small programs,因为在调试器的帮助下,这样的问题应该很容易找到并自行修复。学习如何使用调试器是一项非常宝贵的技能,它将使故障排除变得更加容易。
我还建议从您的程序中删除所有字符串。相反,您应该创建表示坐标的类型,即 Point 或 vector2Int。我建议将其设为只读结构,并添加 ToString
重载、IEquality<Point>
实现、加减运算符、相等性等。此类型可用于表示状态和表示偏移量.这样的类型将可重复用于各种不同的项目。