数据结构——二叉树的遍历

  二叉树的遍历是指通过一定顺序访问二叉树的所有结点。遍历方法一般有四种:先序遍历、中序遍历、后序遍历及层次遍历。

一、先序遍历

  对先序遍历来说,总是先访问根结点 root,然后才去访问左子树和右子树,因此先序遍历的遍历顺序是根结点 -> 左子树 -> 右子树。代码如下:

1 // 先序遍历
2 void preorder(node* root) {
3     if(root == NULL) {
4         return;        // 空树,递归边界 
5     }
6     printf("%d
", root->data);        // 访问该结点
7     preorder(root->lchild);            // 访问左子树 
8     preorder(root->rchild);            // 访问右子树  
9 } 

  对一棵二叉树的先序遍历序列,序列的第一个一定是根结点。  

二、中序遍历

  对中序遍历来说,总是先访问左子树,再访问根结点,最后访问右子树,因此中序遍历的遍历顺序是左子树 -> 根结点 -> 右子树。代码如下:

1 // 中序遍历
2 void inorder(node* root) {
3     if(root == NULL) {
4         return;        // 空树,递归边界 
5     }
6     inorder(root->lchild);            // 访问左子树 
7     printf("%d
", root->data);        // 访问该结点
8     inorder(root->rchild);            // 访问右子树  
9 } 

  由于中序遍历总是把根结点放在左子树和右子树之间,因此只要知道根结点,就可以通过根结点在中序遍历序列中的位置区分出左子树和右子树。

三、后序遍历

  对后序遍历来说,总是先访问左子树,再访问右子树,最后才访问根结点,因此后序遍历的遍历顺序是左子树 -> 右子树 -> 根结点。代码如下:

1 // 后序遍历
2 void postorder(node* root) {
3     if(root == NULL) {
4         return;        // 空树,递归边界 
5     }
6     postorder(root->lchild);            // 访问左子树 
7     postorder(root->rchild);            // 访问右子树
8     printf("%d
", root->data);            // 访问该结点  
9 } 

四、一个重要问题

  给定一棵二叉树的先序遍历序列和中序遍历序列,重建这棵二叉树。

  假设在递归过程中,当前先序序列的区间为 [preL, preR] ,中序序列的区间为 [inL, inR] ,且 ink = pre1 ,那么左子树的结点个数为 numLeft = k - inL。这样左子树的先序序列区间就是 [preL+1, pre+numLeft],左子树的中序序列区间是 [inL, k-1];右子树的先序序列区间是 [preL+numLeft+1, preR],右子树的中序序列区间是 [k+1, inR]。

  当先序序列的长度小于等于 0 时,当前二叉树就不存在了,这个条件可以作为递归边界。代码如下:

 1 int pre[maxn]={1, 2, 4, 5, 3, 6}, in[maxn]={4, 2, 5, 1, 3, 6};    // 储存先序、中序序列
 2 // 当前先序序列 [preL, preR],中序序列 [inL, inR],返回根结点地址
 3 node* create1(int preL, int preR, int inL, int inR) {
 4     if(preL > preR) {
 5         return NULL;    // 先序序列长度小于等于0,递归边界 
 6     }
 7     node* root = (node*)malloc(sizeof(node));
 8     root->data = pre[preL];        // 新结点的数据域为根结点的值
 9     int k;
10     for(k=inL; k<=inR; ++k) {
11         if(in[k] == pre[preL]) {    // 在中序序列中找到根结点 
12             break;
13         }
14     } 
15     int numLeft = k - inL;    // 左子树结点个数
16     
17     // 左子树的先序序列区间是 [preL+1, pre+numLeft],中序序列区间是 [inL, k-1]
18     root->lchild = create1(preL+1, preL+numLeft, inL, k-1);
19     // 右子树的先序序列区间是 [preL+numLeft+1, preR],中序序列区间是 [k+1, inR]
20     root->rchild = create1(preL+numLeft+1, preR, k+1, inR);
21     
22     return root; 
23 } 

  完整 C 代码如下:

  1 /*
  2     二叉树 
  3 */
  4 
  5 #include <stdio.h>
  6 #include <string.h>
  7 #include <math.h>
  8 #include <stdlib.h>
  9 #include <time.h>
 10 #include <stdbool.h>
 11 
 12 #define typename int
 13 #define maxn 20
 14 // 二叉树结构定义 
 15 typedef struct _node {
 16     typename data;        // 数据域
 17     struct _node* lchild;        // 指向左子树的根结点
 18     struct _node* rchild;        // 指向右子树的根结点 
 19 } node; 
 20 
 21 // 生成一个新节点,v为数据 
 22 node* newNode(typename v) {
 23     node* Node = (node*)malloc(sizeof(node));
 24     Node->data = v;
 25     // 初始状态下没有左右子树 
 26     Node->lchild = Node->rchild = NULL;
 27     return Node;
 28 } 
 29 
 30 // 在根结点为root的二叉树查找所有数据域为x的结点并修改为newdata 
 31 void search(node* root, typename x, typename newdata) {
 32     if(root == NULL) {
 33         return;        // 空树 
 34     }
 35     if(root->data == x) {    // 查到 x 
 36         root->data = newdata;    // 修改 
 37     }
 38     search(root->lchild, x, newdata);    // 遍历左子树
 39     search(root->rchild, x, newdata);    // 遍历右子树      
 40 } 
 41 
 42 // 在以*root为根结点的二叉树插入一个新节点 
 43 void insert(node** root, typename x) {
 44     if((*root) == NULL) {        // 找到插入位置 
 45         (*root) = newNode(x);
 46         return; 
 47     }
 48     if(x < (*root)->data) {        // 往左子树插入 
 49         insert(&((*root)->lchild), x);
 50     } else {                    // 往右子树插入 
 51         insert(&((*root)->rchild), x);
 52     }
 53 }
 54 
 55 // 二叉树的建立 
 56 node* create(typename data[], int n) {
 57     node* root = NULL;        // 新建空根结点 root 
 58     int i;
 59     for(i=0; i<n; ++i) {    // 将 data 中的数据插入二叉树 
 60         insert(&root, data[i]);
 61     } 
 62     return root;            // 返回根结点 
 63 } 
 64 
 65 // 先序遍历
 66 void preorder(node* root) {
 67     if(root == NULL) {
 68         return;        // 空树,递归边界 
 69     }
 70     printf("%d
", root->data);        // 访问该结点
 71     preorder(root->lchild);            // 访问左子树 
 72     preorder(root->rchild);            // 访问右子树  
 73 } 
 74 
 75 // 中序遍历
 76 void inorder(node* root) {
 77     if(root == NULL) {
 78         return;        // 空树,递归边界 
 79     }
 80     inorder(root->lchild);            // 访问左子树 
 81     printf("%d
", root->data);        // 访问该结点
 82     inorder(root->rchild);            // 访问右子树  
 83 } 
 84 
 85 // 后序遍历
 86 void postorder(node* root) {
 87     if(root == NULL) {
 88         return;        // 空树,递归边界 
 89     }
 90     postorder(root->lchild);            // 访问左子树 
 91     postorder(root->rchild);            // 访问右子树
 92     printf("%d
", root->data);            // 访问该结点  
 93 } 
 94 
 95 int pre[maxn]={1, 2, 4, 5, 3, 6}, in[maxn]={4, 2, 5, 1, 3, 6};    // 储存先序、中序序列
 96 // 当前先序序列 [preL, preR],中序序列 [inL, inR],返回根结点地址
 97 node* create1(int preL, int preR, int inL, int inR) {
 98     if(preL > preR) {
 99         return NULL;    // 先序序列长度小于等于0,递归边界 
100     }
101     node* root = (node*)malloc(sizeof(node));
102     root->data = pre[preL];        // 新结点的数据域为根结点的值
103     int k;
104     for(k=inL; k<=inR; ++k) {
105         if(in[k] == pre[preL]) {    // 在中序序列中找到根结点 
106             break;
107         }
108     } 
109     int numLeft = k - inL;    // 左子树结点个数
110     
111     // 左子树的先序序列区间是 [preL+1, pre+numLeft],中序序列区间是 [inL, k-1]
112     root->lchild = create1(preL+1, preL+numLeft, inL, k-1);
113     // 右子树的先序序列区间是 [preL+numLeft+1, preR],中序序列区间是 [k+1, inR]
114     root->rchild = create1(preL+numLeft+1, preR, k+1, inR);
115     
116     return root; 
117 } 
118 
119 /*// 输出二叉树,先序 
120 void print(node* root) {
121     if(root == NULL) {
122         return;
123     }
124     printf("%d ", root->data);
125     print(root->lchild);
126     print(root->rchild);
127 }*/
128 
129 int main() {
130     /*int data[5] = {1, 2, 3, 4, 5};
131     node* tree = create(data, 5);    // 创建二叉树 
132     print(tree);                    // 输出二叉树 */
133     
134     node* tree = create1(0, 5, 0, 5);
135     postorder(tree);
136     
137     return 0;
138 }
二叉树的遍历
原文地址:https://www.cnblogs.com/coderJiebao/p/Algorithmofnotes21.html