Algorithm 由前序构造二叉树
这是一个亚马逊采访问题。有谁能给出一个算法来做到这一点 存在具有以下属性的二叉树:Algorithm 由前序构造二叉树,algorithm,binary-tree,Algorithm,Binary Tree,这是一个亚马逊采访问题。有谁能给出一个算法来做到这一点 存在具有以下属性的二叉树: 它的所有内部节点都有值'N',所有叶子都有值'L' 每个节点要么有两个子节点,要么没有子节点 给定其前序,构造树并返回根节点。我可以想到一种递归算法 head=新节点。 删除预排序字符串中的第一个字符 调用f(head,preorderString) 递归函数f(节点,s) -从s中删除第一个字符,如果L,则将其作为叶附加到节点。 否则创建一个nodeLeft,附加到节点,调用f(nodeLeft,s) -从
- 它的所有内部节点都有值
,所有叶子都有值'N'
'L'
- 每个节点要么有两个子节点,要么没有子节点李>
给定其前序,构造树并返回根节点。我可以想到一种递归算法
head
=新节点。
删除预排序字符串中的第一个字符
调用f(head,preorderString)
递归函数f(节点,s)
-从s中删除第一个字符,如果L
,则将其作为叶附加到节点。
否则创建一个nodeLeft,附加到节点,调用f(nodeLeft,s)
-从s中删除第一个字符,如果L
,则将其作为叶附加到节点。
否则创建一个noderlight,附加到节点,调用f(noderlight,s)由于保证每个内部节点正好有2个子节点,我们可以简单地使用它递归地构建树
我们使用提供的输入调用函数,它检查得到的第一个字符。如果它是一个叶节点,它只返回一个叶。如果它是一个内部节点,它只调用自己的左、右子树,并返回使用该节点作为根、左、右子树作为左、右子树形成的树
代码如下(在Python中)。注意,我使用tuple
s表示节点,因此树是tuple
的tuple
#! /usr/bin/env python
from collections import deque
def build_tree(pre_order):
root=pre_order.popleft()
if root=='L':
return root
else:
return (root,build_tree(pre_order),build_tree(pre_order))
if __name__=='__main__':
print build_tree(deque("NNLLL"))
编辑:Java代码
import java.util.*;
class Preorder{
public static Node buildTree(List<Character> preorder){
char token=preorder.remove(0);
if (token=='L'){
return new Node(token,null,null);
}
else{
return new Node(token,buildTree(preorder),buildTree(preorder));
}
}
public static void main(String args[]){
List<Character> tokens=new LinkedList<Character>();
String input="NNLLL";
for(int i=0;i<input.length();i++) tokens.add(input.charAt(i));
System.out.println(buildTree(tokens));
}
}
class Node{
char value;
Node left,right;
public Node(char value, Node left, Node right){
this.value=value;
this.left=left;
this.right=right;
}
public String toString(){
if (left==null && right==null){
return "("+value+")";
}
else{
return "("+value+", "+left+", "+right+")";
}
}
}
import java.util.*;
类前序{
公共静态节点构建树(列表预排序){
char-token=preorder.remove(0);
如果(标记=='L'){
返回新节点(令牌,空,空);
}
否则{
返回新节点(令牌、buildTree(预订单)、buildTree(预订单));
}
}
公共静态void main(字符串参数[]){
列表标记=新的LinkedList();
字符串输入=“NNLLL”;
对于(int i=0;i我认为关键点是认识到相邻节点有三种可能性:NN、NL?、L?(`?''表示N或L)
NN:第二个N是第一个N的左子代,但我们不知道第一个N的右子代是什么
NL?:第二个N是第一个N的左子级,第一个N的右子级是
L:?是堆栈顶部的正确子级
之所以使用堆栈,是因为当我们在预排序序列中读取一个节点时,我们不知道它的右子节点在哪里(我们知道它的左子节点在哪里,只要它有一个)。堆栈存储该节点,以便当它的右子节点出现时,我们可以弹出它并完成它的右链接
NODE * preorder2tree(void)
{
NODE * head = next_node();
NODE * p = head;
NODE * q;
while (1) {
q = next_node();
if (!q)
break;
/* possibilities of adjacent nodes:
* NN, NL?, L?
*/
if (p->val == 'N') {
p->L = q;
if (q->val == 'N') { /* NN */
push(p);
p = q;
} else { /* NL? */
q = next_node();
p->R = q;
p = q;
}
} else { /* L? */
p = pop();
p->R = q;
p = q;
}
}
return head;
}
上面的代码是使用一些简单的案例进行测试的。希望它是正确的。以下是java程序:
导入java.util.*
类预排序\u给定\u NNNLL
{
static Stack stk=new Stack();
静态节点根=null;
静态类节点
{
字符值;
左淋巴结;
节点权;
公共节点(字符值)
{
这个。值=值;
this.left=null;
this.right=null;
}
}
公共静态节点stkoper()
{
节点posr=null,posn=null,posl=null;
posr=stk.pop();
if(stk.empty())
{
stk.push(posr);
返回null;
}
其他的
posl=stk.pop();
if(stk.empty())
{
stk.push(posl);
stk.push(posr);
返回null;
}
其他的
{
posn=stk.pop();
}
如果(posn.value='N'&&posl.value='L'&&posr.value='L')
{
root=buildtree(posn、posl、posr);
if(stk.empty())
{
返回根;
}
其他的
{
stk.push(根);
root=stkoper();
}
}
其他的
{
stk.push(posn);
stk.push(posl);
stk.push(posr);
}
返回根;
}
公共静态节点构建树(节点posn、节点posl、节点posr)
{
posn.left=posl;
posn.right=posr;
posn.value='L';
返回posn;
}
公共静态无效序(节点根)
{
if(root!=null)
{
顺序(根。左);
if((root.left==null)和&(root.right==null))
系统输出打印项次(“L”);
其他的
系统输出打印项次(“N”);
顺序(root.right);
}
}
公共静态void main(字符串参数[]){
字符串输入=“nnnllll”;
char[]pre=input.toCharArray();
对于(int i=0;i
}构造函数执行实际的树构造。代码片段是您上面提到的Geeksforgeks问题的解决方案
struct Node*construct(int &index, Node*root, int pre[], int n, char preLN[])
{
Node*nodeptr;
if(index==n)
{
return NULL;
}
if(root==NULL)
{
nodeptr = newNode(pre[index]);
}
if(preLN[index]=='N')
{
index = index+1;
nodeptr->left = construct(index, nodeptr->left, pre,n,preLN);
index = index+1;
nodeptr->right = construct(index, nodeptr->right,pre,n,preLN);
return nodeptr;
}
return nodeptr;
}
struct Node *constructTree(int n, int pre[], char preLN[])
{
int index =0;
Node*root = construct(index,NULL,pre,n,preLN);
return root;
}
注意事项:
索引已声明为引用变量,因此在返回到父节点时,函数将从索引的总体最新值开始构建树,而不是从最初执行调用时函数所拥有的索引值开始构建树
由于前序遍历遵循节点的根、左、右序列,所以左右子树的索引值不同
希望能有所帮助。你真的应该了解数据结构,但预顺序只是根、左节点、右节点。@TrevorMA-这是真的,但这不是问题所在。想法是如何在给定遍历的情况下重建树,这要求你知道的不仅仅是预顺序。如果你能用java或c提供代码,它将太好了。提前谢谢。@Nohsib:co补充道
struct Node*construct(int &index, Node*root, int pre[], int n, char preLN[])
{
Node*nodeptr;
if(index==n)
{
return NULL;
}
if(root==NULL)
{
nodeptr = newNode(pre[index]);
}
if(preLN[index]=='N')
{
index = index+1;
nodeptr->left = construct(index, nodeptr->left, pre,n,preLN);
index = index+1;
nodeptr->right = construct(index, nodeptr->right,pre,n,preLN);
return nodeptr;
}
return nodeptr;
}
struct Node *constructTree(int n, int pre[], char preLN[])
{
int index =0;
Node*root = construct(index,NULL,pre,n,preLN);
return root;
}