二叉树Bynary_Tree(2):二叉树的递归遍历
前言
以下的代码实现都以该完全二叉树为例:

声明结构体
typedef struct node
{
char ch;
struct node *lchild;
struct node *rchild;
}TreeNode,*Tree; //注意区别,例如TreeNode X1与*Tree X2,X1为结构体变量,X2为结构体指针变量
创建树

1.采用前序创建
2.若某子结点为不存在,则将其置为NULL,方法为:判断输入的字符是否为' * ',若为* ,则置当前结点为NULL
3.递归创建子结点
void Create_pro(Tree* T)
{
char ch;
scanf("%c", &ch); //需一次性输入所有字符,若分行输入,由于缓冲区问题,多出的空格将一直递归下去
if (ch == '*')
{
*T = NULL;
}
else
{
*T = (Tree)malloc(sizeof(TreeNode));
(*T)->ch = ch;
Create_pro(&((*T)->lchild));
Create_pro(&((*T)->rchild));
}
}
这里遇到的scanf缓冲区问题可移步:http://bbs.csdn.net/topics/390284350?page=1
删除二叉树
void ClearTree(Tree *T)
{
if (!*T)
{
return;
} ClearTree(&(*T)->lchild);
ClearTree(&(*T)->rchild);
free(*T);
*T = NULL;
}
前(根)序遍历
先访问根结点,再分别前序遍历左、右两棵子树。前序遍历的结果是:ABCDEF
void Show_pro(Tree t)
{
if(!t)
return;
printf("%c ",t->ch);
Show_pro(t->lchild);
Show_pro(t->rchild);
}
中(根)序遍历
先中序遍历左子树,然后再访问根结点,最后再中序遍历遍历右子树。中序遍历的结果是:CBADEF
void Show_mid(Tree t)
{
if(!t)
return;
Show_mid(t->lchild);
printf("%c ",t->ch);
Show_mid(t->rchild);
}
后(根)序遍历
先后序遍历左子树,然后后序遍历右子树,最后访问根结点。后序遍历的结果是:CBEFDA
void Show_back(Tree t)
{
if(!t)
return;
Show_back(t->lchild);
Show_back(t->rchild);
printf("%c ",t->ch);
}
层次遍历
先按深度划分层,深度为1的对应树的第一层,深度为二的对应树的第二层...以此类推。然后逐层访问结点。
除层次遍历外的三种遍历的设计核心思想为栈,后进先出,因此想到递归。而层次遍历是队列,先进先出,我采用循环队列去解决。具体的算法设计如下:
1.定义一个队列Tree q[MAX]存储队列数据,头变量front与尾变量rear存储首尾位置,规定front == rear时队列为空。
2.初始化,令 front = 0 ,rear = 0
3.入队操作。将树T存入q[rear]中,即T入队,然后 rear = (rear+1)%MAX ,保持rear在0到MAX中循环
4.输出结点数据。同时判断子结点中数据的存在情况,子结点不为NULL,则再进行入队操作
5.出队操作。front = (front+1)%MAX;
void Show_level(Tree T)
{
Tree q[MAX]; //队列
Tree p; //当前结点
int front;
int rear; //初始化
front =0;
rear =0; if(T)
{
q[rear] = T;
rear = (rear+1)%MAX;
} while(front != rear)
{
p = q[front];
printf("%c ",p->ch);
if(p->lchild)
{
q[rear] = p->lchild;
rear = (rear+1)%MAX;
}
if(p->rchild)
{
q[rear] = p->rchild;
rear = (rear+1)%MAX;
}
front = (front+1)%MAX;
}
}
层次遍历模块中有一个难点,即是入队操作,如何将树并入队列呢?我们想到将若根结点并入队列,那么整棵树便并入队列了。然而,就必须考虑一个问题,根结点的地址就是T的地址吗?

