由遍历序列创建二叉树
@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)上述程序假定输入序列中元素都是唯一的(不可重集)。有相同元素的序列不能唯一确定一棵二叉树,即有多棵二叉树与之对应。这个话题另外讨论。