1、二叉树的深度遍历

二叉树的遍历是指从根结点出发,按照某种次序依次访问二叉树的所有结点,使得每个结点被访问一次且仅被访问一次。

对于二叉树的深度遍历,有前序遍历二叉树、中序遍历二叉树、后序遍历二叉树三种形式,下面分别进行学习和介绍。

1.1 二叉树的前序遍历

        1)前序递归遍历

规则是若二叉树为空,则空操作返回,否则先访问根结点,然后前序遍历左子树,再前序遍历右子树。如下图所示,遍历的顺序为ABDGHCEIF。

前序递归遍历的代码实现,如下所示。

//前序递归遍历
void PreOrderTraverse(BiTree t)
{if(t != NULL){printf("%c ", t->data);PreOrderTraverse(t->lchild);PreOrderTraverse(t->rchild);}
}

2)前序非递归遍历

根据前序遍历访问的顺序,优先访问根结点,然后再分别访问左孩子和右孩子。即对任一结点,其可看做是根结点,因此可以直接访问,访问完之后,若其左孩子不为空,按相同的规则访问它的左子树;当访问其左子树时,再访问它的右子树,因此其处理过程如下:

对于任一结点p:

a. 访问结点p,并将结点p入栈;

b. 判断结点p的左孩子是否为空,若为空,则取栈顶结点并进行出栈操作,并将栈顶结点的右孩子置为当前的结点p,循环置a;若不为空,则将p的左孩子置为当前结点p;

c. 直到p为空,并且栈为空,则遍历结束。

前序非递归遍历代码实现,如下所示。

//前序非递归遍历
int NoPreOrderTraverse(BiTree t)
{SqStack s;InitStack(&s);BiTree tmp = t;if(tmp == NULL){fprintf(stdout, "the tree is null.\n");return ERROR;}while((tmp != NULL) || (IsEmpty(&s) != 1)) {while(tmp != NULL){Push(&s, tmp);printf("%c ", tmp->data);tmp = tmp->lchild;}if(IsEmpty(&s) != 1){Pop(&s, &tmp);tmp = tmp->rchild;}}return OK;
}

1.2 中序遍历二叉树

        1)中序递归遍历

规则是若树为空,则空操作返回,否则从根结点开始(注意这里并不是先访问根结点),中序遍历根结点的左子树,然后是访问根结点,最后中序遍历右子树。如下图所示,遍历的顺序为:GDHBAEICF。

中序递归遍历代码实现如下所示。

//中序递归遍历
void InOrderTraverse(BiTree t)
{if(t != NULL){InOrderTraverse(t->lchild);printf("%c ", t->data);InOrderTraverse(t->rchild);}
}

 2)中序非递归遍历

根据中序遍历的顺序,对于任一结点,优先访问其左孩子,而左孩子结点又可以看做一个根结点,然后继续访问其左孩子结点,直到遇到左孩子结点为空的结点才停止访问,然后按相同的规则访问其右子树。其处理过程如下:

对于任一结点:

a. 若其左孩子不为空,则将p入栈,并将p的左孩子设置为当前的p,然后对当前结点再进行相同的操作;

b. 若其左孩子为空,则取栈顶元素并进行出栈操作,访问该栈顶结点,然后将当前的p置为栈顶结点的右孩子;

c. 直到p为空并且栈为空,则遍历结束。

中序非递归遍历代码实现如下所示。

//中序非递归遍历二叉树
int NoInOrderTraverse(BiTree t)
{SqStack s;InitStack(&s);BiTree tmp = t;if(tmp == NULL){fprintf(stderr, "the tree is null.\n");return ERROR;}while(tmp != NULL || (IsEmpty(&s) != 1)){while(tmp != NULL){Push(&s, tmp);tmp = tmp->lchild;}if(IsEmpty(&s) != 1){Pop(&s, &tmp);printf("%c ", tmp->data);tmp = tmp->rchild;}}return OK;
}

1.3 后序遍历二叉树

        1)后序递归遍历

