📜  树遍历(顺序,预顺序和后顺序)

📅  最后修改于: 2021-05-20 08:13:11             🧑  作者: Mango

与只有一种逻辑方式遍历线性数据结构(数组,链接列表,队列,堆栈等)的树不同,可以以不同的方式遍历树。以下是遍历树的常用方法。

示例树

深度优先遍历:
(a)顺序(左,根,右):4 2 5 1 3
(b)预购(根,左,右):1 2 4 5 3
(c)后置顺序(左,右,根):4 5 2 3 1
广度优先或级别顺序遍历:1 2 3 4 5
请参阅广度优先遍历的这篇文章。
有序遍历(练习):

Algorithm Inorder(tree)
   1. Traverse the left subtree, i.e., call Inorder(left-subtree)
   2. Visit the root.
   3. Traverse the right subtree, i.e., call Inorder(right-subtree)

顺序的使用
在二叉搜索树(BST)的情况下,顺序遍历会以非降序顺序给出节点。要使BST的节点以非递增顺序排列,可以使用Inorder遍历的变体,其中Inorder遍历的方向是相反的。
示例:上面给出的数字的顺序遍历为4 2 5 1 3。
预习遍历(练习):

Algorithm Preorder(tree)
   1. Visit the root.
   2. Traverse the left subtree, i.e., call Preorder(left-subtree)
   3. Traverse the right subtree, i.e., call Preorder(right-subtree) 

预购的用途
预遍历遍历用于创建树的副本。前置遍历还用于在表达式树上获取前缀表达式。请参阅http://en.wikipedia.org/wiki/Polish_notation了解前缀表达式为何有用的原因。
示例:上图给定的遍历为1 2 4 5 3。
后遍历(练习):

Algorithm Postorder(tree)
   1. Traverse the left subtree, i.e., call Postorder(left-subtree)
   2. Traverse the right subtree, i.e., call Postorder(right-subtree)
   3. Visit the root.

后订单的用途
后顺序遍历用于删除树。有关详细信息,请参阅删除树的问题。后序遍历对于获取表达式树的后缀表达式也很有用。有关后缀表达式的用法,请参见http://en.wikipedia.org/wiki/Reverse_Polish_notation。
示例:上图给定的事后遍历为4 5 2 3 1。

C++
// C++ program for different tree traversals
#include 
using namespace std;
 
/* A binary tree node has data, pointer to left child
and a pointer to right child */
struct Node {
    int data;
    struct Node *left, *right;
    Node(int data)
    {
        this->data = data;
        left = right = NULL;
    }
};
 
/* Given a binary tree, print its nodes according to the
"bottom-up" postorder traversal. */
void printPostorder(struct Node* node)
{
    if (node == NULL)
        return;
 
    // first recur on left subtree
    printPostorder(node->left);
 
    // then recur on right subtree
    printPostorder(node->right);
 
    // now deal with the node
    cout << node->data << " ";
}
 
/* Given a binary tree, print its nodes in inorder*/
void printInorder(struct Node* node)
{
    if (node == NULL)
        return;
 
    /* first recur on left child */
    printInorder(node->left);
 
    /* then print the data of node */
    cout << node->data << " ";
 
    /* now recur on right child */
    printInorder(node->right);
}
 
/* Given a binary tree, print its nodes in preorder*/
void printPreorder(struct Node* node)
{
    if (node == NULL)
        return;
 
    /* first print data of node */
    cout << node->data << " ";
 
    /* then recur on left sutree */
    printPreorder(node->left);
 
    /* now recur on right subtree */
    printPreorder(node->right);
}
 
/* Driver program to test above functions*/
int main()
{
    struct Node* root = new Node(1);
    root->left = new Node(2);
    root->right = new Node(3);
    root->left->left = new Node(4);
    root->left->right = new Node(5);
 
    cout << "\nPreorder traversal of binary tree is \n";
    printPreorder(root);
 
    cout << "\nInorder traversal of binary tree is \n";
    printInorder(root);
 
    cout << "\nPostorder traversal of binary tree is \n";
    printPostorder(root);
 
    return 0;
}


C
// C program for different tree traversals
#include 
#include 
 
/* A binary tree node has data, pointer to left child
   and a pointer to right child */
struct node {
    int data;
    struct node* left;
    struct node* right;
};
 
/* Helper function that allocates a new node with the
   given data and NULL left and right pointers. */
struct node* newNode(int data)
{
    struct node* node
        = (struct node*)malloc(sizeof(struct node));
    node->data = data;
    node->left = NULL;
    node->right = NULL;
 
    return (node);
}
 
