共计 16621 个字符,预计需要花费 42 分钟才能阅读完成。
@[TOC]
先序遍历
先序遍历规定
先序遍历的核心思想:1. 拜访根节点;2. 拜访以后节点的左子树;3. 若以后节点无左子树,则拜访以后节点的右子树;即考查到一个节点后,即刻输入该节点的值,并持续遍历其左右子树。(根左右)
先序遍历举例
如图所示,采纳先序遍历拜访这颗二叉树的具体过程为:
1. 拜访该二叉树的根节点,找到 1;
2. 拜访节点 1 的左子树,找到节点 2;
3. 拜访节点 2 的左子树,找到节点 4;
4. 因为拜访节点 4 左子树失败,且也没有右子树,因而以节点 4 为根节点的子树遍历实现。但节点 2 还没有遍历其右子树,因而当初开始遍历,即拜访节点 5;
5. 因为节点 5 无左右子树,因而节点 5 遍历实现,并且由此以节点 2 为根节点的子树也遍历实现。当初回到节点 1,并开始遍历该节点的右子树,即拜访节点 3;
6. 拜访节点 3 左子树,找到节点 6;
7. 因为节点 6 无左右子树,因而节点 6 遍历实现,回到节点 3 并遍历其右子树,找到节点 7;
8. 节点 7 无左右子树,因而以节点 3 为根节点的子树遍历实现,同时回归节点 1。因为节点 1 的左右子树全副遍历实现,因而整个二叉树遍历实现;
因而,图 中二叉树采纳先序遍历失去的序列为:1 2 4 5 3 6 7
先序遍历代码(递归)
/*
* @Description:
* @Version:
* @Autor: Carlos
* @Date: 2020-05-29 16:55:41
* @LastEditors: Carlos
* @LastEditTime: 2020-05-30 17:03:23
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define TElemType int
// 结构结点的构造体
typedef struct BiTNode{
TElemType data;// 数据域
struct BiTNode *lchild,*rchild;// 左右孩子指针
}BiTNode,*BiTree;
/**
* @Description: 初始化树的函数
* @Param: BiTree *T 构造体指针的指针
* @Return: 无
* @Author: Carlos
*/
void CreateBiTree(BiTree *T){*T=(BiTree)malloc(sizeof(BiTNode));
// 根节点
(*T)->data=1;
(*T)->lchild=(BiTree)malloc(sizeof(BiTNode));
(*T)->rchild=(BiTree)malloc(sizeof(BiTNode));
// 1 节点的左孩子 2
(*T)->lchild->data=2;
(*T)->lchild->lchild=(BiTree)malloc(sizeof(BiTNode));
(*T)->lchild->rchild=(BiTree)malloc(sizeof(BiTNode));
// 2 节点的右孩子 5
(*T)->lchild->rchild->data=5;
(*T)->lchild->rchild->lchild=NULL;
(*T)->lchild->rchild->rchild=NULL;
// 1 节点的右孩子 3
(*T)->rchild->data=3;
(*T)->rchild->lchild=(BiTree)malloc(sizeof(BiTNode));
// 3 节点的左孩子 6
(*T)->rchild->lchild->data=6;
(*T)->rchild->lchild->lchild=NULL;
(*T)->rchild->lchild->rchild=NULL;
(*T)->rchild->rchild=(BiTree)malloc(sizeof(BiTNode));
// 3 节点的右孩子 7
(*T)->rchild->rchild->data=7;
(*T)->rchild->rchild->lchild=NULL;
(*T)->rchild->rchild->rchild=NULL;
// 2 节点的左孩子 4
(*T)->lchild->lchild->data=4;
(*T)->lchild->lchild->lchild=NULL;
(*T)->lchild->lchild->rchild=NULL;
}
/**
* @Description: 模仿操作结点元素的函数,输入结点自身的数值
* @Param:BiTree elem 就构造体指针
* @Return: 无
* @Author: Carlos
*/
void PrintBiT(BiTree elem){printf("%d",elem->data);
}
/**
* @Description: 先序遍历
* @Param: BiTree T 构造体指针
* @Return: 无
* @Author: Carlos
*/
void PreOrderTraverse(BiTree T){if (T) {PrintBiT(T);// 调用操作结点数据的函数办法
PreOrderTraverse(T->lchild);// 拜访该结点的左孩子
PreOrderTraverse(T->rchild);// 拜访该结点的右孩子
}
// 如果结点为空,返回上一层
return;
}
int main() {
BiTree Tree;
CreateBiTree(&Tree);
printf("先序遍历: \n");
PreOrderTraverse(Tree);
}
先序遍历代码(非递归)
因为要在遍历完某个树的根节点的左子树后接着遍历节点的右子树,为了能找到该树的根节点,须要应用栈来进行暂存。中序和后序也都波及到回溯,所以都须要用到栈。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define TElemType int
// 结构结点的构造体
typedef struct BiTNode{
TElemType data;// 数据域
struct BiTNode *lchild,*rchild;// 左右孩子指针
}BiTNode,*BiTree;
int top = -1;
// 定义一个程序栈
BiTree a[20];
/**
* @Description: 初始化树
* @Param: BiTree *T 指针的指针
* @Return: 无
* @Author: Carlos
*/
void CreateBiTree(BiTree *T){*T=(BiTree)malloc(sizeof(BiTNode));
// 根节点
(*T)->data=1;
(*T)->lchild=(BiTree)malloc(sizeof(BiTNode));
(*T)->rchild=(BiTree)malloc(sizeof(BiTNode));
// 1 节点的左孩子 2
(*T)->lchild->data=2;
(*T)->lchild->lchild=(BiTree)malloc(sizeof(BiTNode));
(*T)->lchild->rchild=(BiTree)malloc(sizeof(BiTNode));
// 2 节点的右孩子 5
(*T)->lchild->rchild->data=5;
(*T)->lchild->rchild->lchild=NULL;
(*T)->lchild->rchild->rchild=NULL;
// 1 节点的右孩子 3
(*T)->rchild->data=3;
(*T)->rchild->lchild=(BiTree)malloc(sizeof(BiTNode));
// 3 节点的左孩子 6
(*T)->rchild->lchild->data=6;
(*T)->rchild->lchild->lchild=NULL;
(*T)->rchild->lchild->rchild=NULL;
(*T)->rchild->rchild=(BiTree)malloc(sizeof(BiTNode));
// 3 节点的右孩子 7
(*T)->rchild->rchild->data=7;
(*T)->rchild->rchild->lchild=NULL;
(*T)->rchild->rchild->rchild=NULL;
// 2 节点的左孩子 4
(*T)->lchild->lchild->data=4;
(*T)->lchild->lchild->lchild=NULL;
(*T)->lchild->lchild->rchild=NULL;
}
/**
* @Description: 打印二叉树
* @Param: BiTree elem 指针的指针
* @Return: 无
* @Author: Carlos
*/
void PrintBiT(BiTree elem){printf("%d",elem->data);
}
/**
* @Description: 二叉树压栈函数
* @Param: BiTree* a 构造体指针的指针(也能够了解为指针数组)BiTree elem 构造体指针
* @Return: 无
* @Author: Carlos
*/
void Push(BiTree* a,BiTree elem)
{a[++top]=elem;
}
/**
* @Description: 二叉树弹栈函数
* @Param: 无
* @Return: 无
* @Author: Carlos
*/
void Pop()
{if (top==-1) {return ;}
top--;
}
/**
* @Description: 获取栈顶元素
* @Param: BiTree*a 构造体指针数组
* @Return: 构造体指针
* @Author: Carlos
*/
BiTree GetTop(BiTree*a){return a[top];
}
/**
* @Description: 先序遍历
* @Param: BiTree Tree 构造体指针
* @Return: 无
* @Author: Carlos
*/
void PreOrderTraverse(BiTree Tree)
{
// 长期指针
BiTree p;
// 根结点进栈
Push(a, Tree);
while (top!=-1) {
// 取栈顶元素
p=GetTop(a);
// 弹栈
Pop();
while (p) {
// 调用结点的操作函数
PrintBiT(p);
// 如果该结点有右孩子,右孩子进栈
if (p->rchild) {Push(a,p->rchild);
}
p=p->lchild;// 始终指向根结点最初一个左孩子
}
}
}
int main() {
BiTree Tree;
CreateBiTree(&Tree);
printf("先序遍历: \n");
PreOrderTraverse(Tree);
}
中序遍历
中序遍历规定
二叉树中序遍历的实现思维是:1. 拜访以后节点的左子树;2. 拜访根节点;3. 拜访以后节点的右子树。即考查到一个节点后,将其暂存,遍历完左子树后,再输入该节点的值,而后遍历右子树。(左根右)
中序遍历举例
以上图为例,采纳中序遍历的思维遍历该二叉树的过程为:
1. 拜访该二叉树的根节点,找到 1;
2. 遍历节点 1 的左子树,找到节点 2;
3. 遍历节点 2 的左子树,找到节点 4;
4. 因为节点 4 无左孩子,因而找到节点 4,并遍历节点 4 的右子树;
5. 因为节点 4 无右子树,因而节点 2 的左子树遍历实现,拜访节点 2;
6. 遍历节点 2 的右子树,找到节点 5;
7. 因为节点 5 无左子树,因而拜访节点 5,又因为节点 5 没有右子树,因而节点 1 的左子树遍历实现,拜访节点 1,并遍历节点 1 的右子树,找到节点 3;
8. 遍历节点 3 的左子树,找到节点 6;
9. 因为节点 6 无左子树,因而拜访节点 6,又因为该节点无右子树,因而节点 3 的左子树遍历实现,开始拜访节点 3,并遍历节点 3 的右子树,找到节点 7;
10. 因为节点 7 无左子树,因而拜访节点 7,又因为该节点无右子树,因而节点 1 的右子树遍历实现,即整棵树遍历实现;
因而,上图中二叉树采纳中序遍历失去的序列为:4 2 5 1 6 3 7
中序遍历代码(递归)
/*
* @Description: 递归实现的中序遍历
* @Version: V1.0
* @Autor: Carlos
* @Date: 2020-05-18 14:53:29
* @LastEditors: Carlos
* @LastEditTime: 2020-05-30 17:21:06
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define TElemType int
// 结构结点的构造体
typedef struct BiTNode{
// 数据域
TElemType data;
// 左右孩子指针
struct BiTreelchild,*rchild;
}BiTNode,*BiTree;
/**
* @Description: 初始化树
* @Param: BiTree *T 构造体指针的指针(指针数组)* @Return: 无
* @Author: Carlos
*/
void CreateBiTree(BiTree *T){*T=(BiTree)malloc(sizeof(BiTNode));
(*T)->data=1;
(*T)->lchild=(BiTree)malloc(sizeof(BiTNode));
(*T)->rchild=(BiTree)malloc(sizeof(BiTNode));
(*T)->lchild->data=2;
(*T)->lchild->lchild=(BiTree)malloc(sizeof(BiTNode));
(*T)->lchild->rchild=(BiTree)malloc(sizeof(BiTNode));
(*T)->lchild->rchild->data=5;
(*T)->lchild->rchild->lchild=NULL;
(*T)->lchild->rchild->rchild=NULL;
(*T)->rchild->data=3;
(*T)->rchild->lchild=(BiTree)malloc(sizeof(BiTNode));
(*T)->rchild->lchild->data=6;
(*T)->rchild->lchild->lchild=NULL;
(*T)->rchild->lchild->rchild=NULL;
(*T)->rchild->rchild=(BiTree)malloc(sizeof(BiTNode));
(*T)->rchild->rchild->data=7;
(*T)->rchild->rchild->lchild=NULL;
(*T)->rchild->rchild->rchild=NULL;
(*T)->lchild->lchild->data=4;
(*T)->lchild->lchild->lchild=NULL;
(*T)->lchild->lchild->rchild=NULL;
}
/**
* @Description: 显示函数
* @Param: BiTree elem 构造体指针
* @Return: 无
* @Author: Carlos
*/
void PrintBiT(BiTree elem){printf("%d",elem->data);
}
/**
* @Description: 中序遍历
* @Param: BiTree T 构造体指针
* @Return: 无
* @Author: Carlos
*/
void INOrderTraverse(BiTree T){if (T) {INOrderTraverse(T->lchild);// 遍历左孩子
PrintBiT(T);// 调用操作结点数据的函数办法
INOrderTraverse(T->rchild);// 遍历右孩子
}
// 如果结点为空,返回上一层
return;
}
int main() {
BiTree Tree;
CreateBiTree(&Tree);
printf("中序遍历算法: \n");
INOrderTraverse(Tree);
}
中序遍历代码(非递归)
和非递归先序遍历相似,惟一区别是考查到以后节点时,并不间接输入该节点。而是当考查节点为空时,从栈中弹出的时候再进行输入(永远先思考左子树,直到左子树为空才拜访根节点)。
/*
* @Description: 二叉树的先序遍历(非递归)* @Version: V1.0
* @Autor: Carlos
* @Date: 2020-05-17 16:35:27
* @LastEditors: Carlos
* @LastEditTime: 2020-05-18 14:51:01
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define DBG_PRINTF(fmt, args...) \
do\
{\
printf("<<File:%s Line:%d Function:%s>>", __FILE__, __LINE__, __FUNCTION__);\
printf(fmt, ##args);\
}while(0)
#define TElemType int
int top=-1;//top 变量时刻示意栈顶元素所在位置
// 结构结点的构造体
typedef struct BiTNode{
// 数据域
TElemType data;
// 左右孩子指针
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
/**
* @Description: 初始化树
* @Param: BiTree *T 构造体指针的指针
* @Return: 无
* @Author: Carlos
*/
void CreateBiTree(BiTree *T){*T=(BiTree)malloc(sizeof(BiTNode));
(*T)->data=1;
(*T)->lchild=(BiTree)malloc(sizeof(BiTNode));
(*T)->rchild=(BiTree)malloc(sizeof(BiTNode));
(*T)->lchild->data=2;
(*T)->lchild->lchild=(BiTree)malloc(sizeof(BiTNode));
(*T)->lchild->rchild=(BiTree)malloc(sizeof(BiTNode));
(*T)->lchild->rchild->data=5;
(*T)->lchild->rchild->lchild=NULL;
(*T)->lchild->rchild->rchild=NULL;
(*T)->rchild->data=3;
(*T)->rchild->lchild=(BiTree)malloc(sizeof(BiTNode));
(*T)->rchild->lchild->data=6;
(*T)->rchild->lchild->lchild=NULL;
(*T)->rchild->lchild->rchild=NULL;
(*T)->rchild->rchild=(BiTree)malloc(sizeof(BiTNode));
(*T)->rchild->rchild->data=7;
(*T)->rchild->rchild->lchild=NULL;
(*T)->rchild->rchild->rchild=NULL;
(*T)->lchild->lchild->data=4;
(*T)->lchild->lchild->lchild=NULL;
(*T)->lchild->lchild->rchild=NULL;
}
/**
* @Description: 中序遍历应用的进栈函数
* @Param: BiTree* a 指向树的指针数组 BiTree elem 进栈的元素
* @Return: 无
* @Author: Carlos
*/
void Push(BiTree* a,BiTree elem){
// 指针进栈
a[++top]=elem;
}
/**
* @Description: 前序遍历应用的弹栈函数
* @Param: 无
* @Return: 无
* @Author: Carlos
*/
void Pop( ){if (top==-1) {return;}
top--;
}
/**
* @Description: 显示函数
* @Param: BiTree elem 指向树的指针
* @Return: 无
* @Author: Carlos
*/
void PrintBiT(BiTree elem){printf("%d",elem->data);
}
/**
* @Description: 拿到栈顶元素
* @Param: BiTree*a 指针数组
* @Return: 栈顶元素的地址
* @Author: Carlos
*/
BiTree GetTop(BiTree*a){return a[top];
}
/**
* @Description: 中序遍历非递归算法,先左,而后回退,而后右。从根结点开始,遍历左孩子同时压栈,当遍历完结,阐明以后遍历的结点没有左孩子,* 从栈中取出来调用操作函数,而后拜访该结点的右孩子,持续以上重复性的操作
* @Return: 栈顶元素的地址
* @Author: Carlos
*/
void InOrderTraverse1(BiTree Tree){
// 定义一个程序栈
BiTree a[20];
// 长期指针
BiTree p;
// 根结点进栈
Push(a, Tree);
//top!=- 1 阐明栈内不为空,程序持续运行
while (top!=-1) {
// 始终取栈顶元素,且不能为 NULL
while ((p=GetTop(a)) &&p){
// 将该结点的左孩子进栈,如果没有左孩子,NULL 进栈
Push(a, p->lchild);
}
// 跳出循环,栈顶元素必定为 NULL,将 NULL 弹栈。打印的第一个元素没有右孩子,所以也会 Pop 掉,再取栈顶元素就是第一个元素的父节点
Pop();
if (top!=-1) {
// 取栈顶元素
p=GetTop(a);
// 栈顶元素弹栈
Pop();
// 遍历完所有左孩子之后,打印栈顶的元素。PrintBiT(p);
// 将 p 指向的结点的右孩子进栈
Push(a, p->rchild);
}
}
}
/**
* @Description: 中序遍历非递归算法。中序遍历过程中,只需将每个结点的左子树压栈即可,右子树不须要压栈。* 当结点的左子树遍历实现后,只须要以栈顶结点的右孩子为根结点,持续循环遍历即可
* @Param: 无
* @Return: 栈顶元素的地址
* @Author: Carlos
*/
void InOrderTraverse2(BiTree Tree){
// 定义一个程序栈
BiTree a[20];
// 长期指针
BiTree p;
p=Tree;
// 当 p 为 NULL 或者栈为空时,表明树遍历实现
while (p || top!=-1) {
// 如果 p 不为 NULL,将其压栈并遍历其左子树
if (p) {Push(a, p);
p=p->lchild;
}
// 如果 p ==NULL,表明左子树遍历实现,须要遍历上一层结点的右子树 弹出时顺便拜访右子树
else{p=GetTop(a);
Pop();
PrintBiT(p);
p=p->rchild;
}
}
}
int main(){
BiTree Tree;
CreateBiTree(&Tree);
printf("中序遍历: \r\n");
InOrderTraverse2(Tree);
DBG_PRINTF("123456\r\n");
return 0;
}
后序遍历
后序遍历规定
二叉树后序遍历的实现思维是:1. 拜访左子树;2. 拜访右子树;3. 实现该节点的左右子树的拜访后,再拜访该节点。即考查到一个节点后,将其暂存,遍历完左右子树后,再输入该节点的值。(左右根)
后序遍历举例
如上图中,对此二叉树进行后序遍历的操作过程为:
从根节点 1 开始,遍历该节点的左子树(以节点 2 为根节点);
1. 遍历节点 2 的左子树(以节点 4 为根节点);
2. 因为节点 4 既没有左子树,也没有右子树,此时拜访该节点中的元素 4,并回退到节点 2,遍历节点 2 的右子树(以 5 为根节点);
3. 因为节点 5 无左右子树,因而能够拜访节点 5,并且此时节点 2 的左右子树也遍历实现,因而也能够拜访节点 2;
4. 此时回退到节点 1,开始遍历节点 1 的右子树(以节点 3 为根节点);
5. 遍历节点 3 的左子树(以节点 6 为根节点);
6. 因为节点 6 无左右子树,因而拜访节点 6,并回退到节点 3,开始遍历节点 3 的右子树(以节点 7 为根节点);
7. 因为节点 7 无左右子树,因而拜访节点 7,并且节点 3 的左右子树也遍历实现,能够拜访节点 3;节点 1 的左右子树也遍历实现,能够拜访节点 1;
由此,对上图 中二叉树进行后序遍历的后果为:4 5 2 6 7 3 1
后序遍历代码(递归)
/*
* @Description: 二叉树的后序遍历(递归)* @Version: V1.0
* @Autor: Carlos
* @Date: 2020-05-18 16:23:57
* @LastEditors: Carlos
* @LastEditTime: 2020-05-30 17:29:38
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define TElemType int
// 结构结点的构造体
typedef struct BiTNode{
// 数据域
TElemType data;
// 左右孩子指针
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
/**
* @Description: 初始化树
* @Param: BiTree *T 构造体指针
* @Return: 无
* @Author: Carlos
*/
void CreateBiTree(BiTree *T){*T=(BiTree)malloc(sizeof(BiTNode));
(*T)->data=1;
(*T)->lchild=(BiTree)malloc(sizeof(BiTNode));
(*T)->rchild=(BiTree)malloc(sizeof(BiTNode));
(*T)->lchild->data=2;
(*T)->lchild->lchild=(BiTree)malloc(sizeof(BiTNode));
(*T)->lchild->rchild=(BiTree)malloc(sizeof(BiTNode));
(*T)->lchild->rchild->data=5;
(*T)->lchild->rchild->lchild=NULL;
(*T)->lchild->rchild->rchild=NULL;
(*T)->rchild->data=3;
(*T)->rchild->lchild=(BiTree)malloc(sizeof(BiTNode));
(*T)->rchild->lchild->data=6;
(*T)->rchild->lchild->lchild=NULL;
(*T)->rchild->lchild->rchild=NULL;
(*T)->rchild->rchild=(BiTree)malloc(sizeof(BiTNode));
(*T)->rchild->rchild->data=7;
(*T)->rchild->rchild->lchild=NULL;
(*T)->rchild->rchild->rchild=NULL;
(*T)->lchild->lchild->data=4;
(*T)->lchild->lchild->lchild=NULL;
(*T)->lchild->lchild->rchild=NULL;
}
/**
* @Description: 显示函数
* @Param: BiTree elem 指向树的构造体指针
* @Return: 无
* @Author: Carlos
*/
void PrintBiT(BiTree elem){printf("%d",elem->data);
}
/**
* @Description: 先序遍历
* @Param: BiTree T 指针数组,寄存各个节点的指针
* @Return: 无
* @Author: Carlos
*/
void PreOrderTraverse(BiTree T){if (T) {PreOrderTraverse(T->lchild);// 拜访该结点的左孩子
PreOrderTraverse(T->rchild);// 拜访该结点的右孩子
PrintBiT(T);// 调用操作结点数据的函数办法
}
// 如果结点为空,返回上一层
return;
}
int main() {
BiTree Tree;
CreateBiTree(&Tree);
printf("后序遍历: \n");
PreOrderTraverse(Tree);
}
后序遍历代码(非递归)
/*
* @Description: 二叉树的后序遍历(非递归)* @Version: V1.0
* @Autor: Carlos
* @Date: 2020-05-18 16:23:57
* @LastEditors: Carlos
* @LastEditTime: 2020-05-18 16:24:29
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define TElemType int
//top 变量时刻示意栈顶元素所在位置
int top=-1;
// 结构结点的构造体
typedef struct BiTNode{
// 数据域
TElemType data;
// 左右孩子指针
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
/**
* @Description: 初始化树
* @Param: BiTree *T 构造体指针数组
* @Return: 无
* @Author: Carlos
*/
void CreateBiTree(BiTree *T){*T=(BiTNode*)malloc(sizeof(BiTNode));
(*T)->data=1;
(*T)->lchild=(BiTNode*)malloc(sizeof(BiTNode));
(*T)->rchild=(BiTNode*)malloc(sizeof(BiTNode));
(*T)->lchild->data=2;
(*T)->lchild->lchild=(BiTNode*)malloc(sizeof(BiTNode));
(*T)->lchild->rchild=(BiTNode*)malloc(sizeof(BiTNode));
(*T)->lchild->rchild->data=5;
(*T)->lchild->rchild->lchild=NULL;
(*T)->lchild->rchild->rchild=NULL;
(*T)->rchild->data=3;
(*T)->rchild->lchild=(BiTNode*)malloc(sizeof(BiTNode));
(*T)->rchild->lchild->data=6;
(*T)->rchild->lchild->lchild=NULL;
(*T)->rchild->lchild->rchild=NULL;
(*T)->rchild->rchild=(BiTNode*)malloc(sizeof(BiTNode));
(*T)->rchild->rchild->data=7;
(*T)->rchild->rchild->lchild=NULL;
(*T)->rchild->rchild->rchild=NULL;
(*T)->lchild->lchild->data=4;
(*T)->lchild->lchild->lchild=NULL;
(*T)->lchild->lchild->rchild=NULL;
}
/**
* @Description: 后序遍历应用的弹栈函数
* @Param: 无
* @Return: 无
* @Author: Carlos
*/
void Pop( ){if (top==-1) {return ;}
top--;
}
/**
* @Description: 显示函数
* @Param: 无
* @Return: 无
* @Author: Carlos
*/
void PrintBiT(BiTree elem){printf("%d",elem->data);
}
// 减少左右子树的拜访标记
typedef struct SNode{
BiTree p;
int tag;
}SNode;
/**
* @Description: 后序遍历应用的进栈函数
* @Param: SNode *a 指向树和标记位的构造体的指针 BiTree sdata 进栈的元素
* @Return: 无
* @Author: Carlos
*/
void Push(SNode *a,SNode sdata){a[++top]=sdata;
}
/**
* @Description: 后序遍历非递归算法。后序遍历是在遍历完以后结点的左右孩子之后,才调用操作函数,所以须要在操作结点进栈时,为每个结点装备一个标记位。* 当遍历该结点的左孩子时,设置以后结点的标记位为 0,进栈;当要遍历该结点的右孩子时,设置以后结点的标记位为 1,进栈。这样,当遍历实现,该结点弹栈时,* 查看该结点的标记位的值:如果是 0,示意该结点的右孩子还没有遍历;反之如果是 1,阐明该结点的左右孩子都遍历实现,能够调用操作函数。* @Param: 构造体指针数组
* @Return: 无
* @Author: Carlos
*/
void PostOrderTraverse(BiTree Tree){
// 定义一个程序栈
SNode a[20];
// 长期指针
BiTree p;
int tag;
SNode sdata;
p=Tree;
while (p||top!=-1) {
// 左孩子进栈
while (p) {
// 为该结点入栈做筹备
sdata.p=p;
// 因为遍历是左孩子,设置标记位为 0
sdata.tag=0;
// 压栈
Push(a, sdata);
// 以该结点为根结点,遍历左孩子
p=p->lchild;
}
// 取栈顶元素 取左孩子的父节点
sdata=a[top];
// 栈顶元素弹栈
Pop();
p=sdata.p;
tag=sdata.tag;
// 右孩子进栈
// 如果 tag==0,阐明该结点还没有遍历它的右孩子
if (tag==0) {
sdata.p=p;
sdata.tag=1;
// 更改该结点的标记位,从新压栈
Push(a, sdata);
// 以该结点的右孩子为根结点,反复循环
p=p->rchild;
}
// 如果取出来的栈顶元素的 tag==1,阐明此结点左右子树都遍历完了,能够调用操作函数了
else{PrintBiT(p);
p=NULL;
}
}
}
int main(){
BiTree Tree;
CreateBiTree(&Tree);
printf("后序遍历: \n");
PostOrderTraverse(Tree);
}
档次遍历
档次遍历规定
依照二叉树中的档次从左到右顺次遍历每层中的结点。通过应用队列的数据结构,从树的根结点开始,顺次将其左孩子和右孩子入队。而后每次队列中一个结点出队,都将其左孩子和右孩子入队,直到树中所有结点都出队,出队结点的先后顺序就是档次遍历的最终后果。
档次遍历举例
例如,档次遍历如上图中的二叉树:
1. 根结点 1 入队;
2. 根结点 1 出队,出队的同时,将左孩子 2 和右孩子 3 别离入队;
3. 队头结点 2 出队,出队的同时,将结点 2 的左孩子 4 和右孩子 5 顺次入队;
4. 队头结点 3 出队,出队的同时,将结点 3 的左孩子 6 和右孩子 7 顺次入队;
5. 一直地循环,直至队列内为空。
档次遍历代码
/*
* @Description: 二叉树的档次遍历
* @Version: V1.0
* @Autor: Carlos
* @Date: 2020-05-20 14:52:38
* @LastEditors: Carlos
* @LastEditTime: 2020-05-30 17:41:48
*/
#include <stdio.h>
#include <stdlib.h>
#define TElemType int
// 初始化队头和队尾指针开始时都为 0
int front=0,rear=0;
typedef struct BiTNode{
// 数据域
TElemType data;
// 左右孩子指针
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
// 采纳程序队列,初始化创立队列数组
BiTree a[20];
/**
* @Description: 初始化二叉树
* @Param: BiTree *T 二叉树的构造体指针数组
* @Return: 无
* @Author: Carlos
*/
void CreateBiTree(BiTree *T){*T=(BiTNode*)malloc(sizeof(BiTNode));
(*T)->data=1;
(*T)->lchild=(BiTNode*)malloc(sizeof(BiTNode));
(*T)->rchild=(BiTNode*)malloc(sizeof(BiTNode));
(*T)->lchild->data=2;
(*T)->lchild->lchild=(BiTNode*)malloc(sizeof(BiTNode));
(*T)->lchild->rchild=(BiTNode*)malloc(sizeof(BiTNode));
(*T)->lchild->rchild->data=5;
(*T)->lchild->rchild->lchild=NULL;
(*T)->lchild->rchild->rchild=NULL;
(*T)->rchild->data=3;
(*T)->rchild->lchild=(BiTNode*)malloc(sizeof(BiTNode));
(*T)->rchild->lchild->data=6;
(*T)->rchild->lchild->lchild=NULL;
(*T)->rchild->lchild->rchild=NULL;
(*T)->rchild->rchild=(BiTNode*)malloc(sizeof(BiTNode));
(*T)->rchild->rchild->data=7;
(*T)->rchild->rchild->lchild=NULL;
(*T)->rchild->rchild->rchild=NULL;
(*T)->lchild->lchild->data=4;
(*T)->lchild->lchild->lchild=NULL;
(*T)->lchild->lchild->rchild=NULL;
}
/**
* @Description: 入队
* @Param: BiTree *a 二叉树构造体指针 BiTree node 入队的节点
* @Return: 无
* @Author: Carlos
*/
void EnQueue(BiTree *a,BiTree node){a[rear++]=node;
}
/**
* @Description: 出队
* @Param: BiTree *node 二叉树构造体指针数组
* @Return: 构造体指针
* @Author: Carlos
*/
BiTree DeQueue(BiTree *node){return a[front++];
}
/**
* @Description: 二叉树输入函数
* @Param: BiTree node 输入的节点
* @Return: 无
* @Author: Carlos
*/
void displayNode(BiTree node){printf("%d",node->data);
}
int main() {
BiTree tree;
// 初始化二叉树
CreateBiTree(&tree);
BiTree p;
// 根结点入队
EnQueue(a, tree);
// 当队头和队尾相等时,示意队列为空
while(front<rear) {
// 队头结点出队
p=DeQueue(a);
displayNode(p);
// 将队头结点的左右孩子顺次入队
if (p->lchild!=NULL) {EnQueue(a, p->lchild);
}
if (p->rchild!=NULL) {EnQueue(a, p->rchild);
}
}
return 0;
}
总结 :其实不论是哪种遍历形式,咱们最终的目标就是拜访所有的树(子树)的根节点,左孩子,右孩子。那么在拜访的过程中,必定不能一次拜访并打印结束。这个时候就须要栈来暂存咱们曾经拜访过的元素。在须要的时候将其打印进去即可(咱们以左孩子节点为基准,先序遍历是在拜访左孩子节点之前打印节点,中序遍历是在左孩子节点压栈之后打印节点,后序遍历是在拜访完左右孩子节点之后打印节点)。
文中代码均已测试,有任何意见或者倡议均可分割我。欢送学习交换!
如果感觉写的不错,请点个赞再走,谢谢!
如遇到排版错乱的问题,能够通过以下链接拜访我的 CSDN。
**CSDN:[CSDN 搜寻“嵌入式与 Linux 那些事”]