数据结构——树的遍历

来源:互联网 发布:linux内核架构 编辑:程序博客网 时间:2024/06/15 16:18

原文地址:Tree Traversals

不像线性数据结构(数组,列表,队列,堆栈等),它们在逻辑上只有一种遍历方式,树可以有不同的遍历方式。下面就是遍历树的一般所用的方法:

![这里写图片描述](http://img.blog.csdn.net/20161126134534698)深度优先遍历:1)中序遍历(Left, Root, Right):4 2 5 1 32)先序遍历(Root, Left, Right):1 2 4 5 33)后序遍历(Left, Right, Root): 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的非递减顺序。

例如:上图的中序遍历是: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 <stdio.h>#include <stdlib.h>/* 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;}

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();    }}

输出:

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

另外一个例子:


这里写图片描述

图片地址:https://www.cs.swarthmore.edu/~newhall/unixhelp/Java_bst.pdf

时间复杂度:O(n)

我们看下不同的边界情况。

函数复杂度 T(n) ——对于遍历说涉及到的所有问题——可以定义为:

T(n) = T(k) + T(n – k – 1) + c

这里根一边的节点的数目,n-k-1是另一边的节点数。

我们分析一下边界条件:

情况1:偏树(Skewed tree)(其中的一个子树为空,而另一边的子树不为空)。

这种情况下k等于0。

T(n)=T(0)+T(n1)+c
T(n)=2T(0)+T(n2)+2c
T(n)=3T(0)+T(n3)+3c
T(n)=4T(0)+T(n4)+4c

…………………………………………
………………………………………….
T(n)=(n1)T(0)+T(1)+(n1)c
T(n)=nT(0)+(n)c

T(0)的值将是一个常数,比如d。(遍历一个空树的时间就是花费常量的时间)

T(n)=n(c+d)
T(n)=Θ(n)(Thetaofn)

情况2:左右子树的节点数目是相同的

T(n)=2T(n/2)+c

这个递归函数对于大师级的方法( http://en.wikipedia.org/wiki/Master_theorem)是标准形式(T(n)=aT(n/b)+()(n))。如果我们用大师方法解决,那么会得到(-)(n)。

空间复杂度:如果我们不考虑栈的大小,那么函数调用是O(1) 否则是O(n)。

0 0
原创粉丝点击