如何以后序方式遍历一个先序创建的列表?

huangapple go评论143阅读模式
英文:

How to traverse a list in postorder manner which was made in preorder?

问题

在Java中,我有一个列表,其中每个元素包含leftName和rightName。如果left或rightName为null,则表示它有另一个叶子/节点(如果它们都为null,则有2个叶子)。该列表是从树的前序遍历中生成的,现在我想以后序方式遍历元素。

除了null之外,你无法通过文本来确定列表的顺序。(如果是有序数字的情况会容易得多)。

列表示例:
[[null,null],[something1,something2],[otherthing1,otherthing2]]

期望输出
something1,something2,otherthing1,otherthing2

另一个列表示例:
[[something,null],[other,secondOther],[otherthing1,otherthing2]]

期望输出
something,other,secondother,otherthing1,otherthing2

我已成功遍历整个列表的左侧,但对我来说找到左侧最后一个元素的索引很难。(如果你可以动态地知道这个数字,你可以处理树的右侧)。

提前感谢你的帮助!

英文:

In java I have a list where each element consist of a leftName and rightName. If the left or rightName is null it indicates that it has an another leaf/node (if both of them are null they have 2 leaves). The list was made from a tree in preorder traversal, and now I would like to go through the the elements in postorder manner.

Other from the null-s you can not really know the order of the list by looking at the text. (In the case of ordered numbers it would be much easier).

> Example for the list:
> [[null,null],[something1,something2],[otherthing1,otherthing2]]
>
> Desired output
>
> something1,something2,otherthing1,otherthing2
>
> Another example for the list:
> [[something,null],[other,secondOther],[otherthing1,otherthing2]]
>
> Desired output
>
> something, other, secondother, otherthing1, otherthing2

I have managed to correctly traverse through the whole left side of the list, but finding the index of the last element in the left side is hard for me. (If you know this number dynamically you can process the right side of the tree).

Thanks for the help in advance!

答案1

得分: 2

以下是您要翻译的内容:


您写道:

> 现在我想以后序方式遍历元素

如果您不打算包括 null 项,那么以前序、中序或后序方式遍历元素都没有任何区别:输出将是相同的。

您描述的二叉树是一个没有数据的 二叉树,内部节点。遍历顺序(如前序、中序和后序)之间的区别在于何时访问 内部 节点:

  • "pre" 意味着首先访问内部节点,然后访问其子节点,
  • "in" 意味着在访问其左子节点和右子节点之间访问内部节点,
  • "post" 意味着在访问其子节点后访问内部节点。

但这不会影响它们访问叶子节点的相对顺序,因为它们都会在访问节点的右子节点之前访问其左子节点!对于所有三种遍历,叶子节点的访问顺序是相同的。

示例

您的示例有点小,所以这是一个不那么简单的示例,我临时用数字标记了内部节点:

                             _______1______ 
                            /              \
                         __2__              6
                        /     \            / \
                       3       5          7   I
                      / \     / \        / \
                     A   4   D   E      8   H
                        / \            / \
                       B   C          F   G

这是这棵树的遍历:

Pre-order:  1 2 3 A 4 B C 5 D E 6 7 8 F G H I
In-order:   A 3 B 4 C 2 D 5 E 1 F 8 G 7 H 6 I
Post-order: A B C 4 3 D E 5 2 F G 8 H 7 I 6 1

如果我们现在去掉内部节点的标签,只保留数据,我们会看到所有这些遍历对于这些数据的顺序都是相同的:

Pre-order:  A B C D E F G H I
In-order:   A B C D E F G H I
Post-order: A B C D E F G H I

算法

生成遍历的算法可以使用递归或显式堆栈。我选择了第二个选项。在这里,我将数据定义为字符串,但对于任何其他数据类型,也会类似:

    static List<String> collectLeaves(String[][] tree) {
        List<String> output = new ArrayList<>();
        Stack<String> stack = new Stack<>();
        stack.push(null);
        for (var pair : tree) {
            stack.push(pair[1]);
            stack.push(pair[0]);
            while (stack.peek() != null) {
                output.add(stack.pop()); // 数据
            }
            stack.pop(); // null
        }
        return output;
    }

