我正在尝试通过深度优先搜索在图表中找到特定节点。我当前(简单)的实现正在运行,但只返回bool
,即是否找到了节点。
我想添加从操作中返回路径的功能,例如,如果我在以下示例中搜索5
,我将获得"1-2-3-5"
而不是true
public class BinaryTreeNode
{
public List<BinaryTreeNode> Children { get; set; }
public int Data { get; set; }
}
public class DepthFirstSearch
{
private Stack _searchStack;
private BinaryTreeNode _root;
public DepthFirstSearch(BinaryTreeNode rootNode)
{
_root = rootNode;
_searchStack = new Stack();
}
public bool Search(int data)
{
BinaryTreeNode _current;
_searchStack.Push(_root);
while (_searchStack.Count != 0)
{
_current = _searchStack.Pop();
if (_current.Data == data)
{
return true;
}
foreach(BinaryTreeNode b in current.Children.AsEnumerable().Reverse())
_searchStack.Push(b);
}
return false;
}
}
感谢任何帮助。
答案 0 :(得分:1)
另一种方法。
此方法在每个节点上存储父信息,getPath
向上走树并返回值。但是你的树不是二叉树,也许你应该将类名更改为TreeNode或其他东西。
static void Main(string[] args)
{
var root = createNode();
var search = new DepthFirstSearch(root);
var result = search.Search(5);
var arr = result.getPath();
arr.Reverse();
Console.Write(String.Join("-",arr));
}
public class DepthFirstSearch
{
private Stack _searchStack;
private BinaryTreeNode _root;
public DepthFirstSearch(BinaryTreeNode rootNode)
{
_root = rootNode;
_searchStack = new Stack();
}
public BinaryTreeNode Search(int data)
{
BinaryTreeNode _current;
_searchStack.Push(_root);
while (_searchStack.Count != 0)
{
_current = (BinaryTreeNode)_searchStack.Pop();
if (_current.Data == data)
{
return _current;
}
foreach (BinaryTreeNode b in _current.Children.AsEnumerable().Reverse())
_searchStack.Push(b);
}
return null;
}
}
public class BinaryTreeNode
{
public BinaryTreeNode parent { get; set; }
public List<BinaryTreeNode> Children { get; set; }
public int Data { get; set; }
public List<int> getPath()
{
var list = new List<int>(){Data};
if (parent != null)
{
list.AddRange(parent.getPath());
}
return list;
}
}
答案 1 :(得分:0)
最简单的方法是在session_write_close()
类中存储BinaryTreeNode Parent { get; set; }
,如果没有父级,则为BinaryTreeNode
,否则它是节点的父级。这些将在您最初构建树时设置。然后你可以简单地返回找到的节点(如果找不到任何内容,则返回null
)并通过父节点重建列表,如
null
我完全不记得List<int> path = new List<int>();
BinaryTreeNode found = new DepthFirstSearch(root).Search();
while(found != null)
{
path.Push(found.Data);
found = found.Parent;
}
string stringPath = String.Join("-", path);
的语义,因此您可能最终必须撤消列表或附加到列表的末尾或类似的内容而不是使用Push
。
答案 2 :(得分:0)
首先,树图像中的示例不是二叉树节点,因为第一个节点(根)有3个子节点。二叉树应该有只有两个子节点的节点,一个叫做“left”,另一个叫“right”,因此“二叉树”中的“bi”
此外,您对BinaryTreeNode的实现有两个好主意:
一个名为“数据”的值(您说明节点需要存储此“数据”)。但我建议不命名变量“Data”,因为C#中还有其他变量和库,其中包含“Data”一词。将它命名为“nodeData”怎么样?描述性越强,越独特越好。
你有正确的想法存储孩子,但其他BinaryTreeNodes的列表是不正确的,因为如果该列表意外地有超过2个孩子怎么办?同样,如果需要,您可以执行此操作,但这将是“树”,而不是“二叉树”数据结构。怎么样而不是:
public List<BinaryTreeNode> Children { get; set; }
DO
public BinaryTreeNode LeftNode { get; set; }
public BinaryTreeNode RightNode { get; set; }
现在你的“布尔搜索”功能:
您正在将节点的所有子节点推入堆栈。根据定义,这几乎是“广度优先搜索”而不是“深度优先搜索”。 “宽度”因为您首先按“行”(或“宽度”)存储节点。认为第0行是根节点,第1行是root的子节点,第2行是root子节点的子节点,等等。您使用堆栈这一事实意味着您将要搜索弹出到堆栈_searchStack中的最后一个子节点。正确的广度优先使用队列而不是堆栈(FIFO与FILO),但这超出了这个问题的范围。
您的深度优先搜索应该专注于一次保存一个(且仅一个)节点。对于第一个根节点,您选择一个子节点。然后你在那个ONE孩子上调用深度优先搜索。那个孩子会选择其中一个孩子,然后打电话给深度优先。等等。如果节点没有子节点,则返回/退出该函数。节点完成一个孩子后,调用另一个孩子的深度优先搜索。深度优先搜索的一般思想是,在覆盖任何兄弟节点之前,您希望“深入”到树中。
回答您的问题:
成功实现DFS后,您需要找到一种方法来“记住”您已遍历的父节点,并在返回“深度”时从找到的子节点向父节点构建字符串
所以在你的例子中,在之后,DFS在树下找到“5”,然后它会上升到树上: 五 3-5 2-3-5 1-2-3-5