简体   繁体   English

如何使用来自3个数组的数据实现对二叉树的有序,前序和后序遍历

[英]How to implement in-order, pre-order and post-order traversals of a binary tree with data from 3 arrays

I understand that the binary tree can be implemented easily this way: 我了解二叉树可以通过以下方式轻松实现:

class Node {
    int key;
    Node left, right;
    public Node(int item) {
        key = item;
        left = right = null;
    }
}

class BinaryTree {
    Node root;
    public BinaryTree() {
      root = null;
    }
}

Also the methods for traversal that I've figured out are: 我想出的遍历方法还有:

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 + " ");
}

However, I'm given this starter file where the tree data is in 3 arrays: key[],left[] and right[], so key[] elements are the data of the nodes, left and right elements are the indexes of the left and right child of the ith node, so Node root is keys[0], with left child keys[left[0]] and keys[right[0]. 但是,我给了这个起始文件 ,其中树数据位于3个数组中:key [],left []和right [],所以key []元素是节点的数据,left和right元素是的索引。第i个节点的左右子节点,因此节点根是keys [0],左子节点keys [left [0]]和keys [right [0]。

I'm not sure how (or if I need) to convert the 3 arrays into a Binary tree using the Node and BinaryTree classes. 我不确定如何(或如果需要)使用Node和BinaryTree类将3个数组转换为Binary树。 Where should the Node and BinaryTree classes should go? Node和BinaryTree类应该放在哪里? Outside of tree_orders? 在tree_orders之外? Inside of tree_orders but outside of TreeOrders? 在tree_orders内部但在TreeOrders外? (sorry about the "creative" naming convention, not mine) (对不起“创意”命名约定,不是我的)

Do I need to iterate over the three arrays to build the tree nodes? 我是否需要遍历三个数组以构建树节点?

I tried implementing the insert(int data) and insert(Node n, int data) methods below to convert the arrays into nodes but it doesn't seem to fill the tree. 我尝试实现下面的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;
}

It's just 5 months that I've started learning programming (picked Java) and I've worked with Trees before but this starter is an OOP puzzle for me, I'll need to recheck my OOP knowledge. 我刚开始学习编程(选Java)仅5个月,之前我就使用Trees,但是对于我来说,这是一个面向对象的难题,我需要重新检查我的面向对象的知识。

This is an example of how the input and output should show (-1 = null node / 5 = number of given nodes): 这是输入和输出应如何显示的示例(-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 

Your question is not very clear. 您的问题不是很清楚。 The title asks about traversal but you also have worries about reading 100.000 nodes and about giving nodes a name, and about iteration/recursion slowness. 标题询问有关遍历的问题,但您还担心读取100.000个节点,为节点指定名称以及迭代/递归慢度。 That's a whole muddled bundle of confusion! 那真是一团混乱!

The traversal logic you show looks OK at first glance. 乍一看,您显示的遍历逻辑看起来不错。

Assuming you want to build a binary tree using your Node class from the three arrays you could do this (you don't need the BinaryTree class, it only contains the root Node): 假设您想使用来自三个数组的Node类构建一个二叉树,您可以这样做(不需要BinaryTree类,它仅包含根Node):

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;
    }
}

I think 100.000 nodes is not that much. 我认为100.000个节点并不多。 Making it should not pose a problem either memory wise or speed wise (unless you start doing complex searching, indexing or other fun stuff). 无论是在内存方面还是在速度方面,使其都不会造成问题(除非您开始进行复杂的搜索,索引或其他有趣的工作)。 NOTE: after seeing the artificial limitations imposed on the Thread running this code, it might be a problem. 注意:在看到对运行此代码的线程施加的人为限制后,这可能是一个问题。

You don't have to store nodes in named variables or otherwise name them. 您不必将节点存储在命名变量中或以其他方式命名它们。 Just making sure the binary tree nodes refer to the correct children is enough. 只要确保二叉树节点引用正确的子节点就足够了。

EDIT: about your starter file 编辑:关于您的入门文件

This is total crap: 这是完全废话:

while (!tok.hasMoreElements())
            tok = new StringTokenizer(in.readLine());

Firstly StringTokenizer is a legacy class that should no longer be used (for new code). 首先,StringTokenizer是一个旧类,不应再使用(用于新代码)。 String.split() is the alternative to use nowadays. String.split()是当今使用的替代方法。 Furthermore, creating a new instance of StringTokenizer for each line is unnecessary and wasteful. 此外,为每行创建一个新的StringTokenizer实例是不必要且浪费的。 Are you bound to use this code as-is? 您是否必须按原样使用此代码?

And do I understand that you're supposed to enter your tree data from the command line? 而且我了解您应该从命令行输入树数据吗? Why not read the data from a file so you only have to type it in once? 为什么不从文件中读取数据,而只需要键入一次?

And how are you supposed to type in a valid binary tree? 您应该如何键入有效的二叉树? The values in left[] and right[] are actually indices of the key[], so you will have to figure out, whilst typing, in which index each child node will be stored? left []和right []中的值实际上是key []的索引,因此在键入时您必须弄清楚每个子节点将存储在哪个索引中? Crazy stuff. 疯狂的事情。 The person setting you this task much be a little bit sadistic. 设置您这项任务的人会有点虐待。 There are much better ways to store binary trees in a single array, see for example this lecture . 有很多更好的方法将二进制树存储在单个数组中,例如,请参阅本讲座

This is also remarkable: 这也很了不起:

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();
}

Here the class tree_orders (sic.) is run in a Thread with a stack size of 1 << 23 . 在这里,类tree_orders (sic。)在堆栈大小为1 << 23的线程中运行。 This stack size is a hint to the Java runtime to limit the memory needed to keep track of nested method calls to 8388608 bytes. 此堆栈大小是Java运行时的一个提示,它将限制跟踪嵌套方法调用所需的内存限制为8388608字节。 This is probably intended to either make you hit a limit when implementing this recursively, or to ensure that you don't (I haven't figured out which one it is). 这可能是为了使您在递归地实现此目标时达到一个极限,或者确保您没有达到极限(我还没有弄清楚它是哪个)。

In order to apply my TreeMaker in this example, you could use in the run() method : 为了在此示例中应用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);
}

But I get the impression you are supposed to just implement the three given methods and do the traversal on the existing data structure (3 arrays). 但是我得到的印象是,您应该只实现这三个给定的方法,并在现有数据结构(3个数组)上进行遍历。

What a poor design, those arrays. 糟糕的设计,那些数组。 Anyway, if you want or need to stick to it, traversing the tree is not too bad: 无论如何,如果您想要或需要坚持下去,遍历树还不错:

void printInorder(int index) {
    if (index == -1) return;
    printInorder(left[index]);
    System.out.print(keys[index] + " ");
    printInorder(right[index]);
}

Similarly for the other traversal orders. 其他遍历顺序也是如此。 I am assuming -1 in either left or right means no decendant. 我假设leftright -1表示没有后代。 To print the whole tree, call printInOrder(0) since the root is in index 0. 要打印整个树,请调用printInOrder(0)因为根在索引0中。

Edit: I believe your example gives the following arrays: 编辑:我相信你的例子给出了以下数组:

    int[] keys = { 4, 2, 5, 1, 3 };
    // indices 0..4
    int[] left = { 1, 3, -1, -1, -1 };
    int[] right = { 2, 4, -1, -1, -1 };

With these, calling printInorder(0) and then System.out.println() prints: 有了这些,先调用printInorder(0) ,然后调用System.out.println()打印:

1 2 3 4 5 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM