还有其他办法吗?花了2个小时试图解决它。我有一个解决方案(参见下面的DumpPostOrder)但是,有更好或更有效的方法吗?感觉可能有。规则是 - 没有递归,节点不能有访问标志。即,你只能使用左+右成员。
我的方法是在这个过程中破坏树。通过将每一边的子节点设置为null,您可以将节点标记为遍历一次,但我也会查看每个节点有两次子节点:(。有更好的更快方式吗?(对我的预订和顺序实现的评论表示赞赏)但没有必要(即投票,但没有标记答案)。谢谢!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BinaryTreeNoRecursion
{
public class TreeNode<T>
{
public T Value { get; set; }
public TreeNode<T> Left { get; set; }
public TreeNode<T> Right { get; set; }
public TreeNode(T inValue)
{
Value = inValue;
}
public TreeNode(TreeNode<T> left, TreeNode<T> right, T inValue)
{
Left = left;
Right = right;
Value = inValue;
}
}
public class BinaryTree<T>
{
private TreeNode<T> root;
public TreeNode<T> Root
{
get { return root; }
}
public BinaryTree(TreeNode<T> inRoot)
{
root = inRoot;
}
public void DumpPreOrder(T[] testme)
{
Stack<TreeNode<T>> stack = new Stack<TreeNode<T>>();
stack.Push(root);
int count =0;
while (true)
{
if (stack.Count == 0) break;
TreeNode<T> temp = stack.Pop();
if (!testme[count].Equals(temp.Value)) throw new Exception("fail");
if (temp.Right != null)
{
stack.Push(temp.Right);
}
if (temp.Left != null)
{
stack.Push(temp.Left);
}
count++;
}
}
public void DumpPostOrder(T[] testme)
{
Stack<TreeNode<T>> stack = new Stack<TreeNode<T>>();
TreeNode<T> node = root;
TreeNode<T> temp;
int count = 0;
while(node!=null || stack.Count!=0)
{
if (node!=null)
{
if (node.Left!=null)
{
temp = node;
node = node.Left;
temp.Left = null;
stack.Push(temp);
}
else
if (node.Right !=null)
{
temp = node;
node = node.Right;
temp.Right= null;
stack.Push(temp);
}
else //if the children are null
{
if (!testme[count].Equals(node.Value)) throw new Exception("fail");
count++;
if (stack.Count != 0)
{
node = stack.Pop();
}
else
{
node = null;
}
}
}
}
}
public void DumpInOrder(T[] testme)
{
Stack<TreeNode<T>> stack = new Stack<TreeNode<T>>();
TreeNode<T> temp = root;
int count = 0;
while (stack.Count!=0 || temp!=null)
{
if (temp != null)
{
stack.Push(temp);
temp = temp.Left;
}
else
{
temp = stack.Pop();
if (!testme[count].Equals(temp.Value)) throw new Exception("fail");
count++;
temp = temp.Right;
}
}
}
}
class Program
{
static void Main(string[] args)
{
//create a simple tree
TreeNode<int> node = new TreeNode<int>(100);
node.Left = new TreeNode<int>(50);
node.Right = new TreeNode<int>(150);
node.Left.Left = new TreeNode<int>(25);
node.Left.Right = new TreeNode<int>(75);
node.Right.Left = new TreeNode<int>(125);
node.Right.Right = new TreeNode<int>(175);
node.Right.Left.Left = new TreeNode<int>(110);
int[] preOrderResult = { 100, 50, 25, 75, 150, 125, 110, 175};
int[] inOrderResult = { 25, 50, 75, 100, 110, 125, 150, 175};
int[] postOrderResult = { 25, 75, 50, 110, 125, 175, 150, 100 };
BinaryTree<int> binTree = new BinaryTree<int>(node);
//do the dumps, verify output
binTree.DumpPreOrder(preOrderResult);
binTree.DumpInOrder(inOrderResult);
binTree.DumpPostOrder(postOrderResult);
}
}
}
答案 0 :(得分:1)
对我来说,在穿越它时摧毁树是非常残酷的。
您目前正在构建访问过的节点集合。
您通过将节点设置为null来将节点标记为已访问。
您是否可以通过检查收藏中的节点来检查访问情况?为了提高效率,您可能不需要使用Stack,但这是一个实现细节。
答案 1 :(得分:1)
如前所述,在这种情况下避免递归可能是一个坏主意。系统调用堆栈旨在处理这样的事情。销毁树是一种标记节点的形式。
如果您想使用自己的堆栈,那么您需要提供的信息不仅仅是节点。请记住,系统调用堆栈包含程序计数器以及函数参数(局部变量以及此处不重要的bu)。我们可以推送(PushMyChildren, node)
,(PrintMe, Node)
格式的元组,当我们弹出(PushMyChildren, node)
格式的节点时,我们会推送(PrintMe, Node)
,然后(PushMyChildren, right child)
,然后{ {1}}。如果左右儿童不存在则不要推他们。当我们弹出(PushMyChildren, left child)
形式的节点时,我们打印节点。在伪C#(我不知道C#,没有时间查找正确的类型和语法)。
(PrintMe, Node)
答案 2 :(得分:1)
您可以将二叉树映射到一个数组(类似于将堆映射到数组的方式,如here所示),并在那里进行后序遍历。将二叉树转换为数组的操作可能会使用递归,但如果您正在控制树的初始构造方式(或者您只是在寻找一个有趣的想法),那么您可以将其构建为数组,并简化你的非递归后序遍历(没有标志)问题。
<强> 修改 强>
我认为这是一个可行的选择:
1)保持指向树中节点的双向链接列表 2)从根节点开始 3)将根指针附加到列表 4)去右边的孩子 5)将当前节点指针附加到列表 6)重复步骤4和5,直到没有正确的孩子为止 7)将当前节点写入后订单遍历 8)将当前节点设置为列表中的最后一个节点 9)去左边的孩子 10)将当前音符指针附加到列表 11)重复步骤4到10,直到列表为空。
基本上,这会使树中的所有节点都有一个指向其父节点的指针。
答案 3 :(得分:0)
我刚刚使用遍历到宽度(使用队列)在Java中进行了下订单。
search_button = driver.execute_script('return document.querySelector("downloads-manager").shadowRoot.querySelector("downloads-toolbar").shadowRoot.querySelector("cr-search-field").shadowRoot.querySelector("#search-button")')
search_button.click()