通过在create_tree时将每一次申请的结点地址打印出来,并在创建完毕后在main函数里printf一次T的地址,实际结果如图,根结点地址果然是T的地址,那么我们就可以用根结点入队来实现整棵树入队的操作了,同时也可得到一个结论:递归建树,根结点地址即是树的地址。
判断树是否为空树
void IsTreeEmpty(Tree T)
{
if(T)
printf("Tree is not empty\n");
else
printf("Tree is empty\n");
}
源代码
/*************************************************************************
> File Name: Binary tree
> Author: Bw98
> Mail: 786016746@qq.com
> Blog: www.cnblogs.com/Bw98blogs/
> Created Time: SUN 16th Jul. 2017
************************************************************************/
#include<stdio.h>
#include<stdlib.h>
#define MAX 100
typedef struct node
{
char ch;
struct node *lchild;
struct node *rchild;
}TreeNode,*Tree; void InitTree(Tree *T); //树初始化
void Create_pro(Tree *T); //创建一棵树并输入相应元素
void Show_pro(Tree t); //先(根)序遍历输出
void Show_mid(Tree t); //中(根)序遍历输出
void Show_back(Tree t); //后(根)序遍历输出
void Show_level(Tree T); //层次遍历输出
void IsTreeEmpty(Tree T); //检测树是否为空
void ClearTree(Tree *T); //清除树 int main()
{
Tree t;
InitTree(&t);
printf("输入前序遍历序列(输入'*'时,该树结点为空)\n");
Create_pro(&t);
Show_pro(t);
Show_mid(t);
Show_back(t);
Show_level(t);
IsTreeEmpty(t);
ClearTree(&t);
IsTreeEmpty(t);
return 0;
} void InitTree(Tree *T)
{
*T =NULL;
} void Create_pro(Tree* T)
{
char ch;
scanf("%c", &ch);
if (ch == '*')
{
*T = NULL;
}
else
{
*T = (Tree)malloc(sizeof(TreeNode));
(*T)->ch = ch;
Create_pro(&((*T)->lchild));
Create_pro(&((*T)->rchild));
}
} void Show_pro(Tree t)
{
if(!t)
return;
printf("%c ",t->ch);
Show_pro(t->lchild);
Show_pro(t->rchild);
} void Show_mid(Tree t)
{
if(!t)
return;
Show_mid(t->lchild);
printf("%c ",t->ch);
Show_mid(t->rchild);
} void Show_back(Tree t)
{
if(!t)
return;
Show_back(t->lchild);
Show_back(t->rchild);
printf("%c ",t->ch);
} void Show_level(Tree T)
{
Tree q[MAX]; //队列
Tree p; //当前结点
int front;
int rear; //初始化
front =0;
rear =0; if(T)
{
q[rear] = T;
rear = (rear+1)%MAX;
} while(front != rear)
{
p = q[front];
printf("%c ",p->ch);
if(p->lchild)
{
q[rear] = p->lchild;
rear = (rear+1)%MAX;
}
if(p->rchild)
{
q[rear] = p->rchild;
rear = (rear+1)%MAX;
}
front = (front+1)%MAX;
}
} void IsTreeEmpty(Tree T)
{
if(T)
printf("Tree is not empty\n");
else
printf("Tree is empty\n");
} void ClearTree(Tree *T)
{
if (!(*T))
{
return;
} ClearTree(&(*T)->lchild);
ClearTree(&(*T)->rchild);
free(*T);
*T = NULL;
}
二叉树Bynary_Tree(2):二叉树的递归遍历的更多相关文章
- Java数据结构之二叉树的基本介绍与递归遍历
二叉树的基本概念: 正如我们所了解的,树是有很多中形态,但是我们规定,形如每个节点最多只能有两个子节点的一种形如称为二叉树.我们将二叉树中该节点的两个子节点分别称作为:左孩子节点和右孩子节点.该节点称 ...
- C++学习---二叉树的输入及非递归遍历
二叉树的二叉链表存储表示如下 //二叉树的二叉链表存储表示 typedef struct BiTNode { char data;//结点数据域 struct BiTNode* lchild, * r ...
- 数据结构二叉树的递归与非递归遍历之java,javascript,php实现可编译(1)java
前一段时间,学习数据结构的各种算法,概念不难理解,只是被C++的指针给弄的犯糊涂,于是用java,web,javascript,分别去实现数据结构的各种算法. 二叉树的遍历,本分享只是以二叉树中的先序 ...
- 二叉树3种递归和非递归遍历(Java)
import java.util.Stack; //二叉树3种递归和非递归遍历(Java) public class Traverse { /******************一二进制树的定义*** ...
- C++编程练习(17)----“二叉树非递归遍历的实现“
二叉树的非递归遍历 最近看书上说道要掌握二叉树遍历的6种编写方式,之前只用递归方式编写过,这次就用非递归方式编写试一试. C++编程练习(8)----“二叉树的建立以及二叉树的三种遍历方式“(前序遍历 ...
- 二叉树的递归遍历 Tree UVa548
题意:给一棵点带权的二叉树的中序和后序遍历,找一个叶子使得他到根的路径上的权值的和最小,如果多解,那该叶子本身的权值应该最小 解题思路:1.用getline()输入整行字符,然后用stringstre ...
- c/c++二叉树的创建与遍历(非递归遍历左右中,破坏树结构)
二叉树的创建与遍历(非递归遍历左右中,破坏树结构) 创建 二叉树的递归3种遍历方式: 1,先中心,再左树,再右树 2,先左树,再中心,再右树 3,先左树,再右树,再中心 二叉树的非递归4种遍历方式: ...
- JAVA递归、非递归遍历二叉树(转)
原文链接: JAVA递归.非递归遍历二叉树 import java.util.Stack; import java.util.HashMap; public class BinTree { priva ...
- 非递归遍历二叉树Java实现
2018-10-03 20:16:53 非递归遍历二叉树是使用堆栈来进行保存,个人推荐使用双while结构,完全按照遍历顺序来进行堆栈的操作,当然在前序和后序的遍历过程中还有其他的压栈流程. 一.Bi ...
- ZT 二叉树的非递归遍历
ZT 二叉树的非递归遍历 二叉树的非递归遍历 二叉树是一种非常重要的数据结构,很多其它数据结构都是基于二叉树的基础演变而来的.对于二叉树,有前序.中序以及后序三种遍历方法.因为树的定义本身就 是递归定 ...
随机推荐
- CTF 文件包含与伪协议
正巧在写代码审计的文章,无意间看到了一篇CTF的代码审计,CTF题目很好,用的姿势正如标题,文件包含和伪协议. 先放出原文链接(http://www.freebuf.com/column/150028 ...
- [译]漫画SELinux概念
h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h ...
- Function Programming - First Class(一等公民function)
引用外界一等公民的定义:"在JavaScript世界中函数却是一等公民,它不仅拥有一切传统函数的使用方式(声明和调用),而且可以做到像简单值一样赋值.传参.返回,这样的函数也称之为第一级函数 ...
- static,final,包,访问修饰符,内部类
static 关键字可以修饰成员变量,被static修饰的成员变量归属于类static关键字可以修饰成员方法:被static修饰的成员方法可以直接使用类名调用,也可以通过对象调用,建议使用类名.非静态 ...
- 【转】千万不要在JS中使用连等赋值操作
原文链接 千万不要在JS中使用连等赋值操作 目录 前言 赋值顺序? 连续赋值能拆开写么? 后记 前言 文章标题这句话原本是在国外某JavaScript规范里看到的,当时并没有引起足够的重视,直到最 ...
- TCP/IP 协议栈 ------ ICMP
I C M P经常被认为是 I P层的一个组成部分.它传递差错报文以及其他需要注意的信息.I C M P报文通常被I P层或更高层协议( T C P或U D P)使用.一些I C M P报文把差错报文 ...
- javaWeb开发中关于eclipse等ide重新部署或重启项目等原因造成上传文件丢失问题解决方案
在开发项目时,有时候需要用到上传功能,比如头像上传等,其文件会保存到服务器中.但是我发现在用eclipse做项目的过程中,每次重新部署项目,原来上传的文件就会丢失. 其原因是因为每次项目修改后,ecl ...
- 读取不标准的JSON数据
正常的JSON数据 [ {"key":"UI","value":"UII"}, {"key ...
- PDFBox 打印带背景的文件速度慢
打印慢的原因 java的RasterPrinterJob会执行很多次printPage方法 他应该是按块填充的, 如果页面元素非常复杂, 那么printPage方法可能会执行十几次. 而如果你用了如下 ...
- 大白话Vue源码系列(02):编译器初探
阅读目录 编译器代码藏在哪 Vue.prototype.$mount 构建 AST 的一般过程 Vue 构建的 AST 题接上文,上回书说到,Vue 的编译器模块相对独立且简单,那咱们就从这块入手,先 ...