首先,您的前序遍历代码以相反的顺序遍历子代。当您按顺序将孩子推入堆栈时,它们会以相反的顺序弹出,导致不正确的行为。它应该是这样的:
static List<Node> preorderTraversal(Node root) {
List<Node> list = new ArrayList<>();
if (root == null) return list;
Stack<Node> stack = new Stack<>();
stack.push(root);
while (!stack.empty()) {
root = stack.pop();
list.add(root);
if (root.children != null) {
// iterate in reverse
for (int i = root.children.size() - 1; i >= 0; i--) {
Node child = root.children.get(i);
if (child != null) {
stack.push(child);
}
}
}
}
return list;
}
在我们查看修改后的前序遍历之前,看看如何递归地实现前序遍历会很有帮助:
static List<Node> preorderTraversalRecursive(Node root) {
ArrayList<Node> outList = new ArrayList<>();
preorderTraversalRecursive(root, outList);
return outList;
}
private static void preorderTraversalRecursive(Node root, ArrayList<Node> outList) {
if (root == null) {
return;
}
outList.add(root);
if (root.children != null) {
for (Node child : root.children) {
preorderTraversalRecursive(child, outList);
}
}
}
此代码在遍历其子节点之前简单地输出一个节点。
要将其变为修改后的前序遍历,您只需要跟踪在每个节点处理之前和之后递增的计数器,并在处理子节点之前和之后记录它以获得left和right价值观。在这里,当前的count 由方法返回,以便在处理子节点期间可以更改它,并且此更新值用于其父节点的right 值:
static List<MPTTNode> modifiedPreorderTraversalRecursive(Node root) {
ArrayList<MPTTNode> outList = new ArrayList<>();
modifiedPreorderTraversalRecursive(root, 0, outList);
return outList;
}
private static int modifiedPreorderTraversalRecursive(Node root, int counter, ArrayList<MPTTNode> outList) {
if (root == null) {
return counter;
}
counter++;
MPTTNode mpttNode = new MPTTNode(root.data, counter, 0); // right value is unknown, leave as 0 for now
outList.add(mpttNode);
if (root.children != null) {
for (Node child : root.children) {
// modify counter
counter = modifiedPreorderTraversalRecursive(child, counter, outList);
}
}
counter++;
mpttNode.right = counter;
return counter;
}
这也可以迭代地实现:
static List<MPTTNode> modifiedPreorderTraversal(Node root) {
List<MPTTNode> list = new ArrayList<>();
if (root == null) return list;
Stack<Node> stack = new Stack<>();
Stack<Integer> pending = new Stack<>();
stack.push(root);
int counter = 0;
while (!stack.empty()) {
root = stack.pop();
if (root == null) {
int nodeIndex = pending.pop();
counter++;
list.get(nodeIndex).right = counter;
continue;
}
counter++;
pending.push(list.size());
list.add(new MPTTNode(root.data, counter, 0)); // right value is unknown, leave as 0 for now
stack.push(null);
if (root.children != null) {
// iterate in reverse
for (int i = root.children.size() - 1; i >= 0; i--) {
Node child = root.children.get(i);
if (child != null) {
stack.push(child);
}
}
}
}
return list;
}
这通过使用pending 堆栈来跟踪输出列表(list)中父节点的索引来工作。它使用stack 堆栈中的null 值来表示节点的所有子节点都已被处理,因此其父节点的right 值是已知的。
这是我的所有代码,包括与链接问题中使用的相同的示例树:
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class Main {
public static void main(String[] args) {
Node tree = new Node("Electronics",
Arrays.asList(
new Node("Televisions",
Arrays.asList(
new Node("Tube"),
new Node("LCD"),
new Node("Plasma")
)
),
new Node("Portable Electronics",
Arrays.asList(
new Node("MP3 Players", Collections.singletonList(
new Node("Flash")
)),
new Node("CD Players"),
new Node("2 Way Radios")
)
)
)
);
List<MPTTNode> list1 = Node.modifiedPreorderTraversal(tree);
List<MPTTNode> list2 = Node.modifiedPreorderTraversalRecursive(tree);
if (!list1.equals(list2)) {
throw new RuntimeException("Traversals not equal");
}
for (var node : list1) {
System.out.printf("%-30s left:%5d, right:%5d
", node.data, node.left, node.right);
}
}
}
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
public class Node {
String data;
List<Node> children;
public Node(String data, List<Node> children) {
this.data = data;
this.children = children;
}
public Node(String data) {
this.data = data;
}
static List<Node> preorderTraversal(Node root) {
List<Node> list = new ArrayList<>();
if (root == null) return list;
Stack<Node> stack = new Stack<>();
stack.push(root);
while (!stack.empty()) {
root = stack.pop();
list.add(root);
if (root.children != null) {
// iterate in reverse
for (int i = root.children.size() - 1; i >= 0; i--) {
Node child = root.children.get(i);
if (child != null) {
stack.push(child);
}
}
}
}
return list;
}
static List<MPTTNode> modifiedPreorderTraversal(Node root) {
List<MPTTNode> list = new ArrayList<>();
if (root == null) return list;
Stack<Node> stack = new Stack<>();
Stack<Integer> pending = new Stack<>();
stack.push(root);
int counter = 0;
while (!stack.empty()) {
root = stack.pop();
if (root == null) {
int nodeIndex = pending.pop();
counter++;
list.get(nodeIndex).right = counter;
continue;
}
counter++;
pending.push(list.size());
list.add(new MPTTNode(root.data, counter, 0)); // right value is unknown, leave as 0 for now
stack.push(null);
if (root.children != null) {
// iterate in reverse
for (int i = root.children.size() - 1; i >= 0; i--) {
Node child = root.children.get(i);
if (child != null) {
stack.push(child);
}
}
}
}
return list;
}
static List<Node> preorderTraversalRecursive(Node root) {
ArrayList<Node> outList = new ArrayList<>();
preorderTraversalRecursive(root, outList);
return outList;
}
private static void preorderTraversalRecursive(Node root, ArrayList<Node> outList) {
if (root == null) {
return;
}
outList.add(root);
if (root.children != null) {
for (Node child : root.children) {
preorderTraversalRecursive(child, outList);
}
}
}
static List<MPTTNode> modifiedPreorderTraversalRecursive(Node root) {
ArrayList<MPTTNode> outList = new ArrayList<>();
modifiedPreorderTraversalRecursive(root, 0, outList);
return outList;
}
private static int modifiedPreorderTraversalRecursive(Node root, int counter, ArrayList<MPTTNode> outList) {
if (root == null) {
return counter;
}
counter++;
MPTTNode mpttNode = new MPTTNode(root.data, counter, 0);
outList.add(mpttNode);
if (root.children != null) {
for (Node child : root.children) {
counter = modifiedPreorderTraversalRecursive(child, counter, outList);
}
}
counter++;
mpttNode.right = counter;
return counter;
}
}
import java.util.Objects;
public class MPTTNode {
String data;
int left;
int right;
public MPTTNode(String data, int left, int right) {
this.data = data;
this.left = left;
this.right = right;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MPTTNode mpttNode = (MPTTNode) o;
return left == mpttNode.left && right == mpttNode.right && Objects.equals(data, mpttNode.data);
}
}
输出:
Electronics left: 1, right: 20
Televisions left: 2, right: 9
Tube left: 3, right: 4
LCD left: 5, right: 6
Plasma left: 7, right: 8
Portable Electronics left: 10, right: 19
MP3 Players left: 11, right: 14
Flash left: 12, right: 13
CD Players left: 15, right: 16
2 Way Radios left: 17, right: 18