数据结构-二叉树遍历(基于递归实现)

二叉树的存储结构主要了解二叉链表结构,也就是一个数据域,两个指针域,(分别为指向左右孩子的指针)

typedef char DataType;
typedef struct BinTreeNode
{
      //左孩子
      struct BinTreeNode* pleft;
      //右孩子
      struct BinTreeNode* pright;
      //数据区
      DataType data;
}BinTreeNode;

在本文中,我们要构建一棵如下图中的不完全二叉树,他的遍历结果如下图中所示
这里写图片描述

创建二叉树

  • 首先需要创建节点,编写创建节点函数如下

  • 建立二叉树时,这里是以前序遍历的方式,输入的是扩展二叉树,也就是要告诉计算机什么是叶结点,否则将一直递归,当输入“#”时,指针指向NULL,说明是叶结点。

  • 然后定义一个指针index,指向数组首元素,便于操作数组元素(访问,判断)
  • 根据index指针的内容,创建一个节点
  • 然后将指针的位置后移,即++(*index),然后递归调用构建左子树
  • 继续将指针的位置后移,即++(*index),然后递归调用构建右子树
//创建节点
BinTreeNode * BinTreeNodeCreate(DataType value)
{
      BinTreeNode* newnode=(  *BinTreeNode)malloc(BinTreeNode);
      assert(  newnode);
      newnode->data=value;
      newnode->pleft=NULL;
      newnode->right=NULL;
      return newnode;
}


//创建二叉树
BinTreeNode* BinTreeCreate(DataType *arr,size_t size,size_t *index,DataType null_node)
{
     //数组为空或者index指向空
      if(arr==NULL||index==NULL)
      {
            return NULL;
      }
      //如果index不在有效范围内
      if(*index>=size)
      {
            return NULL;
      }
      //如果该节点为空节点
      if(arr[*index]==null_node) 
      {
            return NULL;
      }
      //创建根节点
      BinTreeNode* newnode=BinTreeNodeCreate(arr[*index]);
      //创建左孩子
      ++(*index);
      newnode->pleft=BinTreeCreate(arr,size,index,null_node);
      //创建右孩子
      ++(*index);
      newnode->pright=BinTreeCreate(arr,size,index,null_node);
      return newnode;

}

先序遍历:首先访问根节点,然后遍历访问左子树,最后遍历访问右子树

//二叉树的初始化
void BinTreeInit(BinTreeNode** root)
{
      //非法输入
      if(root==NULL)
      {
            return ;
      }
      *root=NULL;
      return ;
}

先序遍历:首先访问根节点,然后访问根节点的左子树,最后访问根节点的右子树
(这里的访问是指打印,当然还有其他访问方式,如比较,销毁等等)

在途中,蓝色线条圈住的属于同一颗子树,数字标号表示走的顺序

这里写图片描述


//先序遍历
void BinTreePreOrder(BinTreeNode* root)
{
      if(  root==NULL)
      {
            return ;
      }
      //先访问根节点
      printf( "%c   ",root->data);
      //再递归访问左左子树
      BinTreePreOrder(root->pleft);
      //最后递归遍历右子树
      BinTreePreOrder(root->pright);
      return;
}

中序遍历:首先访问根节点的左子树,然后访问根节点,最后访问右子树
如果左右子树还有子数,则重复上述步骤

这里写图片描述


//中序遍历
void BinTreeInOrder(BinTreeNode* root)  
{
      if(  root==NULL)
      {
            return ;
      }
      //先递归遍历左子树
      BinTreeInOrder(  root->pleft);

      //在访问根节点
      printf("%c    "root->data);
      //最后遍历访问右子树
      BinTreeInOrder(  root->pright);
      return ;
}

后续遍历:先访问根节点的左子树,然后访问右子树,最后访问根节点

特点:后序遍历。最后一个元素必定是根节点

这里写图片描述


//后续遍历

void BinTreePostOrder(BinTreeNode* root)  
{
      if(  root==NULL)
      {
            return ;
      }
      //先递归遍历左子树
      BinTreepostOrder(  root->pleft);

      //然后遍历访问右子树
      BinTreepostOrder(  root->pright);
      //最后访问根节点 
      printf("%c    ",root->data);
      return ;
} 

层序遍历:从根节点点出发,从上到下,从左到右,依次访问。

二叉树的层序遍历的实现还是比较简单的,由于其层级的关系,很明显要用到队列来辅助实现,主要是从左向右,自上而下,依次将二叉树的各节点入队,这样便可以保证输出的顺序是层序排列的。下面是算法的实现思想:

先将树的根节点入队,

如果队列不空,则进入循环

{

  将队首元素出队,并输出它;

  如果该队首元素有左孩子,则将其左孩子入队;

  如果该队首元素有右孩子,则将其右孩子入队

}

这里写图片描述



//层序遍历
void BinTreeLeveOrder(BinTreeNode* root)  
{
      SeqQueueNode queue;
      if(  root==NULL)
      {
            return ;
      }

      SeqQueueInit(&queue);
      //将根节点入队列
      SeqQueuePush(&queue,root);
      //循环访问二叉树的左右子树
      while( 1)
      {
            SeqQueueType front;
            //取队首元素,如果返回值是0,则说明对空,结束遍历
            int ret=SeqQueueFront(&queue,&front);
            if(ret==0)
            {
                break;    
            }
            //访问队首元素
            printf("%c  ",front->data);
            //将队首出队列
            SeqQueuePop(&queue);
            //将左子树根节点插入队列
            if(front->pleft)
            {
               SeqQueuePush(&queue,front->pleft);
            }
            //将右子树根节点插入队列
            if(front->pright)
            {
               SeqQueuePush(&queue,front->pright);
            }  

      }



}  
  • 基于后序遍历实现二叉树的销毁

由于二叉树结构根节点便可以找到其他任何节点,所以销毁时,保存根节点,然后递归遍历销毁左右子树,最后销毁根节点

二叉树的每个节点都是通过malloc申请所得,所谓销毁就是free掉malloc申请的节点,并置为NULL,防止野指针出现

//销毁二叉树
void BinTreeDestory(BinTreeNode* root)
{
     //空树,直接返回
      if(root==NULL)
      {
            return ;
      }
      //销毁左子树
      if(root->pleft)
      {
           BinTreeDestory(root->pleft);
           free(root->pleft);
           root->pleft=NULL;
      }
      //销毁右子树
      if(root->pright)
      {
           BinTreeDestory(root->pright);
           free(root->pright);
           root->pright=NULL;
      }
      //销毁根节点
      if(root)
      {
           BinTreeDestory(root);
           free(root);
           root=NULL;
      }


}

当然,也可以按照别的遍历顺序实现销毁,只要在销毁根节点之前先保存左右子树即可。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值