如何迭代二叉树?

发布于 2024-09-03 05:48:56 字数 227 浏览 2 评论 0原文

现在我

 private static void iterateall(BinaryTree foo) {
    if(foo!= null){
    System.out.println(foo.node);
    iterateall(foo.left);
    iterateall(foo.right);
   }
  }

可以将其更改为迭代而不是递归吗?

Right now I have

 private static void iterateall(BinaryTree foo) {
    if(foo!= null){
    System.out.println(foo.node);
    iterateall(foo.left);
    iterateall(foo.right);
   }
  }

Can you change it to Iteration instead of a recursion?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

埋葬我深情 2024-09-10 05:48:56

您正在寻找的是后继算法。

它的定义方式如下:

  • 第一条规则:树中的第一个节点是树中最左边的节点。
  • 下一条规则:节点的后继者是:
    • Next-R规则:如果有右子树,则为右子树中最左边的节点。
    • Next-U规则:否则,向上遍历树
      • 如果右转(即该节点是左子节点),则该父节点是后继节点
      • 如果左转(即该节点是右子节点),请继续向上。
      • 如果你不能再往上走,那就没有继任者

正如你所看到的,要使其工作,你需要一个父节点指针。


示例:

alt text

  • 第一个规则:树中的第一个节点是树中最左边的节点:(1)
  • Next-U 规则:自 (1)< /code> 没有右子树,我们转到 (3)。这是右转,因此 (3) 是下一个。
  • Next-R 规则:由于 (3) 有一个右子树,因此该子树中最左边的节点是下一个:(4)
  • Next-U 规则:由于 (4) 没有右子树,因此我们转到 (6)。这是右转,所以接下来是(6)
  • Next-R 规则:由于 (6) 有一个右子树,因此该子树中最左边的节点是下一个:(7)
  • Next-U 规则:由于 (7) 没有右子树,因此我们转到 (6)。这是左转,因此我们继续前往 (3)。这是左转,因此我们继续前往 (8)。这是右转,所以接下来是(8)
  • Next-R 规则:由于 (8) 有一个右子树,因此该子树中最左边的节点是下一个:(10)
  • Next-R 规则:由于 (10) 有一个右子树,因此该子树中最左边的节点是下一个:(13)
  • Next-U 规则:由于 (13) 没有右子树,因此我们转到 (14)。这是右转,所以接下来是(14)
  • Next-U 规则:由于 (14) 没有右子树,因此我们转到 (10)。这是左转,因此我们继续前往 (8)。这是左转,所以我们想继续向上,但由于 (8) 没有父节点,所以我们已经到达终点了。 (14) 没有后继者。

伪代码

Node getLeftMost(Node n)
  WHILE (n.leftChild != NULL)
    n = n.leftChild
  RETURN n

Node getFirst(Tree t)
  IF (t.root == NULL) RETURN NULL
  ELSE
     RETURN getLeftMost(t.root);

Node getNext(Node n)
  IF (n.rightChild != NULL)
     RETURN getLeftMost(n.rightChild)
  ELSE
     WHILE (n.parent != NULL AND n == n.parent.rightChild)
        n = n.parent;
     RETURN n.parent;

PROCEDURE iterateOver(Tree t)
  Node n = getFirst(t);
  WHILE n != NULL
     visit(n)
     n = getNext(n)

Java 代码

这是上述算法的简单实现:

public class SuccessorIteration {
    static class Node {
        final Node left;
        final Node right;
        final int key;
        Node parent;
        Node(int key, Node left, Node right) {
            this.key = key;
            this.left = left;
            this.right = right;
            if (left != null) left.parent = this;
            if (right != null) right.parent = this;
        }
        Node getLeftMost() {
            Node n = this;
            while (n.left != null) {
                n = n.left;
            }
            return n;
        }
        Node getNext() {
            if (right != null) {
                return right.getLeftMost();
            } else {
                Node n = this;
                while (n.parent != null && n == n.parent.right) {
                    n = n.parent;
                }
                return n.parent;
            }
        }
    }
}

然后您可以拥有如下所示的测试工具:

