前言


  以下的代码实现都以该完全二叉树为例:

  

声明结构体


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):二叉树的递归遍历的更多相关文章

  1. Java数据结构之二叉树的基本介绍与递归遍历

    二叉树的基本概念: 正如我们所了解的,树是有很多中形态,但是我们规定,形如每个节点最多只能有两个子节点的一种形如称为二叉树.我们将二叉树中该节点的两个子节点分别称作为:左孩子节点和右孩子节点.该节点称 ...

  2. C++学习---二叉树的输入及非递归遍历

    二叉树的二叉链表存储表示如下 //二叉树的二叉链表存储表示 typedef struct BiTNode { char data;//结点数据域 struct BiTNode* lchild, * r ...

  3. 数据结构二叉树的递归与非递归遍历之java,javascript,php实现可编译(1)java

    前一段时间,学习数据结构的各种算法,概念不难理解,只是被C++的指针给弄的犯糊涂,于是用java,web,javascript,分别去实现数据结构的各种算法. 二叉树的遍历,本分享只是以二叉树中的先序 ...

  4. 二叉树3种递归和非递归遍历(Java)

    import java.util.Stack; //二叉树3种递归和非递归遍历(Java) public class Traverse { /******************一二进制树的定义*** ...

  5. C++编程练习(17)----“二叉树非递归遍历的实现“

    二叉树的非递归遍历 最近看书上说道要掌握二叉树遍历的6种编写方式,之前只用递归方式编写过,这次就用非递归方式编写试一试. C++编程练习(8)----“二叉树的建立以及二叉树的三种遍历方式“(前序遍历 ...

  6. 二叉树的递归遍历 Tree UVa548

    题意:给一棵点带权的二叉树的中序和后序遍历,找一个叶子使得他到根的路径上的权值的和最小,如果多解,那该叶子本身的权值应该最小 解题思路:1.用getline()输入整行字符,然后用stringstre ...

  7. c/c++二叉树的创建与遍历(非递归遍历左右中,破坏树结构)

    二叉树的创建与遍历(非递归遍历左右中,破坏树结构) 创建 二叉树的递归3种遍历方式: 1,先中心,再左树,再右树 2,先左树,再中心,再右树 3,先左树,再右树,再中心 二叉树的非递归4种遍历方式: ...

  8. JAVA递归、非递归遍历二叉树(转)

    原文链接: JAVA递归.非递归遍历二叉树 import java.util.Stack; import java.util.HashMap; public class BinTree { priva ...

  9. 非递归遍历二叉树Java实现

    2018-10-03 20:16:53 非递归遍历二叉树是使用堆栈来进行保存,个人推荐使用双while结构,完全按照遍历顺序来进行堆栈的操作,当然在前序和后序的遍历过程中还有其他的压栈流程. 一.Bi ...

  10. ZT 二叉树的非递归遍历

    ZT 二叉树的非递归遍历 二叉树的非递归遍历 二叉树是一种非常重要的数据结构,很多其它数据结构都是基于二叉树的基础演变而来的.对于二叉树,有前序.中序以及后序三种遍历方法.因为树的定义本身就 是递归定 ...

随机推荐

  1. 深入理解Postgres中的cache

    众所周知,缓存是提高数据库性能的一个重要手段.本文着重讲一讲PostgreSQL中的缓存相关的东西.当然万变不离其宗,原理都是共同的,理解了这些,你也很容易把它运用到其它数据库中. What is a ...

  2. 手写particles

    var canvas = document.getElementById('canvas'); var ctx = canvas.getContext('2d'); var Grewer = { in ...

  3. [OIDC in Action] 2. 基于OIDC(OpenID Connect)的SSO(纯JS客户端)

    在上一篇基于OIDC的SSO的中涉及到了4个Web站点: oidc-server.dev:利用oidc实现的统一认证和授权中心,SSO站点. oidc-client-hybrid.dev:oidc的一 ...

  4. GameObject类及相关API

    GameObject.Find(String name):查找一个名为name的游戏物体,并返回这个游戏物体,找不到返回null.(不到万不得已,不要在Update()中使用,建议在Start()中使 ...

  5. 【Centos】解决设置JAVA_HOME不断失效问题

    问题还原: 我们都知道,要修改centos的全局配置,可以在/etc/profile这个文件里面修改,比如,我需要修改JAVA_HOME变量 ,那么一般来说我们只要在其中修改,source 一下就行了 ...

  6. Oracle存储过程和自定义函数

    新博客文章链接,欢迎大家评论探讨 概述 存储过程和存储函数是指存储在数据库中供所有用户程序调用的子程序叫存储过程.存储函数. 异同点: 存储过程和存储函数的相同点:完成特定功能的程序. 存储过程和存储 ...

  7. 基于iframe的移动端嵌套

    需求描述 上上周接到了新的项目,移动端需要做一个底部有五个导航,点击不同的导航页面主体显示不同的页面,其中两个页面是自己做,而另外三个页面是引用另外三个网址,其中两个网址为内部项目,另外一个为外部(涉 ...

  8. redis 梳理笔记(二)

    一.redis 分布式 redis+keepalived (虚ip漂移) redis 100秒平均写入并发  3.6w (写入与keepalived监控程序无关) .redis 数据库内存已占有80% ...

  9. 使用ThinkPHP的扩展功能

    文件上传类的代码位于“\ThinkPHP\Libabry\Think\Uplod.class.php”,实例化电偶用即可.1:在Home模块Index控制器test方法中实现文件上传功能.打开文件\A ...

  10. 如何使用python将MySQL中的查询结果导出为Excel----xlwt的使用

    如何在MySQL中执行的一条查询语句结果导出为Excel? 一.可选方法 1.使用sql yog等远程登录,执行查询语句并导出结果集为Excel 适用于较简单的查询结果集的导出 如果需要多个SQL语句 ...