二叉树基本操作续一:二叉树建立、节点数统计

  在上一篇:二叉树基本操作 中,我们描述了二叉树的递归遍历函数。在这里主要是给出这些函数的测试代码,为了测试更加方便,我们实现了三个新的函数:建立二叉树、统计二叉树叶子节点数量、统计二叉树总节点数量。(二叉树的定义用上篇文章中的定义

  二叉树建立:

 1 tree_pointer create_bin_tree()
 2 {
 3     tree_pointer node;
 4     int x;
 5     scanf("%d", &x);
 6     if (x == 0) {
 7         node = NULL;
 8     }else {
 9         node = (tree_pointer) malloc (sizeof(struct node));
10         node->data = x;
11         printf("Enter %d left_child: ", node->data);
12         node->left_child = create_bin_tree();
13         printf("Enter %d right_child: ", node->data);
14         node->right_child = create_bin_tree();
15     }
16     
17     return node;
18 }

从上篇的定义中我们知道二叉树节点里面存储的是整数,create函数为了便于处理,约定存储的数据不能为0,输入0时,表示这个节点为空。

仔细观察这个函数,就会发现这个函数和前序递归遍历函数很相像,最大的区别就是把遍历函数中的printf操作替换成了:当输入一个合法的需要插入的节点值时,就分配新的节点存储这个值,然后再分别用当前节点的左右儿子作为参数进行递归调用。

  统计叶子节点数和总的节点数:

 1 //注意这两个函数的返回值类型不是void,而是int
 2 
 3 //统计叶子节点数量
 4 int leaf_num(tree_pointer ptr)
 5 {
 6     if (ptr) { //当前节点不为空
 7         if (!ptr->left_child && !ptr->right_child) {
 8             //如果当前节点左右儿子都是空,则这个节点为叶子,返回 1
 9             //如果当前节点为root,说明这颗二叉树只有一个根节点,叶子节点自然为1
10             return 1;
11         } else {
12             //否则,递归调用左右儿子,把返回值相加,即得到总叶子节点数量
13             return leaf_num(ptr->left_child) + leaf_num(ptr->right_child);
14         }
15     }
16     return 0;
17 }
18 
19 //统计全部节点数量
20 int node_num(tree_pointer ptr)
21 {
22     if (ptr) { //当前节点不为空
23         //节点数+1 ,再加上递归调用左右儿子返回的节点数,即得到总节点数量
24         return 1 + node_num(ptr->left_child) + node_num(ptr->right_child);
25     }
26     return 0;
27 }

  如果对递归概念不是很熟悉的话,看到这两个函数会稍微有一点糊涂。但是仔细观察一下,会发现这两个函数其实也是和之前的create函数类似的:同样都是是前序遍历的一个变种。

  在叶子节点统计函数中:preorder中的printf函数现在变成了一个if判断,如果该节点左右儿子都为空,即当前节点为叶子节点,就返回 1,但如果存在左儿子或者右儿子的话,就说明当前节点不是叶子,就进入else流程,递归统计左右儿子,把统计到的数量相加,就得到叶子节点数。换种说法就是:对一颗二叉树进行前序遍历,每遇到一个节点就判断当前节点是否是叶子节点,是的话就返回 1,不是的话继续遍历,代码13行,就把这些递归遍历中返回的 1 相加在了一起,最后得到的就是叶子节点数量。(其实回顾上篇中描述的遍历函数的执行过程可以发现:在遍历函数中也可以在一个是否是叶子节点的if判断,如果是,就输出,然后直接return。因为如果节点是叶子节点,它的左右儿子都为空,所以无论什么遍历,以这个叶子节点为根节点的二叉树(回顾二叉树定义),遍历输出都一样。直接返回从系统层面看,少了两次函数调用,即少了两次入栈出栈和if判断)。

  在总节点统计函数中:就是把前序遍历的三个步骤,printf ,preorder(ptr->lc),preorder(ptr->rc),的返回值直接相加。(有printf说明当前节点不为空,所以前序遍历中的printf在node_num函数中就变成了 +1)。

 

  正如上一篇中说的:二叉树是一个递归定义的数据结构,所以它的大部分操作都非常适合用递归方式实现,而这些操作中最重要的就是三种递归遍历方式,其他很多操作都可以基于这三种递归遍历操作变形。

  这些函数的完成测试代码如下:

(注意:代码中iter_开头的遍历函数,是三种遍历函数的迭代函数,本文中并没有给出实现,下篇文章中单独给出函数实现)

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 
  4 #define MAXSIZE 100
  5 
  6 typedef struct node *tree_pointer;
  7 typedef struct node {
  8     int data;
  9     tree_pointer left_child, right_child;
 10 };
 11 
 12 tree_pointer create_bin_tree();
 13 void preorder(tree_pointer ptr);
 14 void iter_preorder(tree_pointer ptr);
 15 void inorder(tree_pointer ptr);
 16 void iter_inorder(tree_pointer ptr);
 17 void postorder(tree_pointer ptr);
 18 void iter_postorder(tree_pointer ptr);
 19 int leaf_num(tree_pointer ptr);
 20 void show_tree(tree_pointer ptr);
 21 int node_num(tree_pointer ptr);
 22 
 23 int main(void)
 24 {
 25     tree_pointer root = NULL;
 26     int choice = 0;
 27     do {
 28         printf("\n");
 29         printf(" BinaryTree \n");
 30         printf(" *******************\n");
 31         printf(" * *\n");
 32         printf(" * Main Menu *\n");
 33         printf(" * 1. create: *\n");
 34         printf(" * 2. preorder/iter_preorder: *\n");
 35         printf(" * 3. inorder/iter_inorder: *\n");
 36         printf(" * 4. postorder/iter_postorder: *\n");
 37         printf(" * 5. leaf_num: *\n");
 38         printf(" * 6. show_tree: *\n");
 39         printf(" * 7. node_num: *\n");
 40         printf(" * 8. quit!!! *\n");
 41         printf(" *******************\n");
 42         printf(" Enter your choice (1-8): ");
 43         scanf("%d", &choice);
 44 
 45         switch (choice) {
 46             case 1:
 47                 printf("Begin create: enter root: \n");
 48                 root = create_bin_tree();
 49                 printf("Finished!!!\n");
 50                 break;
 51             case 2:
 52                 printf("\n preorder: \n");
 53                 preorder(root);
 54                 printf("\n iter_preorder: \n");
 55                 iter_preorder(root);
 56                 break;
 57             case 3:
 58                 printf("\n inorder: \n");
 59                 inorder(root);
 60                 printf("\n iter_inorder: \n");
 61                 iter_inorder(root);
 62                 break;
 63             case 4:
 64                 printf("\n postorder: \n");
 65                 postorder(root);
 66                 printf("\n iter_postorder: \n");
 67                 iter_postorder(root);
 68                 break;
 69             case 5:
 70                 printf("\n leaf_num: \n");
 71                 printf(" %d\n", leaf_num(root));
 72                 break;
 73             case 6:
 74                 printf("\n show_tree: \n");
 75                 show_tree(root);
 76                 break;
 77             case 7:
 78                 printf("\n node_num: \n %d\n", node_num(root));
 79                 break;
 80             case 8:
 81                 printf("\n quit.\n");
 82                 exit(0);
 83                 break;
 84             default:
 85                 break;
 86         }
 87     }while (choice <= 8);
 88 
 89     return 0;
 90 }
 91 
 92 tree_pointer create_bin_tree()
 93 {
 94     tree_pointer node;
 95     int x;
 96     scanf("%d", &x);
 97     if (x == 0) {
 98         node = NULL;
 99     }else {
100         node = (tree_pointer) malloc (sizeof(struct node));
101         node->data = x;
102         printf("Enter %d left_child: ", node->data);
103         node->left_child = create_bin_tree();
104         printf("Enter %d right_child: ", node->data);
105         node->right_child = create_bin_tree();
106     }
107     
108     return node;
109 }
110 
111 void preorder(tree_pointer ptr)
112 {
113     if (ptr) {
114         printf("\t%d", ptr->data);
115         preorder(ptr->left_child);
116         preorder(ptr->right_child);
117     }
118 }
119 void iter_preorder(tree_pointer ptr)
120 {
121 }
122 
123 void inorder(tree_pointer ptr)
124 {
125     if (ptr) {
126         inorder(ptr->left_child);
127         printf("\t%d", ptr->data);
128         inorder(ptr->right_child);
129     }
130 }
131 void iter_inorder(tree_pointer ptr)
132 {
133 
134 }
135 
136 void postorder(tree_pointer ptr)
137 {
138     if (ptr) {
139         postorder(ptr->left_child);
140         postorder(ptr->right_child);
141         printf("\t%d", ptr->data);
142     }
143 }
144 void iter_postorder(tree_pointer ptr)
145 {}
146 
147 int leaf_num(tree_pointer ptr)
148 {
149     if (ptr) {
150         if (!ptr->left_child && !ptr->right_child) {
151             return 1;
152         } else {
153             return leaf_num(ptr->left_child) + leaf_num(ptr->right_child);
154         }
155     }
156     return 0;
157 }
158 
159 void show_tree(tree_pointer ptr)
160 {
161 }
162 
163 int node_num(tree_pointer ptr)
164 {
165     if (ptr) {
166         return 1 + node_num(ptr->left_child) + node_num(ptr->right_child);
167     }
168     return 0;
169 }

 

posted @ 2014-06-18 12:09  風之痕  阅读(1355)  评论(0编辑  收藏  举报