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

时间:2016-09-08 14:42:57

标签: java algorithm binary-tree tree-traversal

我知道二叉树可以通过这种方式轻松实现:

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 []元素是节点的数据,左右元素是第i个节点的左右子节点的索引,因此节点根是键[0],左子键[left [0]]和键[right [0]。

我不确定如何(或者我需要)使用Node和BinaryTree类将3个数组转换为二叉树。 Node和BinaryTree类应该去哪里?在tree_orders之外?在tree_orders里面但在TreeOrders之外? (抱歉“创意”命名约定,而不是我的)

我是否需要迭代这三个数组来构建树节点?

我尝试在下面实现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),我之前和Tree一起工作过,但这个启动器对我来说是一个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 

2 个答案:

答案 0 :(得分:3)

你的问题不是很清楚。标题询问遍历,但您也担心读取100.000个节点以及给节点命名,以及迭代/递归缓慢。这是一堆混乱的混乱!

您展示的遍历逻辑乍一看看起来不错。

假设您想使用三个数组中的Node类构建二叉树,您可以这样做(您不需要BinaryTree类,它只包含根节点):

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个节点并不多。使它不应该是内存明智或速度明智的问题(除非你开始做复杂的搜索,索引或其他有趣的东西)。注意:在看到运行此代码的线程施加的人为限制后,可能会出现问题。

您不必将节点存储在命名变量中或以其他方式命名它们。只是确保二叉树节点引用正确的子节点就足够了。

编辑:关于你的入门文件

这是完全废话:

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

首先,StringTokenizer是一个不再使用的遗留类(对于新代码)。 String.split()是现在使用的替代方法。此外,为每一行创建一个新的StringTokenizer实例是不必要和浪费的。您是否必须按原样使用此代码?

我是否理解您应该从命令行输入树数据?为什么不从文件中读取数据,所以你只需要输入一次?

你应该怎么输入有效的二叉树? left []和right []中的值实际上是key []的索引,因此在键入时,您必须弄清楚每个子节点将存储在哪个索引中?疯狂的事情。让你完成这项任务的人有点虐待狂。有更好的方法可以在单个数组中存储二进制树,例如参见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();
}

此处,类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个数组)。

答案 1 :(得分:1)

这是一个糟糕的设计,那些数组。无论如何,如果你想要或需要坚持下去,遍历树也不错:

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

同样适用于其他遍历订单。我假设-1left中的right表示没有后代。要打印整个树,请调用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