static Node C(int key, Node left, Node right) {
    return new Node(key, left, right);
}
static Node X(int key)             { return C(key, null, null);  }
static Node L(int key, Node left)  { return C(key, left, null);  }
static Node R(int key, Node right) { return C(key, null, right); }
public static void main(String[] args) {
    Node n =
        C(8,
            C(3,
                X(1),
                C(6,
                    X(4),
                    X(7)
                )
            ),
            R(10,
                L(14,
                    X(13)
                )
            )
        );
    Node current = n.getLeftMost();
    while (current != null) {
        System.out.print(current.key + " ");
        current = current.getNext();
    }
}

此打印:

1 3 4 6 7 8 10 13 14 

另请参阅

What you're looking for is a successor algorithm.

Here's how it can be defined:

  • First rule: The first node in the tree is the leftmost node in the tree.
  • Next rule: The successor of a node is:
    • Next-R rule: If it has a right subtree, the leftmost node in the right subtree.
    • Next-U rule: Otherwise, traverse up the tree
      • If you make a right turn (i.e. this node was a left child), then that parent node is the successor
      • If you make a left turn (i.e. this node was a right child), continue going up.
      • If you can't go up anymore, then there's no successor

As you can see, for this to work, you need a parent node pointer.


Example:

alt text

  • First rule: The first node in the tree is the leftmost node in the tree: (1)
  • Next-U rule: Since (1) has no right subtree, we go up to (3). This is a right turn, so (3) is next.
  • Next-R rule: Since (3) has a right subtree, the leftmost node in that subtree is next: (4).
  • Next-U rule: Since (4) has no right subtree, we go up to (6). This is a right turn, so next is (6).
  • Next-R rule: Since (6) has a right subtree, the leftmost node in that subtree is next: (7).
  • Next-U rule: Since (7) has no right subtree, we go up to (6). This is a left turn, so we continue going up to (3). This is a left turn, so we continue going up to (8). This is a right turn, so next is (8).
  • Next-R rule: Since (8) has a right subtree, the leftmost node in that subtree is next: (10).
  • Next-R rule: Since (10) has a right subtree, the leftmost node in that subtree is next: (13).
  • Next-U rule: Since (13) has no right subtree, we go up to (14). This is a right turn, so next is (14).
  • Next-U rule: Since (14) has no right subtree, we go up to (10). This is a left turn, so we continue going up to (8). This is a left turn, so we want to continue going up, but since (8) has no parent, we've reached the end. (14) has no successor.

Pseudocode

Node getLeftMost(Node n)
  WHILE (n.leftChild != NULL)
    n = n.leftChild
  RETURN n

Node getFirst(Tree t)
  IF (t.root == NULL) RETURN NULL
  ELSE
     RETURN getLeftMost(t.root);

Node getNext(Node n)
  IF (n.rightChild != NULL)
     RETURN getLeftMost(n.rightChild)
  ELSE
     WHILE (n.parent != NULL AND n == n.parent.rightChild)
        n = n.parent;
     RETURN n.parent;

PROCEDURE iterateOver(Tree t)
  Node n = getFirst(t);
  WHILE n != NULL
     visit(n)
     n = getNext(n)

Java code

Here's a simple implementation of the above algorithm:

public class SuccessorIteration {
    static class Node {
        final Node left;
        final Node right;
        final int key;
        Node parent;
        Node(int key, Node left, Node right) {
            this.key = key;
            this.left = left;
            this.right = right;
            if (left != null) left.parent = this;
            if (right != null) right.parent = this;
        }
        Node getLeftMost() {
            Node n = this;
            while (n.left != null) {
                n = n.left;
            }
            return n;
        }
        Node getNext() {
            if (right != null) {
                return right.getLeftMost();
            } else {
                Node n = this;
                while (n.parent != null && n == n.parent.right) {
                    n = n.parent;
                }
                return n.parent;
            }
        }
    }
}

Then you can have a test harness like this:

