zoukankan      html  css  js  c++  java
  • 二叉树的创建及各种遍历

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

    二叉树简介

    来源于维基百科

     

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

    二叉树的第i层至多拥有2^{i-1}个节点数;深度为k的二叉树至多总共有{displaystyle 2^{egin{aligned}k+1end{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 ( "
    中序遍历输出:" );
    11     out2 ( T );
    12     printf ( "
    后序遍历输出:" );
    13     out3 ( T );
    14     printf ( "
    层次遍历输出:" );
    15     out4 ( T );
    16     printf ( "
    " );
    17     return 0;
    18 }
    希望对大家的学习有一定的帮助,欢迎大家批评指正~

  • 相关阅读:
    Android Studio打开出现:Default activity not found
    关于LayoutInflater的错误用法(警告提示:Avoid passing null as the view root)
    获取屏幕的宽和高-Display中getHeight()和getWidth() 官方已废弃
    setUserVisibleHint-- fragment真正的onResume和onPause方法
    Fragment的setUserVisibleHint方法实现懒加载,但setUserVisibleHint 不起作用?
    Android权限判断checkPermission
    Android:安装时提示:INSTALL_FAILED_INSUFFICIENT_STORAGE
    Android M新的运行时权限开发者需要知道的一切
    Android开发——Android M(6.0) 权限解决方案
    三个案例带你看懂LayoutInflater中inflate方法两个参数和三个参数的区别
  • 原文地址:https://www.cnblogs.com/nanshaobit/p/12464643.html
Copyright © 2011-2022 走看看