IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 二叉树的非递归遍历 -> 正文阅读

[数据结构与算法]二叉树的非递归遍历

第五章 二叉树非递归遍历

先序遍历
先遍历根节点其次左子树和右子树
中序遍历
先遍历左子树其次根节点最后右子树
后序遍历
先左子树再右子树最后根节点

还是上个博客的图
在这里插入图片描述
先序遍历结果
1 2 4 6 3 5 (根左右)
1是根 2 4 6 是左子树 3 5 是右子树
中序遍历结果
2 6 4 1 3 5 (左根右)
2 6 4 是左子树 1 是根 3 5 是右子树
后序遍历结果
6 4 2 5 3 1 (左右根)
6 4 2 是左子树 5 3 是右子树 1 是根
今天用栈来实现非递归遍历
非递归VS递归
递归一般比较好像容易实现
但是占用空间资源比较多,递归的层次越多,资源占用越大。

非递归就比较难实现,同时还要依托栈来实现。但空间利用高一点。运行时间也会相较递归短很多。

先序遍历
根左右
先访问根节点,同时压栈。纵深左子树(先访问后压栈),当左子树空了,退栈纵深右子树(先访问后压栈)。直至没有节点同时栈空。

//先序遍历(非递归)
void PreOrder2(BiTree T){
	Stack S=(Stack)malloc(sizeof(struct stack));
	Initstack(S);//初始化栈
	BiTree p=T;//指向树的根节点
	while(p||!isEmpty(S)){//栈不空或p不空时循环
		if(p){
			printf("%c  ",p->data);//访问节点
			push(S,p);//入栈
			p=p->lchild;//左子树不空的话,纵深左子树
		}
		else{//出栈,转向右子树
			pop(S,p);
			p=p->rchild;
		}
	}
	free(S);
}

中序遍历
左根右
第一步,纵深左子树,同时压栈。直至左孩子为空了,说明这是可以访问的节点了。
第二步,退栈并访问,检查是否有右孩子。若右孩子为空,继续执行第二步。若存在右孩子,转向右子树执行第一步。

//中序遍历(非递归)
void InOrder2(BiTree T){
	Stack S=(Stack)malloc(sizeof(struct stack));
	Initstack(S);//初始化栈
	BiTree p=T;//指向树的根节点
	while(p||!isEmpty(S)){//栈不空或p不空时循环
		if(p){//压栈,纵深左子树
			push(S,p);
			p=p->lchild;
		}
		else{//退栈,访问,检查右子树
			pop(S,p);
			printf("%c  ",p->data); 
			p=p->rchild;
		}
	}
	free(S); 
}

后序遍历
左右根
第一步,沿着根的左孩子依次入栈,直至左孩子为空。
第二步,读栈顶元素,若其右孩子不空且被未被访问过,转向右子树执行第一步。否则,出栈并访问。

//后序遍历(非递归) 
void PostOrder2(BiTree T){
	Stack S=(Stack)malloc(sizeof(struct stack));
	Initstack(S);//初始化栈
	BiTree p=T;//指向树的根节点,充当遍历指针
	BiTree r=NULL;//r指向上一次被访问的节点,辅助判断
	while(p||!isEmpty(S)){//栈不空或p不空时循环
		if(p){//压栈,纵深左子树
			push(S,p);
			p=p->lchild;
		}
		else{
			GetTop(S,p);//读栈顶元素
			if(p->rchild&&p->rchild!=r)//若栈顶元素有右孩子并且未被访问
				p=p->rchild;//转向右子树
			else{//若栈顶元素没有右孩子或被访问了
				pop(S,p);//退栈
				printf("%c  ",p->data);//访问
				r=p;//r指向上一次被访问的节点,辅助判断
				p=NULL;
			}
		}
		
	}
	free(S); 
}

贴一下完整的代码
包含了栈的定义,出入栈,访问栈顶元素等。
使用了带头结点的链栈。出栈入栈容易实现和理解!之前的稿子也写了几次栈了,这里的代码就不详细注释了。

