@[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 intint 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//初始化队头和队尾指针开始时都为0int 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那些事”]