/* Given a binary tree, print its nodes according to the
  "bottom-up" postorder traversal. */
void printPostorder(struct node* node)
{
    if (node == NULL)
        return;
 
    // first recur on left subtree
    printPostorder(node->left);
 
    // then recur on right subtree
    printPostorder(node->right);
 
    // now deal with the node
    printf("%d ", node->data);
}
 
/* Given a binary tree, print its nodes in inorder*/
void printInorder(struct node* node)
{
    if (node == NULL)
        return;
 
    /* first recur on left child */
    printInorder(node->left);
 
    /* then print the data of node */
    printf("%d ", node->data);
 
    /* now recur on right child */
    printInorder(node->right);
}
 
/* Given a binary tree, print its nodes in preorder*/
void printPreorder(struct node* node)
{
    if (node == NULL)
        return;
 
    /* first print data of node */
    printf("%d ", node->data);
 
    /* then recur on left sutree */
    printPreorder(node->left);
 
    /* now recur on right subtree */
    printPreorder(node->right);
}
 
/* Driver program to test above functions*/
int main()
{
    struct node* root = newNode(1);
    root->left = newNode(2);
    root->right = newNode(3);
    root->left->left = newNode(4);
    root->left->right = newNode(5);
 
    printf("\nPreorder traversal of binary tree is \n");
    printPreorder(root);
 
    printf("\nInorder traversal of binary tree is \n");
    printInorder(root);
 
    printf("\nPostorder traversal of binary tree is \n");
    printPostorder(root);
 
    getchar();
    return 0;
}


Python
# Python program to for tree traversals
 
# A class that represents an individual node in a
# Binary Tree
 
 
class Node:
    def __init__(self, key):
        self.left = None
        self.right = None
        self.val = key
 
 
# A function to do inorder tree traversal
def printInorder(root):
 
    if root:
 
        # First recur on left child
        printInorder(root.left)
 
        # then print the data of node
        print(root.val),
 
        # now recur on right child
        printInorder(root.right)
 
 
# A function to do postorder tree traversal
def printPostorder(root):
 
    if root:
 
        # First recur on left child
        printPostorder(root.left)
 
        # the recur on right child
        printPostorder(root.right)
 
        # now print the data of node
        print(root.val),
 
 
# A function to do preorder tree traversal
def printPreorder(root):
 
    if root:
 
        # First print the data of node
        print(root.val),
 
        # Then recur on left child
        printPreorder(root.left)
 
        # Finally recur on right child
        printPreorder(root.right)
 
 
# Driver code
root = Node(1)
root.left = Node(2)
root.right = Node(3)
root.left.left = Node(4)
root.left.right = Node(5)
print "Preorder traversal of binary tree is"
printPreorder(root)
 
print "\nInorder traversal of binary tree is"
printInorder(root)
 
print "\nPostorder traversal of binary tree is"
printPostorder(root)


Java
// Java program for different tree traversals
 
/* Class containing left and right child of current
   node and key value*/
class Node {
    int key;
    Node left, right;
 
    public Node(int item)
    {
        key = item;
        left = right = null;
    }
}
 
class BinaryTree {
    // Root of Binary Tree
    Node root;
 
    BinaryTree() { root = null; }
 
    /* Given a binary tree, print its nodes according to the
      "bottom-up" postorder traversal. */
    void printPostorder(Node node)
    {
        if (node == null)
            return;
 
        // first recur on left subtree
        printPostorder(node.left);
 
        // then recur on right subtree
        printPostorder(node.right);
 
        // now deal with the node
        System.out.print(node.key + " ");
    }
 
    /* Given a binary tree, print its nodes in inorder*/
    void printInorder(Node node)
    {
        if (node == null)
            return;
 
        /* first recur on left child */
        printInorder(node.left);
 
        /* then print the data of node */
        System.out.print(node.key + " ");
 
        /* now recur on right child */
        printInorder(node.right);
    }
 
    /* Given a binary tree, print its nodes in preorder*/
    void printPreorder(Node node)
    {
        if (node == null)
            return;
 
        /* first print data of node */
        System.out.print(node.key + " ");
 
        /* then recur on left sutree */
        printPreorder(node.left);
 
        /* now recur on right subtree */
        printPreorder(node.right);
    }
 
    // Wrappers over above recursive functions
    void printPostorder() { printPostorder(root); }
    void printInorder() { printInorder(root); }
    void printPreorder() { printPreorder(root); }
 
