数据结构与算法学习:二叉树的后序遍历的递归与非递归实现,以及非递归实现中的流程控制的说明。

news2024/11/13 11:21:07

需求二叉树:

采用二叉树后序遍历非递归算法。设置一个指针p初始指向树根,p先入栈,而后使得p指向它的左孩子p->firstchild,重复操作,使得每个左孩子都依次入栈,同时初始化一个Treenode*类型的指针pre,这个指针是后序前驱,这个后序前驱用以区分为已访问过的结点和未访问过的结点。

由于栈顶元素一定是某一子树的根,那么先假设p==S.top()我们把叶子结点等价为左右孩子都为空的子树的根作为分析时的假设,想要访问栈顶元素那么要么右子树为空,要么右子树被访问完为空好办,核心的流程控制就在于右子树访问完这里的问题,根据后续遍历的性质又知道,因为先前设置pre为上一步刚访问过的结点,即后序前驱,如果右子树被访问完那么就意味着p->nextchild==后序前驱,而这个后序前驱就是pre,要是p=p->nextchild,而后右设置pre=p,而p->nextchild==pre...那么就会在pre那里死循环。所以,能让p=p->nextchild;的条件就是(p->nextchild!=NULL&&p->nextchild!=后序前驱)若p->nextchild!=NULL不和后一个条件相与会形成访问某一个结点的右子树的死循环。

后序遍历非递归算法的流程控制较为复杂,以上为流程控制中条件判断的确定方法,下面给出算法流程:

①沿着根的左孩子依次入栈

②直到左孩子为空读栈顶元素若其右孩子不空且未被访问过将右子树转执行①否则栈顶元素出栈并访问。

”tree.hpp":

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdbool.h>
#include <iostream>
#include <stdlib.h>
#include <ctime>
#include <stack>
#include<queue>
using namespace std;


class Treenode
{
	friend class Bitree;
public:
	
	Treenode();
	Treenode(char a);
	//Treenode(char c);
	Treenode& setnode(char a)
	{
		this->val = a;
		return *this;
	}

	void setfirstchild(Treenode* a);
	void setnextchild(Treenode* a);
	void setrtag(bool a);
	void setltag(bool a);
	char getval();
	Treenode& getfirstchild();
	Treenode& getnextchild();

private:
	
	char val;//数据部分
	Treenode* firstchild;
	Treenode *nextchild;//同一化的树的存储
	bool ltag , rtag ;//0表示有左或右孩子,1表示该结点没有左或右孩子,且此链域是线索

};

Treenode& Treenode::getfirstchild()
{
	return *this->firstchild;
}
Treenode& Treenode::getnextchild()
{
	return *this->nextchild;
}
char Treenode::getval()
{
	return this->val;
}
void Treenode::setfirstchild(Treenode* a)
{
	this->firstchild = a;
}
void Treenode::setnextchild(Treenode *a)
{
	this->nextchild = a;
}

void Treenode::setltag(bool a)
{
	this->ltag = a;
}
void Treenode::setrtag(bool a)
{
	this->rtag = a;
}
Treenode::Treenode(char a)
{
	this->val = a;
	if (this->firstchild != NULL)
	{
		delete this->firstchild;
	}
	this->firstchild = NULL;
	if (this->nextchild != NULL)
	{
		delete this->nextchild;
	}
	this->nextchild = NULL;
	this->ltag = false;
	this->rtag = false;
}
Treenode::Treenode()
{
	this->val = '#';
	if (this->firstchild != NULL)
	{
		delete this->firstchild;
	}
	this->firstchild = NULL;
	if (this->nextchild != NULL)
	{
		delete this->nextchild;
	}
	this->nextchild = NULL;
	this->ltag = false;
	this->rtag = false;
}



class Bitree
{
	friend class Treenode;
public:
	Bitree()
	{
		this->root = new(class Treenode);
	}
	Treenode& setroot(Treenode* a);

	void visit(Treenode* a);
	Treenode* getroot()
	{
		return this->root;
	}
	

	
	int getcount()
	{
		return this->count;
	}


	void postorder_traversal(Treenode* t);//后序遍历
	void postorder_nonrecursion_traversal();//后序非递归算法
private:
	Treenode* root;
	int count = 0;
};

void Bitree::postorder_traversal(Treenode* t)//后序遍历
{
	if (t == NULL)
		return;
	postorder_traversal(t->firstchild);
	postorder_traversal(t->nextchild);
	this->visit(t);
}
void Bitree::postorder_nonrecursion_traversal()//后序非递归算法
{
	stack<Treenode*> S;
	Treenode* p = this->root;
	Treenode* pre = NULL;//最近访问过的结点,后序前驱
	while (p || !S.empty())
	{
		if (p)
		{
			S.push(p);
			p = p->firstchild;
		}
		else 
		{
			p = S.top();//只有当前p为空才使它指向栈顶元素
			if (p->nextchild && p->nextchild != pre)//为什么要设置一个最近访问过的结点r?
				p = p->nextchild;//上面的p->nextchile!=r用于防环
			else
			{
				p = S.top();
				S.pop();
				this->visit(p);
				pre= p;
				p = NULL;//这一点不容易想到,比较容易直接给它设为指向栈顶元素,还容易不断地重复逻辑判断,流程控制较复杂

			}

		}
	}

}


