C语言-数据结构-二叉树的递归遍历和非递归遍历
看了大量网络相关的理论和程序,多数的C++ 写的,这里使用devC++
编程语言 C语言; 整合王道考研答案和理论, 还有小甲鱼的数据结构, 郝斌的数据结构,各有特点吧
最值得研究的还是后序遍历的非递归算法, 当时想了使用flag, 想到了多用一个栈, 想到了很多种方式,最后都以失败告终,经过网络查找,
感谢 https://www.cnblogs.com/rain-lei/p/3705680.html
这里使用的一个栈每个结点两次入栈,解决了后序遍历与父结点遍历的冲突,相信只有仔细思考过这个问题的朋友才会明白多有意思.
话不多说,直接上代码, 复制粘贴可用.
#include "stdio.h"
#include "stdlib.h"
#include "malloc.h"
#include "string.h"
#include "stdbool.h"/* 变量声明区 */
typedef char elemType; /* 结构体声明 */
typedef struct BitTree{ //树elemType data;struct BitTree *lChild, *rChild;int lTag, rTag;
}*PBitTree, BitTreeN; #define STACK_MAX_SIZE 50
typedef struct Stack{ //栈PBitTree data[STACK_MAX_SIZE];int top;
}Stack, *PStack;
/*注意 top=-1为空 top=max为满
*/ #define QUEUE_MAX_SIZE 50
typedef struct Queue{ //队列 PBitTree data[QUEUE_MAX_SIZE]; int rear,front;
}Queue, *PQueue;
/*注意 rear=front为空 (rear+1)%max = front为满
*//* 函数声明区 */
//common bit treevoid CreateBieTr_Pre(PBitTree*T); /* 动态创建先序二叉树 */
/*使用递归方式,判断的输入的字符是否为' ',然后递归&(*T)->lChild,在rChild*/ PBitTree CreateBT(void); //静态建立二叉树
/*创建结点,在将结点相互关联到一起*/ PBitTree InitBitTree_Pre(elemType pre[], int pre0, int pren, elemType in[], int in0, int inn);
/*将先序和中序合并成先序, 使用遍历算法,
先找到先序的第一个结点,用第一个查找中序的位置,确定好中序中间位置到两端的长度,
作为递归确定左右孩子的参数, 当找不到中点表示为NULL*/ //递归遍历
void visit(elemType ch, int level);
void PreOrder_Recursion(PBitTree T, int level); /* 先序遍历二叉树 */
void MedOrder_Recursion(PBitTree T, int level); /* 中序遍历二叉树 */
void PostOrder_Recursion(PBitTree T, int level);/* 后序遍历二叉树 *///非递归遍历
void InOrder2(PBitTree T); //使用栈 中序遍历 非递归
void PreOrder2(PBitTree T); //使用栈 先序遍历 非递归
void PostOrder2(PBitTree T); //使用栈 后序遍历 非递归
void PostOrder2_2(PBitTree T); //双次入栈 后序遍历 非递归
void LevelOrder_from_H_to_L_L_to_R(PBitTree T); //使用队列 层次遍历 非递归 void main()
{int i; PBitTree T = NULL;char val;int int_val;int level=1; //初始化二叉树1
// printf("下面进行动态先序生成二叉树,使用空格作为NULL标记:\n");
// CreateBieTr_Pre( &T );//初始化二叉树2
// T =CreateBT();//初始化二叉树3 elemType pre[] = "ABCDEF"; elemType in[] = "CBDAEF"; T = InitBitTree_Pre(pre, 0, 6, in, 0, 6); printf("普通二叉树的前序遍历\n"); PreOrder_Recursion(T, level); printf("普通二叉树的中序遍历\n"); MedOrder_Recursion(T, level); printf("普通二叉树的后序遍历\n"); PostOrder_Recursion(T, level); InOrder2(T); //中序非递归二叉树的遍历 PreOrder2(T);PostOrder2(T); PostOrder2_2(T);LevelOrder_from_H_to_L_L_to_R(T);return;
}/* 函数实现区 */ //---------------------------------------------------------------//动态 先序创建树
void CreateBieTr_Pre(PBitTree*T)
{elemType ch;scanf("%c",&ch);if(' ' == ch) { *T = NULL; return; }else{(*T) = (PBitTree)malloc(sizeof(BitTreeN));(*T)->data = ch;CreateBieTr_Pre(&(*T)->lChild);CreateBieTr_Pre(&(*T)->rChild);return;}
}/* 静态建立二叉树 */
PBitTree CreateBT(void)
{ PBitTree PA = (PBitTree)malloc(sizeof(BitTreeN)); PA->data = 'A';PBitTree PB = (PBitTree)malloc(sizeof(BitTreeN)); PB->data = 'B';PBitTree PC = (PBitTree)malloc(sizeof(BitTreeN)); PC->data = 'C';PBitTree PD = (PBitTree)malloc(sizeof(BitTreeN)); PD->data = 'D'; PBitTree PE = (PBitTree)malloc(sizeof(BitTreeN)); PE->data = 'E'; PBitTree PF = (PBitTree)malloc(sizeof(BitTreeN)); PF->data = 'F'; PA->lChild = PB; PA->rChild = PE;PB->lChild = PC; PB->rChild = PD; PE->lChild = NULL; PE->rChild = PF; PC->lChild = PC->rChild = NULL;PD->lChild = PD->rChild = NULL;PF->lChild = PF->rChild = NULL;return PA;
}
/* 给出先序和中序,求先序的二叉链表 Pre是先序 给出数组中0-n表示的位置 In是中序 */
PBitTree InitBitTree_Pre(elemType pre[], int pre0, int pren, elemType in[], int in0, int inn)
{
// if()return; PBitTree Root = (PBitTree)malloc(sizeof(BitTreeN));Root->data = pre[pre0];int i;int lLen,rLen; for(i=in0; in[i] != Root->data; i++); //找到中间值lLen = i-in0; //左子树长度 rLen = inn-i; //右子树长度 printf("in0=%d, inn=%d pr0=%d, pren=%d data %c zuo %d zyo %d \n",pre0, pren, in0, inn, Root->data,lLen,rLen); if(lLen){Root->lChild = InitBitTree_Pre(pre, pre0+1, pre0+lLen, in, in0, in0+lLen-1);//建立左子树 }else{Root->lChild = NULL;}if(rLen){Root->rChild = InitBitTree_Pre(pre, pren-rLen+1, pren, in, inn-rLen+1, inn);//建立左子树 }else{Root->rChild = NULL;} return Root;
}//-----以下为common Bit Tree的三种遍历----------------------------------------------------------------------------// void visit(elemType ch, int level)
{printf("树 %c 位于第 %d 层\n", ch, level);return;
} /* 先序遍历二叉树 */
void PreOrder_Recursion(PBitTree T, int level)
{if(NULL != T) //递归缺点 浪费空间,运行时间长 {visit(T->data, level);//访问根节点 if(NULL != T->lChild) PreOrder_Recursion(T->lChild, level+1); //先左子树 if(NULL != T->rChild) PreOrder_Recursion(T->rChild, level+1); //后右子树 } return;
} /* 中序遍历二叉树 */
void MedOrder_Recursion(PBitTree T, int level)
{if(NULL != T) //递归缺点 浪费空间,运行时间长 {if(NULL != T->lChild) MedOrder_Recursion(T->lChild, level+1); //先左子树visit(T->data, level);//访问根节点 if(NULL != T->rChild) MedOrder_Recursion(T->rChild, level+1); //后右子树 }
} /* 后序遍历二叉树 */
void PostOrder_Recursion(PBitTree T, int level)
{if(NULL != T) //递归缺点 浪费空间,运行时间长 {if(NULL != T->lChild) PostOrder_Recursion(T->lChild, level+1); //先左子树 if(NULL != T->rChild) PostOrder_Recursion(T->rChild, level+1); //后右子树 visit(T->data, level);//访问根节点 }
}/* 普通二叉树 非递归 中序遍历 */
void InOrder2(PBitTree T)
{ printf("普通二叉树 非递归 中序遍历:\n");PBitTree P = T; //P是遍历指针 PStack S = (PStack)malloc(sizeof(Stack)); S->top = -1; //初始化栈while( P || ( S->top != -1 ) ) //栈不空 P不空 {if( P ){if(S->top != STACK_MAX_SIZE) //栈不满 {S->data[ ++S->top ] = P; P = P->lChild;}}else{if(S->top != -1) //栈不空{P = S->data[ S->top--]; //出栈 printf("%c ",P->data);P = P->rChild;}}}printf("\n");return;
}/* 普通二叉树 非递归 先序遍历 */
void PreOrder2(PBitTree T)
{printf("普通二叉树 非递归 先序遍历:\n");PBitTree P = T; //P是遍历指针PStack S = (PStack)malloc(sizeof(Stack)); S->top = -1; //初始化栈while( P || ( S->top != -1 ) ){if( P ) //遍历左孩子 {printf("%c ",P->data);S->data[++S->top] = P; //入栈P = P->lChild; } //出来是遇到了空 else{P = S->data[S->top--]; //出栈P = P->rChild; }}printf("\n");return;
} /* 普通二叉树 非递归 后序遍历 */
void PostOrder2(PBitTree T)
//重点在于判定指针是从左子树返回的还是右子树, 若右子树则该结点已经到顶了
{printf("普通二叉树 非递归 后序遍历:\n");PBitTree P = T; //P是遍历指针PBitTree R = NULL; //辅助指针 PStack S = (PStack)malloc(sizeof(Stack)); S->top = -1; //初始化栈while( P || (S->top!=-1) ){if(P) // 一直遍历到最左下面 {S->data[++S->top] = P;P = P->lChild; }else {P = S->data[S->top]; if(P->rChild != NULL && P->rChild!=R ) //如果右子树存在且未被访问过 {P = P->rChild;S->data[++S->top] = P;P = P->lChild;}else{P = S->data[S->top--];printf("%c ",P->data);R = P;P = NULL;}}}printf("\n");return;
}void PostOrder2_2(PBitTree T)
{if(T == NULL){return;}printf("通普二叉树 非递归 后序遍历\n"); PBitTree P = T; PStack S = (PStack)malloc(sizeof(Stack));S->top = -1;S->data[++S->top] = T; //树根节点 双次入栈 S->data[++S->top] = T;while(S->top != -1){P = S->data[S->top--]; if(S->top!=-1 && P==S->data[S->top])//栈不为空,且 曾经的栈 前两层相同 {//栈顶的左右孩子如果还有,则下次循环 曾经的栈 前两层相同 继续寻找最左边//结点的左右孩子,然后继续寻找直到找到左右孩子都没有了,就开始打印/*对于每个结点都压栈两次,在循环中,每次弹出的一个结点赋给P,如果P仍然等于栈的头结点,说明P的孩子们还有没被操作过的,应该把他的孩子们入栈,否则,访问P也就是说, 第一次弹出, 将P的孩子压栈, 第二次弹出, 访问P */ if(P->rChild != NULL){S->data[++S->top] = P->rChild;S->data[++S->top] = P->rChild;}if(P->lChild != NULL){S->data[++S->top] = P->lChild;S->data[++S->top] = P->lChild;}}else //曾经的栈 前两层不相同 {printf("%c ",P->data); }}printf("\n");return;
} /* 普通二叉树的遍历 从上到下,从左到右 */
void LevelOrder_from_H_to_L_L_to_R(PBitTree T)
{if(!T)return; //防止空树 printf("普通二叉树的遍历 从上到下,从左到右\n");PBitTree P = T; PQueue Q = (PQueue)malloc(sizeof(Queue)); //新建队列 Q->front = Q->rear =0;Q->data[Q->rear] = P; Q->rear = (Q->rear+1)%QUEUE_MAX_SIZE; //根结点入队while( Q->rear != Q->front ){P = Q->data[Q->front]; Q->front = (Q->front+1)%QUEUE_MAX_SIZE; //出队printf("%c ",P->data);//注意 如果需要层次遍历 从下到上,从右到左 可以在这里入栈,到最后在出栈if(P->lChild) {Q->data[Q->rear] = P->lChild; //入队 Q->rear = (Q->rear+1)%QUEUE_MAX_SIZE; } if(P->rChild) {Q->data[Q->rear] = P->rChild;Q->rear = (Q->rear+1)%QUEUE_MAX_SIZE;}} printf("\n");return;
}
C语言-数据结构-二叉树的递归遍历和非递归遍历相关推荐
- 【数据结构】--- 二叉树的递归遍历和非递归遍历【C语言实现】
目录 1. 创建一颗二叉树 2.递归前序遍历二叉树 3.递归中序遍历二叉树 4.递归后序遍历二叉树 5. 测试递归打印二叉树代码 6. 非-递归前序遍历二叉树 7. 非-递归实现中序遍历二叉树 8. ...
- 信号放大器数据结构_[11/11]数据结构 二叉树应用(树型信号放大器,file transfer,遍历的非递归实现)...
树型分布网络信号放大器 森林和二叉树的相互转换 并查集 例题:File transfer #include <iostream> using namespace std; //typede ...
- 二叉树前中后序遍历的非递归实现以及层次遍历、zig-zag型遍历详解
前言 二叉树的遍历是一个比较常见的问题,递归实现二叉树的前中后序遍历比较简单,但非递归实现二叉树的前中后序遍历相对有难度.这篇博客将详述如何使用非递归的方式实现二叉树的前中后序遍历,在进行理论描述的同 ...
- 二叉树遍历详解(递归遍历、非递归栈遍历,Morris遍历)
一.前言 <二叉查找树全面详细介绍>中讲解了二叉树操作:搜索(查找).遍历.插入.删除.其中遍历深度优先遍历(DFS)按照实现方法可以分为:递归遍历实现.非递归遍历实现.Morris遍历实 ...
- 二叉树创建,递归遍历,非递归遍历
二叉树 博主是一个大一刚刚放暑假的大学生,大学我们只学习了c语言,现在这么卷只学c语言肯定不够,所以博主打算从零开始恶补c++顺便写文章记录一下,另外博主这个暑假还想记录一些算法基础内容欢迎关注哦.这 ...
- 二叉树中序遍历(递归法和迭代法(非递归法))——C++
声明:本文原题主要来自力扣,记录此博客主要是为自己学习总结,不做任何商业等活动! 二叉树的遍历有前序遍历.中序遍历.后序遍历和层次遍历,其中二叉树基本知识点可以参考博主上篇博客(二叉树基本知识点图文介 ...
- 【二叉树Java】二叉树遍历前序中序后序遍历的非递归写法
本文主要介绍二叉树前序中序后序遍历的非递归写法 在探讨如何写出二叉树的前序中序后序遍历代码之前,我们先来明确一个问题,前序中序后序遍历根据什么区分? 二叉树的前序中序后序遍历,是相较根节点说的.最先遍 ...
- 漫谈二叉树遍历(非递归)
------这篇文章旨在提出一种简单方便,易于理解时空复杂度低且风格统一的二叉树非递归遍历方法. 从二叉树先序遍历开始 二叉树的先序遍历(非递归)相比中后序是最少花哨.最统一的.一般来说先序遍历的代码 ...
- 4.二叉树的先序、中序以及后序遍历的递归写法与非递归写法(LeetCode第94、144、145题)
一.递归法 这次我们要好好谈一谈递归,为什么很多同学看递归算法都是"一看就会,一写就废". 主要是对递归不成体系,没有方法论,每次写递归算法 ,都是靠玄学来写代码,代码能不能编过都 ...
- 遍历二叉树的各种操作(非递归遍历)
先使用先序的方法建立一棵二叉树,然后分别使用递归与非递归的方法实现前序.中序.后序遍历二叉树,并使用了两种方法来进行层次遍历二叉树,一种方法就是使用STL中的queue,另外一种方法就是定义了一个数组 ...
最新文章
- 【读书笔记】代码可为维护性标准(一)
- 用JAVASCRIPT实现静态对象、静态方法和静态属性
- 《Cocos2D权威指南》——3.9 本章小结
- mysql 性能 索引怎么用_MySQL索引使用方法和性能優化
- Matlab:批量文件命名
- 上海技术计算机学校学费多少,上海web前端学校学费一般是多少
- 华为狼性文化遭质疑,那我们当个佛系程序员可好?
- 革新OCR结构化技术应用,揭秘百度中英文OCR结构化模型StrucTexT预训练模型
- 进程间的通信方式有哪些?
- 用scratch实现网上“超人训练”游戏
- C++ 中 _T 含义及用途
- SolidWorks中提高大型装配性能Part4— SolidWorks装配工具
- 一台汽车在新上市之前需要经历多少考验,才有资格驶向我们?
- Raft 共识算法1-Raft基础
- Centos7 安装VLC播放器
- MAC vscode 编译多个文件失败(已解决)
- 浅谈游戏《Cuphead茶杯头》
- CAD2018安装计算机黑屏,简单几步解决cad2019在win10上打不开的问题
- 关于动漫的HTML网页设计:期末前端web大作业——海贼王基地(6个页面)
- 批量删除Redis数据库中的Key