规则是若树为空,则空操作返回,否则从左到右先叶子后结点的方式遍历访问左右子树,最后是访问根结点。遍历的顺序为:GHDBIEFCA。

后序递归遍历代码实现,如下所示。

//后序递归遍历
void PostOrderTraverse(BiTree t)
{if(t != NULL){PostOrderTraverse(t->lchild);PostOrderTraverse(t->rchild);printf("%c ", t->data);}
}

2)后序非递归遍历

后序遍历的非递归实现是三种遍历方式中最难的一种。因为在后序遍历中,要保证左孩子和右孩子都已被访问,并且左孩子在右孩子之前访问才能访问根结点,这就为流程控制带来了难题。下面介绍一种思路。

要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点p,先将其入栈。若p不存在左孩子和右孩子,则可以直接访问它,或者p存在左孩子或右孩子,但是其左孩子和右孩子都已经被访问过了,则同样可以直接访问该结点。若非上述两种情况,则将p的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子之前别访问,左孩子和右孩子都在根结点前面被访问。

后序非递归遍历代码实现,如下所示。

//后序非递归遍历二叉树
int NoPostOrderTraverse(BiTree t)
{SqStack s;InitStack(&s);BiTree cur;     //当前结点  BiTree pre = NULL;      //前一次访问的结点BiTree tmp;if(t == NULL){fprintf(stderr, "the tree is null.\n");return ERROR;}Push(&s, t);while(IsEmpty(&s) != 1){GetTop(&s, &cur);//if((cur->lchild == NULL && cur->rchild == NULL) || (pre != NULL && (pre == cur->lchild || pre == cur->rchild))){printf("%c ", cur->data);    //如果当前结点没有孩子结点或者孩子结点都已被访问过Pop(&s, &tmp);pre = cur;}else{if(cur->rchild != NULL){Push(&s, cur->rchild);}if(cur->lchild != NULL){Push(&s, cur->lchild);}}}return OK;
}

2、二叉树的广度遍历 

广度遍历二叉树(即层次遍历)是用队列来实现的,从二叉树的第一层(根结点)开始,自上而下逐层遍历;在同一层中,按照从左到右的顺序对结点逐一访问。如下图所示,遍历的顺序为:ABCDEFGHI。

按照从根结点到叶结点、从左子树到右子树的次序访问二叉树的结点,具体思路如下:

A. 初始化一个队列,并把根结点入队列;

B. 当队列为非空时,循环执行步骤3到步骤5,否则执行步骤6;

C. 出队列取得一个结点,访问该结点;

D. 若该结点的左子树为非空,则将该结点的左子树入队列;

E. 若该结点的右子树为非空,则将该结点的右子树入队列;

F. 结束。

广度遍历二叉树代码实现,如下所示。

//层次遍历二叉树 - 广度遍历二叉树 - 队列
int TraverseBiTree(BiTree t)
{LinkQueue q;InitQueue(&q);BiTree tmp = t;if(tmp == NULL){fprintf(stderr, "the tree is null.\n");return ERROR;}InsertQueue(&q, tmp);while(QueueIsEmpty(&q) != OK){DeQueue(&q, &tmp);printf("%c ", tmp->data);if(tmp->lchild != NULL){InsertQueue(&q, tmp->lchild);}if(tmp->rchild != NULL){InsertQueue(&q, tmp->rchild);}}return OK;
}

3、二叉树的建立

如果要在内存中建立一个如下左图这样的树,wield能让每个结点确认是否有左右孩子,我们对它进行扩展,变成如下右图的样子,也就是将二叉树中的每个结点的空指针引出一个虚结点,其值为一个特定值,比如”#”,称之为扩展二叉树。扩展二叉树就可以做到一个遍历序列确定一棵二叉树了。如前序遍历序列为AB#D##C##。

有了这样的准备,就可以看看如何生成一棵二叉树了。假设二叉树的结点均为一个字符,把刚才前序遍历序列AB#D##C##用键盘挨个输入,实现的算法如下所示。

二叉树建立实现代码一,如下所示。