static Node C(int key, Node left, Node right) {
    return new Node(key, left, right);
}
static Node X(int key)             { return C(key, null, null);  }
static Node L(int key, Node left)  { return C(key, left, null);  }
static Node R(int key, Node right) { return C(key, null, right); }
public static void main(String[] args) {
    Node n =
        C(8,
            C(3,
                X(1),
                C(6,
                    X(4),
                    X(7)
                )
            ),
            R(10,
                L(14,
                    X(13)
                )
            )
        );
    Node current = n.getLeftMost();
    while (current != null) {
        System.out.print(current.key + " ");
        current = current.getNext();
    }
}

This prints:

1 3 4 6 7 8 10 13 14 

See also

暗喜 2024-09-10 05:48:56

你能把它改为迭代而不是递归吗?

您可以使用显式堆栈。伪代码:

private static void iterateall(BinaryTree foo) {
    Stack<BinaryTree> nodes = new Stack<BinaryTree>();
    nodes.push(foo);
    while (!nodes.isEmpty()) {
        BinaryTree node = nodes.pop();
        if (node == null)
            continue;
        System.out.println(node.node);
        nodes.push(node.right);
        nodes.push(node.left);
    }
}

但这并不比递归代码真正优越(除了代码中缺少基本条件)。

Can you change it to Iteration instead of a recursion?

You can, using an explicit stack. Pseudocode:

private static void iterateall(BinaryTree foo) {
    Stack<BinaryTree> nodes = new Stack<BinaryTree>();
    nodes.push(foo);
    while (!nodes.isEmpty()) {
        BinaryTree node = nodes.pop();
        if (node == null)
            continue;
        System.out.println(node.node);
        nodes.push(node.right);
        nodes.push(node.left);
    }
}

But this isn’t really superior to the recursive code (except for the missing base condition in your code).

累赘 2024-09-10 05:48:56

当然,您有两种通用算法,深度优先搜索广度优先搜索

如果遍历顺序对你来说不重要,那么先考虑广度,这样迭代更容易实现。你的算法应该看起来像这样。

LinkedList queue = new LinkedList();

queue.add(root);

while (!queue.isEmpty()){
    Object element = queue.remove();

    queue.add(element.left);
    queue.add(element.right);

    // Do your processing with element;
}

Sure, you have two general algorithms, depth first search and breadth first search.

If order of traversal is not important to you, go for breadth first, it's easier to implement for iteration. You're algorithm should look something like this.

LinkedList queue = new LinkedList();

queue.add(root);

while (!queue.isEmpty()){
    Object element = queue.remove();

    queue.add(element.left);
    queue.add(element.right);

    // Do your processing with element;
}
很酷又爱笑 2024-09-10 05:48:56

与每次递归一样,您可以使用额外的数据结构 - 即堆栈。
解决方案的草图:

private static void visitall(BinaryTree foo) {
  Stack<BinaryTree> iterationStack = new Stack<BinaryTree>();
  iterationStack.push(foo);

  while (!iterationStack.isEmpty()) {
      BinaryTree current = iterationStack.pop();
      System.out.println(current.node);
      current.push(current.right);        // NOTE! The right one comes first
      current.push(current.left);
   }

}

As with every recursion, you can use additional data structure - i.e. the stack.
A sketch of the solution:

private static void visitall(BinaryTree foo) {
  Stack<BinaryTree> iterationStack = new Stack<BinaryTree>();
  iterationStack.push(foo);

  while (!iterationStack.isEmpty()) {
      BinaryTree current = iterationStack.pop();
      System.out.println(current.node);
      current.push(current.right);        // NOTE! The right one comes first
      current.push(current.left);
   }

}
软的没边 2024-09-10 05:48:56

我有一棵树(不是二叉树)并最终用这个非常简单的算法解决了它。其他解决方案使用的与示例无关,甚至没有实现。

我的结构是:每个父节点都包含子节点列表,每个子节点都包含一个指向父节点的指针。很常见...

经过一系列重构后,我使用 Kotlin 提出了以下示例。转换为您选择的语言应该很简单。

辅助函数

首先,节点必须提供 2 个简单的函数。这将根据您的 Node 类的实现而有所不同:

leftMost - 这是第一个子节点。如果该节点有子节点,则它是第一个子节点,依此类推。如果没有子节点,则返回 this