以下是定义示例输入并使用上述函数的一些代码:

        String[][] input = {
            {null, null}, {null, null}, {"A", null}, {"B", "C"},
            {"D", "E"}, {null, "I"}, {null, "H"}, {"F", "G"},
        };
        var output = collectLeaves(input);
        for (var item : output) {
            System.out.print(item + " ");
        }
        System.out.println();

输出:

A B C D E F G H I

英文:

You write:

> now I would like to go through the the elements in postorder manner

If you don't intend to include the null items, then it wouldn't make any difference if you went through the elements in pre-order, in-order or post-order manner: the output will be the same.

The binary tree you describe is a full binary tree with no data in the internal nodes. The difference between traversal orders like pre-order, in-order and post-order, is when internal nodes are visited:

  • "pre" refers to first visiting an internal node, then its children,
  • "in" refers to visiting an internal node in between the visits of its left and right children,
  • "post" refers to visiting an internal node after having visited its children.

But this does not affect the relative order in which they visit leaf nodes, because they all visit a node's left child before its right child! The order of the leaf visits is the same for all three traversals.

Example

Your example was a bit small, so here is a less trivial example, where I have temporarily labeled the internal nodes with numbers:

                             _______1______ 
                            /              \
                         __2__              6
                        /     \            / \
                       3       5          7   I
                      / \     / \        / \
                     A   4   D   E      8   H
                        / \            / \
                       B   C          F   G

Here are the traversals for this tree:

Pre-order:  1 2 3 A 4 B C 5 D E 6 7 8 F G H I
In-order:   A 3 B 4 C 2 D 5 E 1 F 8 G 7 H 6 I
Post-order: A B C 4 3 D E 5 2 F G 8 H 7 I 6 1

If we now remove the labels of the internal nodes, and just keep the data, we see all these traversals have the same order for that data:

Pre-order:  A B C D E F G H I
In-order:   A B C D E F G H I
Post-order: A B C D E F G H I

Algorithm

The algorithm to make the traversal can use recursion or an explicit stack. I went with the second option. Here I have defined the data as strings, but it would be similar for any other data type:

    static List&lt;String&gt; collectLeaves(String[][] tree) {
        List&lt;String&gt; output = new ArrayList&lt;&gt;();
        Stack&lt;String&gt; stack = new Stack&lt;&gt;();
        stack.push(null);
        for (var pair : tree) {
            stack.push(pair[1]);
            stack.push(pair[0]);
            while (stack.peek() != null) {
                output.add(stack.pop()); // data
            }
            stack.pop(); // null
        }
        return output;
    }

And here is some code to define the example as input and use the above function:

        String[][] input = {
            {null, null}, {null, null}, {&quot;A&quot;, null}, {&quot;B&quot;, &quot;C&quot;},
            {&quot;D&quot;, &quot;E&quot;}, {null, &quot;I&quot;}, {null, &quot;H&quot;}, {&quot;F&quot;, &quot;G&quot;},
        };
        var output = collectLeaves(input);
        for (var item : output) {
            System.out.print(item + &quot; &quot;);
        }
        System.out.println();

Output:

A B C D E F G H I

答案2

得分: 0

这产生了你发布的结果:

List<List<String>> input = ...;
List<String> result = input.stream()
  .flatMap(List::stream)
  .filter(Objects::nonNull)
  .collect(toList());
英文:

This produces the results you've posted:

List&lt;List&lt;String&gt;&gt; input = ...;
List&lt;String&gt; result = input.stream()
  .flatMap(List::stream)
  .filter(Objects::nonNull)
  .collect(toList());

huangapple
  • 本文由 发表于 2023年6月29日 06:36:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/76577103.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定