二叉树的创建及各种遍历

前些天看数据结构,看到了二叉树的相关操作,我觉得,链表搞透彻了,这些东西都不是问题,还有栈、队列之类的,都是基于结构体和指针,其原理和链表相差无几,接下来来分享一下二叉树的创建以及各种遍历方法:

二叉树简介

来源于维基百科

 

二叉树(英语:Binary tree)是每个节点最多只有两个分支(不存在分支度大于2的节点)的树结构。通常分支被称作“左子树”和“右子树”。二叉树的分支具有左右次序,不能颠倒。

二叉树的第i层至多拥有2^{i-1}个节点数;深度为k的二叉树至多总共有{\displaystyle 2^{\begin{aligned}k+1\end{aligned}}-1}个节点数(定义根节点所在深度{\displaystyle k_{0}=0}),而总计拥有节点数匹配的,称为“满二叉树”;

深度为kn个节点的二叉树,当且仅当其中的每一节点,都可以和同样深度k的满二叉树,序号为1到n的节点一对一对应时,称为“完全二叉树”;

 

二叉树创建

首先定义结构体:

1 typedef struct Tree
2 {
3     int data;                         //    数据域
4     struct Tree *left, *right;        //    左孩子、右孩子
5 }Tree;

 

接着采用递归的方法进行创建、以先序遍历的方法,附上代码:
 1 void create ( Tree* &T)            
 2     int n;
 3     scanf ( "%d", &n );              //    输入节点数据
 4     if ( n == 0 )                    //    也可以改成其他的,这里仅作为空节点的标志
 5     {
 6         T = NULL;
 7     } 
 8     else 
 9     {
10         T = new Tree;
11         T -> data = n;
12         create ( T -> left );    //    递归创建左孩子
13         create ( T -> right );   //    递归创建右孩子
14     }
15 }

 

直到补全了所有的节点(无孩子的节点用空节点,这里是0来表示)
 

这样一个先序遍历创建的二叉树就建立好了,紧接着就是遍历了,通过遍历可以处理一些基本的操作(增、删、改、查);

二叉树的遍历分为先序遍历、中序遍历、后序遍历以及层次遍历:

来源于维基百科

 

 

先序遍历:

先访问根节点、如果有左孩子,继续访问左孩子,然后将左孩子当作下一个根节点继续重复访问,遇到无左孩子(左孩子为空节点)时开始访问其根节点的右孩子;直到所有的否访问完,退出(图中顺序:2->7->2->6->5->11->5->9->4)。

 

中序遍历:

首先判断是否为空二叉树,如果不是,判断是否有左孩子,如果有访问左孩子,如何继续循环判断,如果没有,开始访问相对根节点(即该节点无孩子,访问该节点的父节点),如何访问右孩子;直到遍历结束退出(途中顺序:2->7->5->6->11->2->5->9->4)。

 

后序遍历:

首先判断是否为空,然后判断是否有左孩子,如果有,访问左孩子,并将左孩子当作根节点继续重复,直到无左孩子时,访问其根节点的右孩子,最后访问根节点,直到遍历结束退出(图中顺序:2->5->11->6->7->4->9->5->2)

 

层次遍历:

层次遍历相对来说好理解一点,就是按行访问,第一行访问结束开始访问下一行,图中的顺序为2->7->5->2->6->9->5->11->4 我相信把访问顺序列出来就应该很容易就理解了。虽然好理解,但是实现起来却不容易;

其实先序中序后续听起来很复杂,弄懂了之后会发现特别简单,先序:跟、左、右;中序:左、根、右;后序:左、右、根;你可以这样理解:按什么顺序,就怎么访问根节点,先序就先访问根节点,中序的话,根节点就放到中间访问,后序就最后访问根节点;理解之后三种顺序搞出来一个,其他两个就So easy 了。
接下来放代码:

 1 void out1 ( Tree* T )                        //        先序遍历输出 
 2 {
 3     if ( T )
 4     {
 5         printf ( "%d ", T -> data );                    //    先访问根节点
 6         out1 ( T -> left );
 7         out1 ( T -> right );
 8     }
 9 }
10 void out2 ( Tree* T )                        //    中序遍历输出 
11 {
12     if ( T )
13     {
14         out2 ( T -> left );                            
15         printf ( "%d ", T -> data );                    //    中间访问根节点
16         out2 ( T -> right );
17     }
18 }
19 void out3 ( Tree* T )                        //        后序遍历输出 
20 {
21     if ( T )
22     {
23         out3 ( T -> left );
24         out3 ( T -> right );
25         printf ( "%d ", T -> data );                       //    最后访问根节点
26     } 
27 }

 

仔细观察不难发现:这三种顺序的代码仅仅是换了位置,代码本身并没有变化,这里的遍历以输出为例,增删改查都是同样的操作。

 1 void out4 ( Tree* T )                        //        层次遍历创建 
 2 {
 3     int rear = -1, front = 0;
 4     Tree *nums[100];
 5     if ( !T )
 6     {
 7         return;
 8     }
 9     nums[front] = T;
10     while ( front != rear )
11     {
12         printf ( "%d ",nums[++rear] -> data );
13         if ( T -> left )
14         {
15             nums[++front] = T -> left;
16         }
17         if ( T -> right )
18         {
19             nums[++front] = T -> right; 
20         }
21         T = nums[rear+1];
22     }
23 }  

 

怎么样,层次遍历还像你想的那么简单了吗?
参差遍历我觉得不用递归的简单些,而且层次遍历相对于先序中序后序来说不是重点,大家选择性的看一下,这里的代码中运用到栈的相关思想,我相信看到二叉树的情况下,栈应该都不成问题了。

最后主函数调用一下即可:

 1 #include "stdio.h"
 2 
 3 int main ( )
 4 {
 5     printf ( "int 型,0 表示空节点:" );
 6     T = new Tree;
 7     create ( T );                            
 8     printf ( "先序遍历输出:" );
 9     out1 ( T );
10     printf ( "\n中序遍历输出:" );
11     out2 ( T );
12     printf ( "\n后序遍历输出:" );
13     out3 ( T );
14     printf ( "\n层次遍历输出:" );
15     out4 ( T );
16     printf ( "\n" );
17     return 0;
18 }

 

希望对大家的学习有一定的帮助,欢迎大家批评指正~

 

posted @ 2018-04-21 16:48  楠少科技  阅读(281)  评论(0编辑  收藏  举报