由遍历序列创建二叉树

  #返回上一级

@Author: 张海拔

@Update: 2014-01-19

@Link: http://www.cnblogs.com/zhanghaiba/p/3525693.html

 

  1 /*
  2  *Author: ZhangHaiba
  3  *Date: 2014-1-19
  4  *File: order_create_binary_tree.c
  5  *
  6  *this demo shows how to use inorder list & preorder list to rebuild binary tree
  7  *and how to use inorder list & postorder list as well
  8  */
  9 
 10 
 11 #include <stdio.h>
 12 #include <stdlib.h>
 13 #define LEN 512
 14 #define CMD_LEN 128
 15 
 16 typedef struct node* link;
 17 
 18 typedef struct node {
 19     int item;
 20     link left;
 21     link right;
 22 }node;
 23 
 24 //public
 25 link NODE(int item, link left, link right);
 26 void set_order(int len, int *first, int *second);
 27 void set_error(void);
 28 link create_by_order1(int *inorder, int *preorder, int len);
 29 link create_by_order2(int *inorder, int *postorder, int len);
 30 void show_by_tree(link root);
 31 //private
 32 void tree_print(link root, FILE *fd);
 33 
 34 //private
 35 node error;
 36 int ERROR;
 37 int inorder[LEN];
 38 int preorder[LEN];
 39 int postorder[LEN];
 40 
 41 int main(void)
 42 {
 43     int len, i;
 44     link root;
 45 
 46     printf("enter the length of order list:\n");
 47     scanf("%d", &len);
 48     printf("enter inorder and preorder list:\n");
 49     set_order(len, inorder, preorder);
 50     set_error();
 51     root = create_by_order1(inorder, preorder, len);
 52     root == &error ? printf("input illegal\n") : show_by_tree(root);
 53 
 54     printf("enter the length of order list:\n");
 55     scanf("%d", &len);
 56     printf("enter inorder and postorder list:\n");
 57     set_order(len, inorder, postorder);
 58     set_error();
 59     root = create_by_order2(inorder, postorder, len);
 60     root == &error ? printf("input illegal\n") : show_by_tree(root);    
 61     return 0;
 62 }
 63 
 64 link NODE(int item, link left, link right)
 65 {
 66     link born = malloc(sizeof (node));
 67     born->item = item;
 68     born->left = left;
 69     born->right = right;
 70     return born;
 71 }
 72 
 73 void set_order(int len, int* first, int *second)
 74 {
 75     int i;
 76 
 77     for (i = 0; i < len; ++i)
 78         scanf("%d", first+i);
 79     for (i = 0; i < len; ++i)
 80         scanf("%d", second+i);
 81 }
 82 
 83 void set_error(void)
 84 {
 85     ERROR = 0;
 86 }
 87 
 88 link create_by_order1(int *inorder, int *preorder, int len)
 89 {
 90     if (ERROR) return NULL; //if ERROR==1, no need to expand nodes
 91     if (len <= 0) return NULL;
 92     int m = 0;
 93     while (inorder[m] != preorder[0] && m < len)
 94          ++m;
 95     if (m == len) ERROR = 1;
 96     link root = NODE(preorder[0], NULL, NULL);
 97     root->left = create_by_order1(inorder, preorder+1, m);
 98     root->right = create_by_order1(inorder+(m+1), preorder+(m+1), len-(m+1));
 99     return ERROR ? &error : root;
100 }
101 
102 
103 link create_by_order2(int *inorder, int *postorder, int len)
104 {
105     if (ERROR) return NULL; //if ERROR==1, no need to expand nodes
106     if (len <= 0) return NULL;
107     int m = 0;
108     while (inorder[m] != postorder[len-1] && m < len)
109         ++m;
110     if (m == len) ERROR = 1;
111     link root = NODE(postorder[len-1], NULL, NULL);
112     root->left = create_by_order2(inorder, postorder, m);
113     root->right = create_by_order2(inorder+(m+1), postorder+m, len-(m+1));
114     return ERROR ? &error : root;
115 }
116 
117 void show_by_tree(link root)
118 {
119     char cmd[CMD_LEN];
120 
121     sprintf(cmd, "rm -f ./tree_src.txt");
122     system(cmd);
123 
124     FILE *fd = fopen("./tree_src.txt", "a+");
125     fprintf(fd, "\n\t\\tree");
126     tree_print(root, fd);
127     fprintf(fd, "\n\n");
128     fclose(fd);
129 
130     sprintf(cmd, "cat ./tree_src.txt | ~/tree/tree");
131     system(cmd);
132 }
133 
134 void tree_print(link root, FILE *fd)
135 {    
136     fprintf(fd, "(");
137     if (root != NULL) {
138         fprintf(fd, "%d", root->item);
139         tree_print(root->left, fd);
140         tree_print(root->right, fd);
141     }
142     fprintf(fd, ")");
143 }

 