//创建树
//按先后次序输入二叉树中结点的值(一个字符),#表示空树
//构造二叉链表表示的二叉树
BiTree CreateTree(BiTree t)
{char ch;scanf("%c", &ch);if(ch == '#'){t = NULL;}else{t = (BitNode *)malloc(sizeof(BitNode));if(t == NULL){fprintf(stderr, "malloc() error in CreateTree.\n");return;}t->data = ch;                        //生成根结点t->lchild = CreateTree(t->lchild);    //构造左子树t->rchild = CreateTree(t->rchild);    //构造右子树}return t;
}

二叉树建立实现代码二,如下所示。

//创建树方法二
int CreateTree2(BiTree *t)
{char ch;scanf("%c", &ch);if(ch == '#'){(*t) = NULL;}else{(*t) = (BiTree)malloc(sizeof(BitNode));if((*t) == NULL){fprintf(stderr, "malloc() error in CreateTree2.\n");return ERROR;}(*t)->data = ch;CreateTree2(&((*t)->lchild));CreateTree2(&((*t)->rchild));}return OK;
}

其实建立二叉树,也是利用了递归的原理。只不过在原来应该打印结点的地方,改成生成结点、给结点赋值的操作而已。因此,完全可以用中序或后序遍历的方式实现二叉树的建立,只不过代码里生成结点和构造左右子树的代码顺序交互一下即可。

4、二叉树的深度

树中结点的最大层次称为树的深度。对于二叉树,求解树的深度用以下两种方法实现。即非递归和递归的方法实现。

递归求解二叉树的深度实现代码,如下所示。

//二叉树的深度 - 递归
//返回值: 二叉树的深度
int BiTreeDeep(BiTree t)
{int dept = 0;if(t){int lchilddept = BiTreeDeep(t->lchild);int rchilddept = BiTreeDeep(t->rchild);dept = lchilddept >= rchilddept ? (lchilddept + 1) : (rchilddept + 1);}return dept;
}
 对于非递归求解二叉树的深度,这里采用了层次遍历的原理,通过层次遍历,找到二叉树的最后一个结点。然后,根据该结点,寻找其双亲结点,即找到其上一层,此时深度dept加1,依次进行,直到根结点为止。
非递归求解二叉树深度的实现,如下所示。
//返回二叉树的深度 - 非递归  - 受层次遍历二叉树的影响
//返回值: 二叉树的深度
int NoBiTreeDeep(BiTree t)
{LinkQueue q;InitQueue(&q);BiTree tmp = t;if(tmp == NULL){return ERROR;}InsertQueue(&q, tmp);while(QueueIsEmpty(&q) != OK){DeQueue(&q, &tmp);//printf("%c ", tmp->data);if(tmp->lchild != NULL){InsertQueue(&q, tmp->lchild);}if(tmp->rchild != NULL){InsertQueue(&q, tmp->rchild);}}int deep = 0;BiTree m = tmp;BiTree n = t;while(m != n){InsertQueue(&q, n);while(QueueIsEmpty(&q) != OK){DeQueue(&q, &tmp);if(m == tmp->lchild || m == tmp->rchild){deep++;m = tmp;break;}if(tmp->lchild != NULL){InsertQueue(&q, tmp->lchild);}if(tmp->rchild != NULL){InsertQueue(&q, tmp->rchild);}}}return deep + 1;    //深度从1开始
}

二叉树(遍历、建立、深度)相关推荐

  1. java二叉树算法_JAVA 二叉树算法 (遍历、深度、汇总求和)

    二叉树构造类: public class BinaryTree { int data; // 根节点数据 BinaryTree left; // 左子树 BinaryTree right; // 右子 ...

  2. Python:二叉树遍历

    二叉树遍历共有四种方法,分别是前序遍历.中序遍历.后序遍历和层次遍历. 前序遍历: 父节点--左孩子--右孩子 中序遍历:左孩子--父节点--右孩子 后序遍历:左孩子--右孩子--父节点 层次遍历:利 ...

  3. 数据结构之二叉树(遍历、建立、深度)

    数据结构之二叉树(遍历.建立.深度) 1.二叉树的深度遍历 二叉树的遍历是指从根结点出发,按照某种次序依次访问二叉树的所有结点,使得每个结点被访问一次且仅被访问一次. 对于二叉树的深度遍历,有前序遍历 ...

  4. linux 递归创建线程,[linux]二叉树的建立及其递归遍历(C语言实现)

    #二叉树的特点: 每一个节点最多有两棵子树,所以二叉树中不存在度大于2的节点,注意,是最多有两棵,没有也是可以的 左子树和右子树是有顺序的,次序不能颠倒,这点可以在哈夫曼编码中体现, 顺序不同编码方式 ...

  5. 二叉树创建,遍历,叶子,深度

    数据结构实验之二叉树的建立与遍历 Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 已知一个按先序序列输入的字符序列,如a ...

  6. 二叉树广度和深度遍历的全部算法

    二叉树广度和深度遍历的全部算法 对于二叉树的遍历,有广度遍历和深度遍历两大类,对于深度遍历又分为先序.中序和后序,这三种先中后序又可以用递归和非递归两种算法来写,下面就分别对这两大类算法做个总结,以后 ...

  7. 二叉树的建立和遍历的各种问题

    链表声明: //基本结构声明 #include<iostream> #include<queue> #include<stack> #include<cstd ...

  8. 二叉树的建立与遍历(先中后层序)

    在做一些算法题时,我会经常用到VS2017去测试,每次去找一个合适的二叉树觉得很麻烦,今天就自己写了一个放在博客上,下次就直接复制了 包含二叉树的建立,以及二叉树的前序遍历.中序遍历.后序遍历和层序遍 ...

  9. 【算法学习笔记】二叉树的基本操作实现和应用举例,根据先序与中序遍历建立二叉树的实现

    基本操作 给某结点插入一个左孩子 删除二叉树中某结点的左子树 根据先序与中序遍历建立二叉树 应用举例 查找数据元素 二叉链表存储结构 统计叶结点的数目 基本操作 通常有:建立空二叉树.生成以X为根节点 ...

最新文章

  1. android对话框的使用(下)
  2. linux shell中清理僵尸进程
  3. php之二叉树,PHP数据结构之实现链式二叉树与遍历
  4. 关于NandFlash在实际产品使用上的一些经验
  5. MYSQL:多表联合查询的例子
  6. AI和大数据技术应用实践峰会:再谈数据破圈,智能化指引能否少走弯路?(11-25,北京)...
  7. ITK:像素是否在区域内
  8. 计算机基础知识的文献,四 计算机文献检索基础知识(原理、结构和功能)
  9. oracle10g新建数据,Oracle10g手工创建数据库
  10. C#中哈希表(HashTable)的用法详解
  11. javascript 西瓜一期 02 编程语言与标记语言的区别
  12. php去数组中的数据库,php 数据库 取出数组
  13. 深入Webpack-编写Loader
  14. linux 中文ssid 显示乱码,两招解决网络设置 支持中文SSID
  15. 【MEMS传感器】BMI160九轴传感器SPI驱动
  16. 搜集一些常见国家语言Unicode编码范围
  17. Arm linux开发板连接笔记本连通外网
  18. 案例分享:Qt + 树莓派3B+ 智能笔筒系统
  19. 阿里云环境(CentOS7.6)部署Zabbix5.0 Agent2
  20. QQ是怎么处理消息的

热门文章

  1. minijson使用_java layuimini使用json传值
  2. (转)ubuntu 文件系统
  3. vue-router使用next()跳转到指定路径时会无限循环
  4. Windows Presentation Foundation(WPF)中的数据绑定(使用XmlDataProvider作控件绑定)
  5. Caused by: java.lang.ClassNotFoundException: org.objectweb.asm.Type
  6. mvn本地生成jar包放在mvn项目依赖(将jar包传到本地仓库)
  7. redis.conf 配置档详解
  8. 损失函数中正则化项L1和L2的理解
  9. RSA非对称加密算法Java实现之输出key文件
  10. Leetcode 210. 课程表 II 解题思路及C++实现