Java 返回二叉树按序遍历的第n项
我提出了这段代码,但它需要一个全局变量秩。有没有什么方法可以解决这个问题而不需要全局变量Java 返回二叉树按序遍历的第n项,java,recursion,binary-tree,Java,Recursion,Binary Tree,我提出了这段代码,但它需要一个全局变量秩。有没有什么方法可以解决这个问题而不需要全局变量 int Rank = 0; public int inOrderTraversal(TreeNode node, int n){ if(node==null) return 0; int x=inOrderTraversal(node.left,n); if(x!=0)return x; Rank++; if(n==Rank) return node
int Rank = 0;
public int inOrderTraversal(TreeNode node, int n){
if(node==null)
return 0;
int x=inOrderTraversal(node.left,n);
if(x!=0)return x;
Rank++;
if(n==Rank) return node.data;
int y=inOrderTraversal(node.right,n);
int c= x==0 ? y:x;
return c;
}
我只是尝试在二叉树的顺序遍历中返回第n个项。您可以将TraversalState对象向下传递到递归调用链,并将访问的节点数存储在变量中:
class TraversalState {
public int rank = 0;
}
...
public int inOrderTraversal(TreeNode node, int n, TraversalState ts){
if(node==null)
return 0;
int x=inOrderTraversal(node.left,n, ts);
ts.rank++;
if(n==ts.rank) return node.data;
int y=inOrderTraversal(node.right,n, ts);
int c= x==0 ? y:x;
return c;
}
现在您的实现是线程安全的,因为它不使用全局对象。按如下方式调用它:
int r = inOrderTraversal(myNode, targetN, new TraversalState());
您可以将TraversalState对象向下传递到递归调用链,并将您访问的节点数存储在变量中:
class TraversalState {
public int rank = 0;
}
...
public int inOrderTraversal(TreeNode node, int n, TraversalState ts){
if(node==null)
return 0;
int x=inOrderTraversal(node.left,n, ts);
ts.rank++;
if(n==ts.rank) return node.data;
int y=inOrderTraversal(node.right,n, ts);
int c= x==0 ? y:x;
return c;
}
现在您的实现是线程安全的,因为它不使用全局对象。按如下方式调用它:
int r = inOrderTraversal(myNode, targetN, new TraversalState());
或者使用MutuableInt from而不是AtomicInteger
或者使用MutuableInt from而不是AtomicInteger。递归方法很容易理解,但是如果您的树形状不符合预期,那么您将受到最大堆栈深度的影响,这可能会更限制显式分配堆栈结构所消耗的堆内存。因此,最好将时间花在构建迭代walker上 首先,定义树节点本身的结构:
public final class TreeNode {
public final int data;
public final TreeNode left, right;
public TreeNode(int data, TreeNode left, TreeNode right) {
this.data = data;
this.left = left;
this.right = right;
}
public TreeNode(int data) {
this(data, null, null);
}
}
我们需要一种方法来对深度优先穿越树时发出的信号做出反应。从这些方法返回true表示访客希望继续行走;返回错误请求,要求尽快停止行走
public abstract class Visitor {
public boolean visitPre(TreeNode node) {
return true;
}
public boolean visitMid(TreeNode node) {
return true;
}
public boolean visitPost(TreeNode node) {
return true;
}
}
现在,定义迭代顺序行走算法:
final class InOrder {
private InOrder() {}
private static final class Breadcrumb {
public final TreeNode node;
public final boolean rightIsNext; // Not a great name.
public Breadcrumb(TreeNode node, boolean rightIsNext) {
this.node = node;
this.rightIsNext = rightIsNext;
}
public static Breadcrumb goingLeft(TreeNode departingPoint) {
return new Breadcrumb(departingPoint, true);
}
public static Breadcrumb goingRight(TreeNode departingPoint) {
return new Breadcrumb(departingPoint, false);
}
}
public static <T extends Visitor> T walk(TreeNode root, T visitor) {
if (null == root ||
null == visitor)
throw new NullPointerException();
final Deque<Breadcrumb> stack = new ArrayDeque<Breadcrumb>();
if (!visitor.visitPre(root))
return visitor;
for (;;) {
for (TreeNode left = root.left;
null != left;
root = left, left = root.left) {
if (!visitor.visitPre(left))
return visitor;
stack.push(Breadcrumb.goingLeft(root));
}
if (!visitor.visitMid(root))
return visitor;
final TreeNode right = root.right;
if (null != right) {
if (!visitor.visitPre(right))
return visitor;
stack.push(Breadcrumb.goingRight(root));
root = right;
} else {
if (!visitor.visitPost(root))
return visitor;
// Go back up the tree until we find a node with an unexplored right child.
for (;;) {
if (stack.isEmpty())
return visitor;
final Breadcrumb breadcrumb = stack.pop();
if (breadcrumb.rightIsNext) {
if (!visitor.visitMid(breadcrumb.node)) {
return visitor;
}
if (null != breadcrumb.node.right) {
if (!visitor.visitPre(breadcrumb.node.right))
return visitor;
stack.push(Breadcrumb.goingRight(breadcrumb.node));
root = breadcrumb.node.right;
break;
}
}
if (!visitor.visitPost(breadcrumb.node))
return visitor;
}
}
}
}
}
也就是说,有五个节点,其中包含数据4和数据5的两个叶子都是正确的子节点
final TreeNode root = new TreeNode(1,
new TreeNode(2,
new TreeNode(3,
null,
new TreeNode(4)),
null),
new TreeNode(5));
walk(root,
new Visitor() {
private final PrintStream ps = System.out;
@Override
public boolean visitPre(TreeNode node) {
trace(node, "Pre");
return true;
}
@Override
public boolean visitMid(TreeNode node) {
trace(node, "Mid");
return true;
}
@Override
public boolean visitPost(TreeNode node) {
trace(node, "Post");
return true;
}
private TreeNode trace(TreeNode node, String phase) {
ps.print(phase);
ps.print('(');
ps.print(node.data);
ps.println(')');
return node;
}
});
这将打印以下内容:
Pre(1)
Pre(2)
Pre(3)
Mid(3)
Pre(4)
Mid(4)
Post(4)
Post(3)
Mid(2)
Post(2)
Mid(1)
Pre(5)
Mid(5)
Post(5)
Post(1)
现在,您要求提供一种方便的方法来查找顺序漫游过程中遇到的第n个节点。我们将编写一个名为findNthInOrder的函数,其中参数n将零指定为遇到的第一个节点,该节点的左子树已被探索,一个指定第二个,依此类推:
private static TreeNode findNthInOrder(TreeNode root, final int n) {
if (n < 0)
throw new IllegalArgumentException();
return walk(root,
new Visitor() {
public TreeNode found = null;
private int remaining = n + 1;
@Override
public boolean visitMid(TreeNode node) {
if (0 == --remaining) {
found = node;
return false;
}
return true;
}
}).found;
}
这会将1打印到控制台,这与样本树上的上一次跟踪遍历相匹配:第四个,即基于零的索引3,根据上面发出的参数,中间跟踪针对的是数据值为1的根节点
总之,考虑建立足够的形式来定义游戏中的概念,这样你就可以在一个坚实的基础上更自信地写出这些特定的查询。
< P>递归方法是容易理解的,但是如果你的树形状不符合预期,那么你就在最大堆栈深度的支配下,这可能会对显式分配的堆栈结构消耗的堆内存造成更大的限制。因此,最好将时间花在构建迭代walker上 首先,定义树节点本身的结构:public final class TreeNode {
public final int data;
public final TreeNode left, right;
public TreeNode(int data, TreeNode left, TreeNode right) {
this.data = data;
this.left = left;
this.right = right;
}
public TreeNode(int data) {
this(data, null, null);
}
}
我们需要一种方法来对深度优先穿越树时发出的信号做出反应。从这些方法返回true表示访客希望继续行走;返回错误请求,要求尽快停止行走
public abstract class Visitor {
public boolean visitPre(TreeNode node) {
return true;
}
public boolean visitMid(TreeNode node) {
return true;
}
public boolean visitPost(TreeNode node) {
return true;
}
}
现在,定义迭代顺序行走算法:
final class InOrder {
private InOrder() {}
private static final class Breadcrumb {
public final TreeNode node;
public final boolean rightIsNext; // Not a great name.
public Breadcrumb(TreeNode node, boolean rightIsNext) {
this.node = node;
this.rightIsNext = rightIsNext;
}
public static Breadcrumb goingLeft(TreeNode departingPoint) {
return new Breadcrumb(departingPoint, true);
}
public static Breadcrumb goingRight(TreeNode departingPoint) {
return new Breadcrumb(departingPoint, false);
}
}
public static <T extends Visitor> T walk(TreeNode root, T visitor) {
if (null == root ||
null == visitor)
throw new NullPointerException();
final Deque<Breadcrumb> stack = new ArrayDeque<Breadcrumb>();
if (!visitor.visitPre(root))
return visitor;
for (;;) {
for (TreeNode left = root.left;
null != left;
root = left, left = root.left) {
if (!visitor.visitPre(left))
return visitor;
stack.push(Breadcrumb.goingLeft(root));
}
if (!visitor.visitMid(root))
return visitor;
final TreeNode right = root.right;
if (null != right) {
if (!visitor.visitPre(right))
return visitor;
stack.push(Breadcrumb.goingRight(root));
root = right;
} else {
if (!visitor.visitPost(root))
return visitor;
// Go back up the tree until we find a node with an unexplored right child.
for (;;) {
if (stack.isEmpty())
return visitor;
final Breadcrumb breadcrumb = stack.pop();
if (breadcrumb.rightIsNext) {
if (!visitor.visitMid(breadcrumb.node)) {
return visitor;
}
if (null != breadcrumb.node.right) {
if (!visitor.visitPre(breadcrumb.node.right))
return visitor;
stack.push(Breadcrumb.goingRight(breadcrumb.node));
root = breadcrumb.node.right;
break;
}
}
if (!visitor.visitPost(breadcrumb.node))
return visitor;
}
}
}
}
}
也就是说,有五个节点,其中包含数据4和数据5的两个叶子都是正确的子节点
final TreeNode root = new TreeNode(1,
new TreeNode(2,
new TreeNode(3,
null,
new TreeNode(4)),
null),
new TreeNode(5));
walk(root,
new Visitor() {
private final PrintStream ps = System.out;
@Override
public boolean visitPre(TreeNode node) {
trace(node, "Pre");
return true;
}
@Override
public boolean visitMid(TreeNode node) {
trace(node, "Mid");
return true;
}
@Override
public boolean visitPost(TreeNode node) {
trace(node, "Post");
return true;
}
private TreeNode trace(TreeNode node, String phase) {
ps.print(phase);
ps.print('(');
ps.print(node.data);
ps.println(')');
return node;
}
});
这将打印以下内容:
Pre(1)
Pre(2)
Pre(3)
Mid(3)
Pre(4)
Mid(4)
Post(4)
Post(3)
Mid(2)
Post(2)
Mid(1)
Pre(5)
Mid(5)
Post(5)
Post(1)
现在,您要求提供一种方便的方法来查找顺序漫游过程中遇到的第n个节点。我们将编写一个名为findNthInOrder的函数,其中参数n将零指定为遇到的第一个节点,该节点的左子树已被探索,一个指定第二个,依此类推:
private static TreeNode findNthInOrder(TreeNode root, final int n) {
if (n < 0)
throw new IllegalArgumentException();
return walk(root,
new Visitor() {
public TreeNode found = null;
private int remaining = n + 1;
@Override
public boolean visitMid(TreeNode node) {
if (0 == --remaining) {
found = node;
return false;
}
return true;
}
}).found;
}
这会将1打印到控制台,这与样本树上的上一次跟踪遍历相匹配:第四个,即基于零的索引3,根据上面发出的参数,中间跟踪针对的是数据值为1的根节点
综上所述,考虑建立足够的形式来定义游戏中的概念,这样你就可以在一个坚实的基础上更自信地写出这些特定的查询。我不认为这能正常工作,在每个函数调用中你都在递减n。例如,假设树有10个节点,每个节点位于其父节点的左侧。n在到达顺序遍历中的第一个节点之前将递减10次。对,它可以修改为仅查看左/右是否为null,如果节点为null,则不递减n。右==null rightVal=0我认为这不会正常工作,您在每次函数调用中递减n。例如,假设树有10个节点,每个节点位于其父节点的左侧。n在到达顺序遍历中的第一个节点之前将递减10次。右侧,可以修改它以仅查看左/右是否为null,如果节点为null,则不递减n。右侧==null rightVal=0这没有意义。为什么要初始化x两次,而int c=x=0中的y在哪里?y:x;?这是一个关于设计的好问题。@ArjunPatel我在编辑之前复制粘贴了OP中的代码
通过查看编辑历史记录。第二个整数x应该是整数y。现在已经修好了,这没有意义。为什么要初始化x两次,而int c=x=0中的y在哪里?y:x;?这是关于设计的一个很好的问题。@ArjunPatel我复制粘贴了OP中的代码,然后由Kee编辑以查看编辑历史。第二个整数x应该是整数y。这个问题现在已经解决了。