测试示范

ZhangHaiba-MacBook-Pro:code apple$ ./a.out
enter the length of order list:
12
enter inorder and preorder list:
4 10 5 30 9 7 13 20 11 15 8 12
10 4 20 30 5 9 13 7 8 11 15 12

              10
         _____|______
         |          |
         4          20
        _|__  ______|______
        |  |  |           |
              30          8
           ___|___     ___|___
           |     |     |     |
           5     9     11    12
          _|__  _|__  _|__  _|__
          |  |  |  |  |  |  |  |
                   13    15
                  _|__  _|__
                  |  |  |  |
                  7
                 _|__
                 |  |

enter the length of order list:
12
enter inorder and postorder list:
4 10 5 30 9 7 13 20 11 15 8 12
4 5 7 13 9 30 15 11 12 8 20 10

              10
         _____|______
         |          |
         4          20
        _|__  ______|______
        |  |  |           |
              30          8
           ___|___     ___|___
           |     |     |     |
           5     9     11    12
          _|__  _|__  _|__  _|__
          |  |  |  |  |  |  |  |
                   13    15
                  _|__  _|__
                  |  |  |  |
                  7
                 _|__
                 |  |


ZhangHaiba-MacBook-Pro:code apple$ ./a.out
enter the length of order list:
7
enter inorder and preorder list:
2 3 7 10 22 11 8
10 2 3 7 8 11 33
input illegal
enter the length of order list:
7
enter inorder and postorder list:
2 3 7 10 22 11 8
7 3 2 22 11 8 10

               10
         ______|______
         |           |
         2           8
        _|__        _|__
        |  |        |  |
           3        11
          _|__     _|__
          |  |     |  |
             7     22
            _|__  _|__
            |  |  |  |

  

给出中序序列和前序序列建二叉树,处理方法类似分治法。

前序序列的第一个元素是树根,在中序序列里面找到这个元素,设下标为m,则该元素左边数组是左子树的中序序列,右边数组是右子树的中序序列。

注意到,子树的前序序列和中序序列元素个数必定是相同的,所以,左子树前序是preorder+1,长度是m;右子树前序是preorder+(m+1),长度是len-(m+1)。

确定了子树的中序和前序序列,则分别对左、右子树调用创建函数,显然该过程是递归进行的。

写递归函数,首先要确定好递归结束条件同时考虑第一次调用的情况,这里是当len <= 0,则不(再)创建,返回NULL。

 

给出中序序列和后序序列建二叉树,原理同上。

值得一提的是,如果序列长度用begin和end两个参量来确定边界则相对麻烦,用len一个参量反而更简单。

可以对比中序和后序建树函数的写法,仅仅是后序序列首地址比前序序列首地址小了一个单位。

左子树: perorder+1 : postorder; 右子树: perorder+(m+1) : postorder + m。

 

说明:

(1)怎样像测试示范那样打印出一棵树,参考 二叉排序树的递归实现 link(public)

(2)创建函数中,与二叉排序树的插入等函数不同,参数列表没有link root,主要是考虑到这个创建过程类似一个原子操作。而BST插入函数的写法是为了代码复用。

(3)上述实现中,还加入了错误检查。即如果在中序序列中,找不到前序序列或后序序列中的某个元素,则说明输入的序列是非法的。

一旦发生错误,用全局错误标记ERROR来控制抑制树的继续生长,并最终返回一个全局错误节点error的地址,而不要返回一棵残缺无意义的树的树根。

(4)上述程序假定输入序列中元素都是唯一的(不可重集)。有相同元素的序列不能唯一确定一棵二叉树,即有多棵二叉树与之对应。这个话题另外讨论。

 

  #返回上一级

posted @ 2014-01-19 02:15  张海拔  阅读(649)  评论(0编辑  收藏  举报