我最近在树实施方面做了很多工作,以及我们如何表示和理解树木。我的重点是将数学表达式转换为二叉树,我设置了以线性形式表示树的问题,如字符串或数组,同时仍保留有关树及其子树的重要信息。
因此我已经为二进制表达式树开发了一个非常简单的编码。但是我在一个递归庄园中有效地实现它有一些问题,它似乎是概念背后的一个失败方面。
如果节点作为左子节点存在,则编码很简单如果它作为右子节点被赋予0,则给出1的映射。这种简单的编码允许我对整个平衡和非平衡树进行编码,如下所示:
## ##
/ \ / \
1 0 OR 1 0
/ \ / \ / \
11 10 01 00 01 00
对深度为N的树木
是否有人建议如何创建递归函数,该函数将创建表示此类映射的前缀字符串(例如## 1 11 10 0 01 00)。
我被告知这将是困难/不可能的,因为必须跟踪1到0之间的交替,同时保留并连接到父母的值。
我想知道是否有人对C#??
如何做到这一点有任何见解或想法答案 0 :(得分:1)
我不确定我是否理解你的问题,但这里可能有所帮助。一种解决方案可能是在Graph上实现图遍历例程(记住Tree是一个专门的图),在第一次遇到节点/顶点时进行访问。当你要求C#发布Java代码时我很抱歉,但我知道Java ...
public void depthFirstSearch(Graph graph, Vertex start){
Set<Vertex> visited = new HashSet<Vertex>(); // could use vertex.isVisited()...
Deque<Vertex> stack = new ArrayDeque<Vertex>(); // stack implies depth first
// first visit the root element, then add it to the stack so
// we will visit it's children in a depth first order
visit(start);
visited.add(start);
stack.push(start);
while(stack.isEmpty() == false){
List<Edge> edges = graph.getEdges(stack.peekFirst());
Vertex nextUnvisited = null;
for(Edge edge : edges){
if(visited.contains(edge.getEndVertex)) == false){
nextUnvisited = edge.getEndVertex();
break; // break for loop
}
}
if(nextUnvisited == null){
// check the next item in the stack
Vertex popped = stack.pop();
} else {
// visit adjacent unvisited vertex
visit(nextUnvisited);
visited.add(nextUnvisited);
stack.push(nextUnvisited); // visit it's "children"
}
}
}
public void visit(Vertex vertex){
// your own visit logic (string append, etc)
}
您可以使用Deque作为队列而不是堆栈,轻松地将其修改为广度优先搜索,如下所示:
stack.pop() >>>> queue.removeFirst()
stack.push() >>>> queue.addLast()
请注意,为此,Graph和Edge类支持以下操作:
public interface Graph {
...
// get edges originating from Vertex v
public List<Edge> getEdges(Vertex v);
...
}
public interface Edge {
...
// get the vertex at the start of the edge
// not used here but kind of implied by the getEndVertex()...
public Vertex getStartVertex();
// get the vertex at the end of the edge
public Vertex getEndVertex();
...
}
希望能给你一些想法。
答案 1 :(得分:1)
嗯,我不知道我是否完全得到你的问题,但似乎你想要对树进行前序遍历。我不知道c#的语法,但我认为伪代码如下:
preorder_traversal(node)
if(node != NULL)
print(node)
preorder_traversal(left_sub_child)
preorder_traversal(right_sub_child)
else
return
答案 2 :(得分:1)
即使对于经验丰富的程序员来说,递归构建树也是一项艰巨的挑战。考虑到它最初发布于2011年3月,我意识到我在这个问题上的派对有点迟了。迟到总比没有好?
创建树的一个重要因素是确保正确格式化数据集。您只需要一种方法将父级与子级关联。一旦明确定义了关联,就可以开始编写解决方案代码。我选择使用这样的简单格式:
ParentId ChildId
1 2
1 3
2 4
3 5
等
一旦建立了这种关系,我就开发了一种递归方法来迭代数据集来构建树。
首先,我识别所有父节点并将它们存储在一个集合中,使用父ID和子ID的组合为每个父节点分配一个唯一的标识符:
private void IdentifyParentNodes()
{
SortedList<string, MyTreeNode> newParentNodes = new SortedList<string,MyTreeNode>();
Dictionary<string, string> parents = new Dictionary<string, string>();
foreach (MyTreeNode oParent in MyTreeDataSource.Values)
{
if (!parents.ContainsValue(oParent.ParentId))
{
parents.Add(oParent.ParentId + "." + oParent.ChildId, oParent.ParentId);
newParentNodes.Add(oParent.ParentId + "." + oParent.ChildId, oParent);
}
}
this._parentNodes = newParentNodes;
}
然后根调用方法将遍历父节点并调用递归方法来构建树:
// Build the rest of the tree
foreach (MyTreeNode node in ParentNodes.Values)
{
RecursivelyBuildTree(node);
}
递归方法:
private void RecursivelyBuildTree(MyTreeNode node)
{
int nodePosition = 0;
_renderedTree.Append(FormatNode(MyTreeNodeType.Parent, node, 0));
_renderedTree.Append(NodeContainer("open", node.ParentId));
foreach (MyTreeNode child in GetChildren(node.ParentId).Values)
{
nodePosition++;
if (IsParent(child.ChildId))
{
RecursivelyBuildTree(child);
}
else
{
_renderedTree.Append(FormatNode(MyTreeNodeType.Leaf, child, nodePosition));
}
}
_renderedTree.Append(NodeContainer("close", node.ParentId));
}
用于获取父母子女的方法:
private SortedList<string, MyTreeNode> GetChildren(string parentId)
{
SortedList<string, MyTreeNode> childNodes = new SortedList<string, MyTreeNode>();
foreach (MyTreeNode node in this.MyTreeDataSource.Values)
{
if (node.ParentId == parentId)
{
childNodes.Add(node.ParentId + node.ChildId, node);
}
}
return childNodes;
}
不是那么复杂或优雅,但它完成了工作。这是写在2007年的时间框架,所以这是旧的代码,但它仍然有效。 :-)希望这有帮助。