#include<stdio.h>
#include<stdlib.h>
//定义树节点
typedef struct BiNode{
	char data;//数据域
	//指针域,分别指向左孩子和右孩子
	struct BiNode *lchild,*rchild;
}BiTNode,*BiTree;
//定义栈节点 
typedef struct stack{
	BiTree data;//栈顶数据域是指向树节点的指针;
	struct stack *next;
}stack,*Stack;
//初始化栈
bool Initstack(Stack &S){
	S->next=NULL;
	return true;
}
//入栈
bool push(Stack &S,BiTree p){
	Stack q=(Stack)malloc(sizeof(struct stack));
	q->data=p;
	q->next=S->next;
	S->next=q;
	return true;
}
//出栈
bool pop(Stack &S,BiTree &p){
	if(S->next==NULL) return false;
	Stack q=S->next;
	S->next=q->next;
	p=q->data;
	free(q);
	return true;
}
//访问栈顶元素
bool GetTop(Stack &S,BiTree &p){
	if(S->next==NULL) return false;
	Stack q=S->next;
	p=q->data;
	return true;
}
//判断是否为空栈
bool isEmpty(Stack S){
	if(S->next==NULL) return true;
	else return false;
}
//创建一棵树,先序创建
void CreateTree(BiTree &T){
	char ch;//存放输入值
    scanf("%c\n",&ch);
    if(ch=='#')
        T=NULL;
    else
    {
        T=(BiTree)malloc(sizeof(BiNode));
        T->data=ch;
        CreateTree(T->lchild);
        CreateTree(T->rchild);
    }
} 
//先序遍历(递归) 
void PreOrder(BiTree T){
	if(T!=NULL){
		if(T->data!='#')//访问当前节点
			printf("%c  ",T->data);
		PreOrder(T->lchild);//遍历左子树
		PreOrder(T->rchild);//遍历右子树
	}
}
//先序遍历(非递归)
void PreOrder2(BiTree T){
	Stack S=(Stack)malloc(sizeof(struct stack));
	Initstack(S);
	BiTree p=T;
	while(p||!isEmpty(S)){
		if(p){
			printf("%c  ",p->data);
			push(S,p);
			p=p->lchild;
		}
		else{
			pop(S,p);
			p=p->rchild;
		}
	}
	free(S);
}
//中序遍历(递归)
void InOrder(BiTree T){
	if(T!=NULL){
		InOrder(T->lchild);//遍历左子树
		if(T->data!='#')//访问当前节点
			printf("%c  ",T->data);
		InOrder(T->rchild);//遍历右子树
	}
}
//中序遍历(非递归)
void InOrder2(BiTree T){
	Stack S=(Stack)malloc(sizeof(struct stack));
	Initstack(S);
	BiTree p=T;
	while(p||!isEmpty(S)){
		if(p){
			push(S,p);
			p=p->lchild;
		}
		else{
			pop(S,p);
			printf("%c  ",p->data); 
			p=p->rchild;
		}
	}
	free(S); 
}
//后序遍历
void PostOrder(BiTree T){
	if(T!=NULL){
		PostOrder(T->lchild);//遍历左子树
		PostOrder(T->rchild);//遍历右子树
		if(T->data!='#')//访问当前节点
			printf("%c  ",T->data);
	}
}
//后序遍历(非递归) 
void PostOrder2(BiTree T){
	Stack S=(Stack)malloc(sizeof(struct stack));
	Initstack(S);
	BiTree p=T;
	BiTree r=NULL;
	while(p||!isEmpty(S)){
		if(p){
			push(S,p);
			p=p->lchild;
		}
		else{
			GetTop(S,p);
			if(p->rchild&&p->rchild!=r)
				p=p->rchild;
			else{
				pop(S,p);
				printf("%c  ",p->data);
				r=p;
				p=NULL;
			}
		}
		
	}
	free(S); 
}
int main(){
	BiTree T;
	CreateTree(T);
	printf("先序遍历:      "); 
	PreOrder(T);
	printf("\n中序遍历:      "); 
	InOrder(T);
	printf("\n后序遍历:      "); 
	PostOrder(T);
	printf("\n非递归先序遍历:");
	PreOrder2(T);
	printf("\n非递归中序遍历:"); 
	InOrder2(T);
	printf("\n非递归后序遍历:"); 
	PostOrder2(T);
	return 0;
} 

结果展示
在这里插入图片描述

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-05-13 11:54:55  更:2022-05-13 11:56:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 4:41:10-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码