首页 > 代码库 > 二叉树基本操作续一:二叉树建立、节点数统计

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

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

  二叉树建立:

 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 =http://www.mamicode.com/ 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,说明这颗二叉树只有一个根节点,叶子节点自然为110             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 =http://www.mamicode.com/ 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 }