fun leftMost(): Node {
        if (children.isEmpty()) {
            return this
        }
        var n = this
        while (n.children.isNotEmpty()) {
            n = n.children[0]
        }
        return n
}

nextSibling - 该节点的下一个兄弟节点,或 NULL

fun nextSibling(): Node? {
    if (parent == null) return null
    val siblingIndex = parent.children.indexOf(this) + 1
    return if (siblingIndex < parent.children.size) {
        parent.children[siblingIndex]
    } else {
        null
    }
}

迭代

迭代从根的最左边开始。

然后检查下一个兄弟姐妹。

  • 如果 NOT NULL,则为同级的 leftMostChild;
  • 如果为 NULL,则为父级;如果父级为 NULL,则完成。

就是这样。

这是一个 Kotlin 迭代器函数。

fun iterator(): Iterator<Node> {
    var next: Node? = this.leftMost()

    return object : Iterator<Node> {

        override fun hasNext(): Boolean {
            return next != null
        }

        override fun next(): Node {
            val ret = next ?: throw NoSuchElementException()
            next = ret.nextSibling()?.leftMost() ?: ret.parent
            return ret
        }
    }
}

这是相同的 next() 函数,但对于那些不熟悉语法的人来说,没有处理 NULL 值的 Kotlin 简写。

fun next(): Node {
    val ret = next
    if (ret == null) throw NoSuchElementException()
    val nextSibling = ret.nextSibling()
    if (nextSibling != null) {
        next = nextSibling.leftMost()
    }
    else {
        next = ret.parent
    }
    return ret
}

I had a tree (not binary) and eventually solved it with this very simple algorithm. The other solutions used left and right that were not relevant or even implemented in the examples.

My structure was: nodes with each parent containing list of children, and each child containing a pointer back to the parent. Pretty common...

After a bunch of refactoring, I came up with the following example using Kotlin. It should be trivial to convert to your language of choice.

Helper Functions

First, the node must provide 2 simple functions. This will vary depending on your Node class' implementation:

leftMost - This is the first child node. If that node has children, it's first child, etc. If no children, return this.

fun leftMost(): Node {
        if (children.isEmpty()) {
            return this
        }
        var n = this
        while (n.children.isNotEmpty()) {
            n = n.children[0]
        }
        return n
}

nextSibling - The next sibling of this node, or NULL

fun nextSibling(): Node? {
    if (parent == null) return null
    val siblingIndex = parent.children.indexOf(this) + 1
    return if (siblingIndex < parent.children.size) {
        parent.children[siblingIndex]
    } else {
        null
    }
}

The Iteration

The iteration starts with the leftMost of the root.

Then inspect the next sibling.

  • If NOT NULL the sibling's leftMostChild
  • If NULL, the parent, and if the parent is NULL, we are done.

That's it.

Here is a Kotlin iterator function.

fun iterator(): Iterator<Node> {
    var next: Node? = this.leftMost()

    return object : Iterator<Node> {

        override fun hasNext(): Boolean {
            return next != null
        }

        override fun next(): Node {
            val ret = next ?: throw NoSuchElementException()
            next = ret.nextSibling()?.leftMost() ?: ret.parent
            return ret
        }
    }
}

Here is the same next() function, but without the Kotlin shorthand for dealing with NULL values, for those that are not hip to the syntax.

fun next(): Node {
    val ret = next
    if (ret == null) throw NoSuchElementException()
    val nextSibling = ret.nextSibling()
    if (nextSibling != null) {
        next = nextSibling.leftMost()
    }
    else {
        next = ret.parent
    }
    return ret
}
谈场末日恋爱 2024-09-10 05:48:56

是的,您可以将其更改为迭代而不是递归,但是这样会变得更加复杂,因为您需要有某种方法来记住从当前节点返回的位置。在递归情况下,Java 调用堆栈会处理该问题,但在迭代解决方案中,您需要构建自己的堆栈,或者可能在节点中存储反向指针。

Yes, you can change it to iteration instead of a recursion, but then it gets much more complicated, since you need to have some way to remember where to go back from the current node. In the recursive case, the Java call stack handles that, but in an iterative solution you need to build your own stack, or perhaps store back pointers in the nodes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文