Treenode& Bitree::setroot(Treenode* a)
{
	
	this->root = a;
	return *this->root;
}
void Bitree::visit(Treenode*a)
{
	if (a->val != '#')
	{
		cout << a->val;
		this->count++;
	}

}


	

"源文件.cpp":

#define _CRT_SECURE_NO_WARNINGS 1

#include	"tree.hpp"



int main()
{
	

	//先创建空树再遍历赋值
	Bitree T;
	Treenode m1('A');
	Treenode m2('B');
	Treenode m3('C');
	Treenode m4('D');
	Treenode m5('E');
	Treenode m6('F');
	Treenode m7('G');

	T.setroot(&m1);
	m1.setfirstchild(&m2);
	m1.setnextchild(&m3);

	m2.setfirstchild(&m4); 
	m2.setnextchild(&m5);
	m3.setfirstchild(&m6);
	m3.setrtag(true) ;
	m4.setnextchild(&m7);
	//cout << m4.getnextchild().getval();
	m4.setrtag(true);
	m5.setrtag(true);
	m5.setrtag(true);
	m6.setrtag(true);
	m6.setrtag(true);
	m7.setrtag(true);
	m7.setrtag(true) ;


	cout << "后序遍历序列为:";
	T.postorder_nonrecursion_traversal();
	cout << endl;
	cout << "树中结点数为:" << T.getcount() << endl;
	
	



	system("pause");
	return 0;
}

代码测试:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/459562.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GPT:你知道这五年我怎么过的么?

时间轴 GPT 首先最初版的GPT&#xff0c;来源于论文Improving Language Understanding by Generative Pre-Training&#xff08;翻译过来就是&#xff1a;使用通用的预训练来提升语言的理解能力&#xff09;。GPT这个名字其实并没有在论文中提到过&#xff0c;后人将论文名最后…

【软件测试】知识图

文章目录 第1章 软件测试概述1.1 软件、软件危机和软件工程1.1.1 基本概念1.1.2 软件工程的目标及其一般开发过程1.1.3 软件过程模型 1.2 软件缺陷与软件故障1.2.1 基本概念1.2.2 典型案例 1.3 软件测试的概念1.3.1 软件测试的定义1.3.2 软件测试的目的&#xff1a;保证软件产品…

备忘录设计模式解读

目录 问题引进 游戏角色状态恢复问题 传统方案解决游戏角色恢复 传统的方式的问题分析 备忘录模式基本介绍 基本介绍 备忘录模式的原理类图 对原理类图的说明 游戏角色恢复状态实例 应用实例要求 思路分析和图解(类图) 代码实战 备忘录模式的注意事项和细节 问题引…

了解网络攻击:类型、策略和技术

近年来&#xff0c;网络攻击变得越来越普遍&#xff0c;个人和企业都成为各种网络威胁的受害者。了解不同类型的网络攻击&#xff0c;以及网络罪犯使用的策略和技术&#xff0c;对于保护您的个人和企业数据免受这些威胁至关重要。 有几种不同类型的网络攻击&#xff0c;每种都…

Linux 查看进程和线程CPU和内存占用情况

文章目录 Linux 查看进程有哪些线程Linux 查看程序内存占用情况 top和free等命令Linux 查看进程、线程数量 Linux 查看进程有哪些线程 linux 下查看进程内的线程有哪些 首先通过进程名称&#xff0c;假设为SensorDev 找到pid号。 ps -p {pid} -T 可以得到该进程里面运行的各…

Mapbox多边形光效晕影特效的实现

相信很多大屏需要展示行政区的发光效果,像下图这样的: 这相比普通的多边形样式,边界有了渐变发光的效果,那么这篇章交给大家如何实现这样一个效果,让你的行政区,地块之类的多边形要素展示成发光的效果。 我们不依赖底层的webgl技术,也不用涉及到什么着色器的概念,我…

【LeetCode: 1143. 最长公共子序列 | 暴力递归=>记忆化搜索=>动态规划】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

Springcloud连接nacos集群,nacos地址配置为nginx,报错:requst nacos server failed

先说下版本&#xff1a; Spring cloud&#xff1a; Hoxton.SR12 spring.cloud.alibaba&#xff1a; 2.2.9.RELEASE spring.boot&#xff1a; 2.3.12.RELEASE Linux Centos7 nacos-server&#xff1a;2.1.0 nginx&#xff1a; 1.20.2 环境说明&#xff1a; nacos正常搭建三个集…

Burpsuite双层代理以及抓https与app包设置