    // Driver method
    public static void main(String[] args)
    {
        BinaryTree tree = new BinaryTree();
        tree.root = new Node(1);
        tree.root.left = new Node(2);
        tree.root.right = new Node(3);
        tree.root.left.left = new Node(4);
        tree.root.left.right = new Node(5);
 
        System.out.println(
            "Preorder traversal of binary tree is ");
        tree.printPreorder();
 
        System.out.println(
            "\nInorder traversal of binary tree is ");
        tree.printInorder();
 
        System.out.println(
            "\nPostorder traversal of binary tree is ");
        tree.printPostorder();
    }
}


C#
// C# program for different
// tree traversals
using System;
 
/* Class containing left and
right child of current
node and key value*/
class Node {
    public int key;
    public Node left, right;
 
    public Node(int item)
    {
        key = item;
        left = right = null;
    }
}
 
class BinaryTree {
    // Root of Binary Tree
    Node root;
 
    BinaryTree() { root = null; }
 
    /* Given a binary tree, print
       its nodes according to the
       "bottom-up" postorder traversal. */
    void printPostorder(Node node)
    {
        if (node == null)
            return;
 
        // first recur on left subtree
        printPostorder(node.left);
 
        // then recur on right subtree
        printPostorder(node.right);
 
        // now deal with the node
        Console.Write(node.key + " ");
    }
 
    /* Given a binary tree, print
       its nodes in inorder*/
    void printInorder(Node node)
    {
        if (node == null)
            return;
 
        /* first recur on left child */
        printInorder(node.left);
 
        /* then print the data of node */
        Console.Write(node.key + " ");
 
        /* now recur on right child */
        printInorder(node.right);
    }
 
    /* Given a binary tree, print
       its nodes in preorder*/
    void printPreorder(Node node)
    {
        if (node == null)
            return;
 
        /* first print data of node */
        Console.Write(node.key + " ");
 
        /* then recur on left sutree */
        printPreorder(node.left);
 
        /* now recur on right subtree */
        printPreorder(node.right);
    }
 
    // Wrappers over above recursive functions
    void printPostorder() { printPostorder(root); }
    void printInorder() { printInorder(root); }
    void printPreorder() { printPreorder(root); }
 
    // Driver Code
    static public void Main(String[] args)
    {
        BinaryTree tree = new BinaryTree();
        tree.root = new Node(1);
        tree.root.left = new Node(2);
        tree.root.right = new Node(3);
        tree.root.left.left = new Node(4);
        tree.root.left.right = new Node(5);
 
        Console.WriteLine("Preorder traversal "
                          + "of binary tree is ");
        tree.printPreorder();
 
        Console.WriteLine("\nInorder traversal "
                          + "of binary tree is ");
        tree.printInorder();
 
        Console.WriteLine("\nPostorder traversal "
                          + "of binary tree is ");
        tree.printPostorder();
    }
}
 
// This code is contributed by Arnab Kundu


输出:

Preorder traversal of binary tree is
1 2 4 5 3 
Inorder traversal of binary tree is
4 2 5 1 3 
Postorder traversal of binary tree is
4 5 2 3 1

再举一个例子:

时间复杂度: O(n)
让我们看看不同的极端情况。
对于涉及树遍历的所有问题,复杂度函数T(n)可以定义为:
T(n)= T(k)+ T(n – k – 1)+ c
其中k是根的一侧上的节点数,而nk-1是另一侧上的节点数。
让我们来分析边界条件
情况1:倾斜的树(子树之一为空,其他子树为非空)
在这种情况下,k为0。
T(n)= T(0)+ T(n-1)+ c
T(n)= 2T(0)+ T(n-2)+ 2c
T(n)= 3T(0)+ T(n-3)+ 3c
T(n)= 4T(0)+ T(n-4)+ 4c
…………………………………………
…………………………………………。
T(n)=(n-1)T(0)+ T(1)+(n-1)c
T(n)= nT(0)+(n)c
T(0)的值将是一个常数,例如d。 (遍历一棵空树将花费一些常量时间)
T(n)= n(c + d)
T(n)=Θ(n)(n的θ)
情况2:左右子树的节点数相等。
T(n)= 2T(| _n / 2_ |)+ c
对于主方法http://en.wikipedia.org/wiki/Master_theorem,此递归函数采用标准形式(T(n)= aT(n / b)+(-)(n))。如果我们通过主方法解决它,我们得到(-)(n)
辅助空间:如果我们不考虑函数调用的堆栈大小,则为O(1)否则为O(h),其中h是树的高度。

倾斜树的高度为n(元素数),因此最差的空间复杂度为O(n),而对于平衡树,高度的高度为(Log n),因此最佳空间复杂度为O(Log n)。