我有一个非常简单的abstract class AbstractTree
,如下所示:
public abstract class AbstractTree
{
public abstract void Accept(AbstractTreeVisitor visitor);
}
和两个具体的类:具有左右AbstractTree字段的Node和具有整数值的Leaf(+覆盖访问者的重写方法):
public class TreeNode : AbstractTree
{
public AbstractTree left;
public AbstractTree right;
public TreeNode(AbstractTree left, AbstractTree right)
{
this.left = left;
this.right = right;
}
public override void Accept(AbstractTreeVisitor visitor)
{
visitor.Visit(this);
}
}
public class TreeLeaf : AbstractTree
{
public int val;
public TreeLeaf(int val)
{
this.val = val;
}
public override void Accept(AbstractTreeVisitor visitor)
{
visitor.Visit(this);
}
}
现在,我可以写抽象的访问者来访问我的树:
public abstract class AbstractTreeVisitor
{
public abstract void VisitNode(TreeNode n);
public abstract void VisitLeaf(TreeLeaf l);
public virtual void Visit(AbstractTree tree)
{
if (tree is TreeNode)
VisitNode((TreeNode)tree);
else
VisitLeaf((TreeLeaf)tree);
}
}
因此,让使具体的访问者来计算叶子中的整数和:
public class SumTreeVisitor : AbstractTreeVisitor
{
int sum = 0;
public override void VisitNode(TreeNode n)
{
base.Visit(n.left);
base.Visit(n.right);
}
public override void VisitLeaf(TreeLeaf l)
{
sum += l.val;
}
public int GetSum()
{
return sum;
}
}
现在我可以在main中将其用作:
AbstractTree tree = new TreeNode(new TreeNode(new TreeLeaf(3), new TreeLeaf(4)), new TreeNode(new TreeLeaf(2),new TreeNode(new TreeLeaf(7),new TreeLeaf(3))));
SumTreeVisitor sum = new SumTreeVisitor();
tree.Accept(sum);
int i = sum.GetSum();
Console.WriteLine(i); //19
但是这个访客真的很简单。
我的问题是,如何写访问者可以找到我的树的深度?当然,用伪代码很容易,但是我不知道如何将其编写为Visitor。在此先感谢您的帮助。
最佳答案
首先-您的AbstractTree
不应是课程。它没有数据,也没有行为。它仅定义合同,因此应将其声明为接口,例如
public interface ITreeNode
{
void Acept(ITreeVisitor visitor);
}
同样,您的访问者类中不需要使用其他名称的方法。如果参数类型不同,则签名也将不同。因此,您不需要
Visit
方法,并且再次没有数据和行为,选择接口:public interface ITreeVisitor
{
void Visit(TreeNode node);
void Visit(TreeLeaf leaf);
}
现在
SumTreeVisitor
-您应该只在节点上接受当前的访问者,呼叫将被分派到适当的访问者方法:public class SumTreeVisitor : ITreeVisitor
{
public override void Visit(TreeNode node)
{
node.Left.Accept(this); // left and right should be properties
mode.Right.Accept(this);
}
public override void Visit(TreeLeaf leaf)
{
Sum += leaf.Value;
}
public int Sum { get; private set; }
}
请记住使用属性而不是公共字段(您可以使用自动实现的属性):
public class TreeNode : ITreeNode
{
public ITreeNode Left { get; private set; }
public ITreeNode Right { get; private set; }
public TreeNode(ITreeNode left, ITreeNode right)
{
Left = left;
Right = right;
}
public void Accept(ITreeVisitor visitor)
{
visitor.Visit(this);
}
}
并且计算深度很简单-只需在访问下一个节点之前增加当前深度,并在访问它之后就将其递减即可:
public class DepthTreeVisitor : ITreeVisitor
{
private int _currentDepth = -1;
public void Visit(TreeNode node)
{
_currentDepth++;
node.Left.Accept(this);
node.Right.Accept(this);
_currentDepth--;
}
public void Visit(TreeLeaf leaf)
{
_currentDepth++;
if (_currentDepth > Depth)
Depth = _currentDepth;
_currentDepth--;
}
public int Depth { get; private set; }
}
通过测试:
ITreeNode root = new TreeNode(
new TreeNode(new TreeLeaf(3), new TreeLeaf(4)),
new TreeNode(new TreeLeaf(2),
new TreeNode(new TreeLeaf(7), new TreeLeaf(3)))
);
var visitor = new DepthTreeVisitor();
root.Accept(visitor);
visitor.Depth.Should().Be(3);