Burp Suite是一款用于Web应用程序安全测试的集成式平台。它由PortSwigger Ltd.开发&#xff0c;是一个功能强大的工具&#xff0c;用于发现Web应用程序的漏洞和安全问题&#xff0c;例如跨站点脚本&#xff08;XSS&#xff09;、SQL注入、会话劫持等。它包括多个模块&#xff0…

酒厂酒业IP网络广播系统建设方案-基于局域网的新一代交互智慧酒厂酒业IP广播设计指南

酒厂酒业IP网络广播系统建设方案-基于局域网的新一代交互智酒业酒厂IP广播系统设计指南 由北京海特伟业任洪卓发布于2023年4月25日 一、酒厂酒业IP网络广播系统建设需求 随着中国经济的快速稳步发展&#xff0c;中国白酒行业也迎来了黄金时期&#xff0c;产品规模、销售业绩等…

NLP 与 Python:构建知识图谱实战案例

概括 积累了一两周&#xff0c;好久没做笔记了&#xff0c;今天&#xff0c;我将展示在之前两周的实战经验&#xff1a;如何使用 Python 和自然语言处理构建知识图谱。 网络图是一种数学结构&#xff0c;用于表示点之间的关系&#xff0c;可通过无向/有向图结构进行可视化展示…

【2023团体程序设计天梯赛CCCC】GPLT2023,L1~L2部分(PTA,L1-089~L1-096,L2-045~L2-048)题解代码复盘

文章目录 概要L1-089 最好的文档 5L1-090 什么是机器学习 5L1-091 程序员买包子 10L1-092 进化论 10L1-093 猜帽子游戏 15L1-094 剪切粘贴 15L1-095 分寝室 20L1-096 谁管谁叫爹 20L2-045 堆宝塔 25L2-046 天梯赛的赛场安排L2-047 锦标赛 25L2-048 寻宝图 25L3-035 完美树&…

GIII EDI 需求分析

G-III成衣集团是一家美国服装公司&#xff0c;拥有30多个授权和自有品牌如&#xff1a;Calvin Klein、Tommy Hilfiger、Guess以及Levi’s等&#xff0c;在全球拥有众多的零售合作伙伴和销售渠道&#xff0c;并致力于提供时尚、高质量和价格合理的服装产品。 GIII EDI 需求 传…

版本控制工具之Git基本操作

Git 相对较新的版本控制工具&#xff0c;特点为分布式。 每一台客户端都具有完整的版本备份&#xff0c;所有的版本提交都不需要依赖中心服务器。只有在多人协同时&#xff0c;服务器会处理并发情况。 一、Git 环境安装 &#x1f449;链接&#xff1a;https://blog.csdn.net/w…

「速通Shell」初次走近Shell,Shell是什么?

目录 初次走进ShellShell是什么Shell工作原理 Shell分类Shell的优势 第一个Shell脚本Hello WorldShell执行方式绝对路径执行相对路径执行脚本命令执行系统命令执行 总结 对于开发者来说&#xff0c;除了掌握Java、C/C等主要编程语言外&#xff0c;还需要掌握支撑性的工具语言和…

Vagrant 安装

系列文章目录 文章目录 系列文章目录前言一、安装地址二、安装步骤注意事项三、常用命令四、问题总结 前言 例如&#xff1a;随着人工智能的不断发展&#xff0c;机器学习这门技术也越来越重要&#xff0c;很多人都开启了学习机器学习&#xff0c;本文就介绍了机器学习的基础内…

机器人方向的人工智能工具是助手还是平替

本文内容严格按创作模板发布&#xff1a; 近日育碧开发了人工智能工具 Ghostwriter&#xff0c;可以一键生成游戏NPC对话。不少游戏开发者担心AI写手工具的出现会让自己“饭碗”不保&#xff0c;但Swanson表示这个工具只是为了提供第一稿的 barks来减少对话生成工作的繁琐度。…

Linux网络编程TCP粘包问题解析及解决方法

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、一次发送多个数据实验二、导致问题的原因三、解决方案之一&#xff1a;延时发送四、知识点补充发送缓冲区和接收缓冲区五、解决方法总结 前言 本篇文章将引…

Java-JDK动态代理(AOP)使用及实现原理分析

Java-JDK动态代理&#xff08;AOP&#xff09;使用及实现原理分析 第一章:代理的介绍 介绍:我们需要掌握的程度 动态代理(理解) 基于反射机制 掌握的程度: 1.什么是动态代理? 2.动态代理能够做什么? 后面我们在用Spirng和Mybatis的时候,要理解怎么使用的. 1.什么是代理? 代理…

PID循迹机器人及整定

如何对线路循迹机器人进行编程 如何对线路循迹机器人进行编程 (robotresearchlab.com)PID调谐文章&#xff1a;http://robotresearchlab.com/2019/02/16/pid-line-follower-tuning/ 介绍人们选择对循迹机器人进行线路编程的两种主要方式&#xff0c;并比较两者。将详细比较“…