如何使用来自 3 个数组的数据实现二叉树的中序、前序和 post 序遍历
How to implement in-order, pre-order and post-order traversals of a binary tree with data from 3 arrays
我明白二叉树可以这样轻松实现:
class Node {
int key;
Node left, right;
public Node(int item) {
key = item;
left = right = null;
}
}
class BinaryTree {
Node root;
public BinaryTree() {
root = null;
}
}
另外我想到的遍历方法是:
void printInorder(Node node) {
if (node == null) return;
printInorder(node.left);
System.out.print(node.key + " ");
printInorder(node.right);
}
void printPreorder(Node node) {
if (node == null) return;
System.out.print(node.key + " ");
printPreorder(node.left);
printPreorder(node.right);
}
void printPostorder(Node node) {
if (node == null) return;
printPostorder(node.left);
printPostorder(node.right);
System.out.print(node.key + " ");
}
但是,我得到 this starter file 其中树数据位于 3 个数组中:key[]、left[] 和 right[],因此 key[] 元素是节点的数据,左而right元素是第i个节点的左右子节点的索引,所以节点根是keys[0],左子keys[left[0]]和keys[right[0].
我不确定如何(或者如果我需要)使用 Node 和 BinaryTree 类 将 3 个数组转换为二叉树。 节点和二叉树类应该去哪里?在tree_orders之外?在 tree_orders 之内但在 TreeOrders 之外? (抱歉 "creative" 命名约定,不是我的)
是否需要遍历三个数组来构建树节点?
我尝试实现下面的 insert(int data) 和 insert(Node n, int data) 方法将数组转换为节点,但它似乎没有填满树。
Node insert(int data) {
root = insert(root, data);
return node;
}
Node insert(Node node, int data) {
if (node == null) {
node = new Node(data)
}
else {
if (node.left == null) insert(node.left, data);
else insert(node.right, data);
}
return node;
}
我开始学习编程才 5 个月(选择 Java)并且我之前使用过 Trees,但是这个初学者对我来说是一个 OOP 难题,我需要重新检查我的 OOP知识.
这是输入和输出应如何显示的示例(-1 = 空节点/5 = 给定节点数):
Input:
5
4 1 2
2 3 4
5 -1 -1
1 -1 -1
3 -1 -1
Output:
1 2 3 4 5
4 2 1 3 5
1 3 2 5 4
你的问题不是很清楚。标题询问遍历,但您也担心读取 100.000 个节点和给节点命名,以及 iteration/recursion 缓慢。真是一团糟!
你展示的遍历逻辑乍一看没问题。
假设您想使用来自三个数组的节点 class 构建一个二叉树,您可以这样做(您不需要 BinaryTree class,它只包含根节点) :
class TreeMaker {
private int[] keys, left, right;
TreeMaker(int[] keys, int[] left, int[] right) {
this.keys = keys;
this.left = left;
this.right = right;
}
public Node make() {
return makeNode(0);
}
private Node makeNode(int index) {
if (index < 0 || index >= keys.length) {
return null;
}
Node node = new Node(keys[index]);
node.left = makeNode(left[index]);
node.right = makeNode(right[index]);
return node;
}
}
我认为 100.000 个节点并不算多。让它不应该在内存方面或速度方面造成问题(除非你开始进行复杂的搜索、索引或其他有趣的事情)。注意:在看到对 Thread 运行ning 这段代码施加的人为限制后,这可能是个问题。
您不必将节点存储在命名变量中或以其他方式命名它们。只需确保二叉树节点引用正确的 children 就足够了。
编辑:关于您的入门文件
这完全是废话:
while (!tok.hasMoreElements())
tok = new StringTokenizer(in.readLine());
首先,StringTokenizer 是遗留的 class,不应再使用(对于新代码)。 String.split() 是现在使用的替代方法。此外,为每一行创建一个新的 StringTokenizer 实例是不必要且浪费的。您一定要使用此代码 as-is 吗?
我知道您应该从命令行输入树数据吗?为什么不从文件中读取数据,这样您只需输入一次呢?
您应该如何输入有效的二叉树? left[] 和 right[] 中的值实际上是 key[] 的索引,因此您必须在键入时弄清楚每个 child 节点将存储在哪个索引中?疯狂的事情。给你布置这项任务的人有点虐待狂。有很多更好的方法可以将二叉树存储在一个数组中,例如 this lecture.
这也很了不起:
static public void main(String[] args) throws IOException {
new Thread(null, new Runnable() {
public void run() {
try {
new tree_orders().run();
} catch (IOException e) {
}
}
}, "1", 1 << 26).start();
}
此处 class tree_orders
(原文如此)在堆栈大小为 1 << 23
的线程中为 运行。此堆栈大小提示 Java 运行 时间将跟踪嵌套方法调用所需的内存限制为 8388608 字节。这可能是为了让你在递归实现时达到极限,或者确保你不会(我还没弄清楚是哪一个)。
为了在此示例中应用我的 TreeMaker,您可以在 run() method
:
public void run() throws IOException {
TreeOrders tree = new TreeOrders();
tree.read();
TreeMaker treeMaker = new TreeMaker(tree.keys, tree.left, tree.right);
Node root = treeMaker.make();
printInorder(root);
printPreorder(root);
printPostorder(root);
}
但我的印象是你应该只实现三个给定的方法并对现有数据结构(3 个数组)进行遍历。
多么糟糕的设计,那些数组。不管怎样,如果你想或需要坚持下去,遍历树也不错:
void printInorder(int index) {
if (index == -1) return;
printInorder(left[index]);
System.out.print(keys[index] + " ");
printInorder(right[index]);
}
其他遍历顺序同理。我假设 left
或 right
中的 -1
表示没有后代。要打印整棵树,请调用 printInOrder(0)
因为根在索引 0.
编辑:我相信您的示例给出了以下数组:
int[] keys = { 4, 2, 5, 1, 3 };
// indices 0..4
int[] left = { 1, 3, -1, -1, -1 };
int[] right = { 2, 4, -1, -1, -1 };
有了这些,调用 printInorder(0)
然后 System.out.println()
打印:
1 2 3 4 5
我明白二叉树可以这样轻松实现:
class Node {
int key;
Node left, right;
public Node(int item) {
key = item;
left = right = null;
}
}
class BinaryTree {
Node root;
public BinaryTree() {
root = null;
}
}
另外我想到的遍历方法是:
void printInorder(Node node) {
if (node == null) return;
printInorder(node.left);
System.out.print(node.key + " ");
printInorder(node.right);
}
void printPreorder(Node node) {
if (node == null) return;
System.out.print(node.key + " ");
printPreorder(node.left);
printPreorder(node.right);
}
void printPostorder(Node node) {
if (node == null) return;
printPostorder(node.left);
printPostorder(node.right);
System.out.print(node.key + " ");
}
但是,我得到 this starter file 其中树数据位于 3 个数组中:key[]、left[] 和 right[],因此 key[] 元素是节点的数据,左而right元素是第i个节点的左右子节点的索引,所以节点根是keys[0],左子keys[left[0]]和keys[right[0].
我不确定如何(或者如果我需要)使用 Node 和 BinaryTree 类 将 3 个数组转换为二叉树。 节点和二叉树类应该去哪里?在tree_orders之外?在 tree_orders 之内但在 TreeOrders 之外? (抱歉 "creative" 命名约定,不是我的)
是否需要遍历三个数组来构建树节点?
我尝试实现下面的 insert(int data) 和 insert(Node n, int data) 方法将数组转换为节点,但它似乎没有填满树。
Node insert(int data) {
root = insert(root, data);
return node;
}
Node insert(Node node, int data) {
if (node == null) {
node = new Node(data)
}
else {
if (node.left == null) insert(node.left, data);
else insert(node.right, data);
}
return node;
}
我开始学习编程才 5 个月(选择 Java)并且我之前使用过 Trees,但是这个初学者对我来说是一个 OOP 难题,我需要重新检查我的 OOP知识.
这是输入和输出应如何显示的示例(-1 = 空节点/5 = 给定节点数):
Input:
5
4 1 2
2 3 4
5 -1 -1
1 -1 -1
3 -1 -1
Output:
1 2 3 4 5
4 2 1 3 5
1 3 2 5 4
你的问题不是很清楚。标题询问遍历,但您也担心读取 100.000 个节点和给节点命名,以及 iteration/recursion 缓慢。真是一团糟!
你展示的遍历逻辑乍一看没问题。
假设您想使用来自三个数组的节点 class 构建一个二叉树,您可以这样做(您不需要 BinaryTree class,它只包含根节点) :
class TreeMaker {
private int[] keys, left, right;
TreeMaker(int[] keys, int[] left, int[] right) {
this.keys = keys;
this.left = left;
this.right = right;
}
public Node make() {
return makeNode(0);
}
private Node makeNode(int index) {
if (index < 0 || index >= keys.length) {
return null;
}
Node node = new Node(keys[index]);
node.left = makeNode(left[index]);
node.right = makeNode(right[index]);
return node;
}
}
我认为 100.000 个节点并不算多。让它不应该在内存方面或速度方面造成问题(除非你开始进行复杂的搜索、索引或其他有趣的事情)。注意:在看到对 Thread 运行ning 这段代码施加的人为限制后,这可能是个问题。
您不必将节点存储在命名变量中或以其他方式命名它们。只需确保二叉树节点引用正确的 children 就足够了。
编辑:关于您的入门文件
这完全是废话:
while (!tok.hasMoreElements())
tok = new StringTokenizer(in.readLine());
首先,StringTokenizer 是遗留的 class,不应再使用(对于新代码)。 String.split() 是现在使用的替代方法。此外,为每一行创建一个新的 StringTokenizer 实例是不必要且浪费的。您一定要使用此代码 as-is 吗?
我知道您应该从命令行输入树数据吗?为什么不从文件中读取数据,这样您只需输入一次呢?
您应该如何输入有效的二叉树? left[] 和 right[] 中的值实际上是 key[] 的索引,因此您必须在键入时弄清楚每个 child 节点将存储在哪个索引中?疯狂的事情。给你布置这项任务的人有点虐待狂。有很多更好的方法可以将二叉树存储在一个数组中,例如 this lecture.
这也很了不起:
static public void main(String[] args) throws IOException {
new Thread(null, new Runnable() {
public void run() {
try {
new tree_orders().run();
} catch (IOException e) {
}
}
}, "1", 1 << 26).start();
}
此处 class tree_orders
(原文如此)在堆栈大小为 1 << 23
的线程中为 运行。此堆栈大小提示 Java 运行 时间将跟踪嵌套方法调用所需的内存限制为 8388608 字节。这可能是为了让你在递归实现时达到极限,或者确保你不会(我还没弄清楚是哪一个)。
为了在此示例中应用我的 TreeMaker,您可以在 run() method
:
public void run() throws IOException {
TreeOrders tree = new TreeOrders();
tree.read();
TreeMaker treeMaker = new TreeMaker(tree.keys, tree.left, tree.right);
Node root = treeMaker.make();
printInorder(root);
printPreorder(root);
printPostorder(root);
}
但我的印象是你应该只实现三个给定的方法并对现有数据结构(3 个数组)进行遍历。
多么糟糕的设计,那些数组。不管怎样,如果你想或需要坚持下去,遍历树也不错:
void printInorder(int index) {
if (index == -1) return;
printInorder(left[index]);
System.out.print(keys[index] + " ");
printInorder(right[index]);
}
其他遍历顺序同理。我假设 left
或 right
中的 -1
表示没有后代。要打印整棵树,请调用 printInOrder(0)
因为根在索引 0.
编辑:我相信您的示例给出了以下数组:
int[] keys = { 4, 2, 5, 1, 3 };
// indices 0..4
int[] left = { 1, 3, -1, -1, -1 };
int[] right = { 2, 4, -1, -1, -1 };
有了这些,调用 printInorder(0)
然后 System.out.println()
打印:
1 2 3 4 5