数据结构与算法-树和森林

news2025/7/27 23:10:10

在这里插入图片描述
🌞 “永远面朝阳光,阴影被甩在身后!”

树和森林

  • 🎈1.线索二叉树
  • 🎈2.树和森林
    • 🔭2.1树的存储结构
    • 🔭2.2双亲表示法
    • 🔭2.3孩子链表表示法
      • 📝2.3.1孩子链表表示法的实现
      • 📝2.3.2查找结点x在树中的下标
      • 📝2.3.3创建k个结点的树
      • 📝2.3.4计算结点x的度数
      • 📝2.3.5插入结点u的孩子v
    • 🔭2.4孩子兄弟表示法
      • 📖2.4.1例题
  • 🎈3.二叉树的小练笔

🎈1.线索二叉树

遍历二叉树是以一定的规则将二叉树中的结点排列成一个线性序列的过程。与线性表相比,二叉树的遍历存在以下问题:
(1).遍历算法复杂而费时
(2).为检索或查找二叉树中某结点在某种遍历下的前驱结点和后继结点,必须从根结点开始遍历,直到找到该结点的前驱结点和后继结点。
为此,我们引入线索二叉树的概念,线索二叉树可以简化遍历算法,提高遍历效率。

为了避免混淆,重新定义结点的结构,在结点的存储结构上增加标志位ltagrtag来区分这两种情况。
在这里插入图片描述

其中,ltag0时,lchild域指向结点的左孩子,ltag1时,lchild指向结点的前驱;rtag0时,rchild域指向结点的右孩子,rtag1时,rchild域指向结点的后继。
在这里插入图片描述

🎈2.树和森林

🔭2.1树的存储结构

🔎树的存储结构常分为:

  1. 双亲表示法
  2. 孩子链表表示法
  3. 孩子兄弟表示法

🔭2.2双亲表示法

由树的定义知,除根结点之外,树中的每个结点都有唯一的双亲。根据这一特点,双亲表示法可以用一组连续的存储空间存放结点信息,即用一维数组来存储树中的各个结点。数据元素为结构体类型,其中包括结点本身信息以及指示其双亲结点在数组中的位置信息。

🔎双亲表示法在类型定义如下:

#define MaxSize 100
typedef int ElemType;
typedef struct PtNode
{
	ElemType data;
	int parent;
}PtNode;
typedef struct
{
	PtNode nodes[MaxSize];
	int r, n;
}PTree;

在这里插入图片描述

🔭2.3孩子链表表示法

孩子链表表示法存储单元的主体是一个与结点个数一样大小的一维数组,数组的每一个元素由两个域组成,一个域用来存放结点自身的数据信息,另一个用来存放指针,该指针指向由该结点孩子组成的单链表的表头。单链表的结点结构也有两个域组成,一个存放孩子结点在一维数组中的下标,另一个是指针域,指向下一个孩子。
在这里插入图片描述

📝2.3.1孩子链表表示法的实现

#define MaxSize 100
typedef struct CtNode
{
	int child;
	CtNode* next;//指向下一个孩子结点
}CtNode;
typedef struct
{
	char data;
	int parent;
	CtNode* firstchild;//指向第一个孩子
	int r, n;
}CtBox;
class CTree
{
private:
	CtBox nodes[MaxSize];
	int r, n;
public:
	int LocateNode(char x);//查找结点x在树中的下标
	void CreateCtree(int k);//创建k个结点的树
	int DegreeNode(char x);//计算结点x的度数
	void InsertNode(char u, char v);//插入结点u的孩子v
};

📝2.3.2查找结点x在树中的下标

在这里插入图片描述

int CTree::LocateNode(char x)
{
	for (int i = 0; i < n; i++)
	{
		if (x == nodes[i].data)
			return i;
		else
			return -1;
	}
}

📝2.3.3创建k个结点的树

void CTree::CreateCtree(int k)
{
	int i;
	for (i = 0; i < k; i++)
	{
		cin >> nodes[i].data;
		nodes[i].firstchild = NULL;
	}
	n = k;
	r = 0;
	char u, v;
	int h, t;
	CtNode* p;
	for (i = 0; i < k; i++)
	{
		cin >> u;
		h = LocateNode(u);
		cin >> v;
		while (v != '.')
		{
			t = LocateNode(v);
			p = new CtNode;
			p->child = t;
			p->next = nodes[h].firstchild;
			nodes[h].firstchild = p;
			cin >> v;
		}
	}
}

📝2.3.4计算结点x的度数

int CTree::DegreeNode(char x)
{
	int h = LocateNode(x);
	CtNode* p = nodes[h].firstchild;
	int count = 0;
	while (p)
	{
		count++;
		p = p->next;
	}
	return count;
}

📝2.3.5插入结点u的孩子v

void CTree::InsertNode(char u, char v)
{
	int h = LocateNode(u);
	if (h == -1)
		return;
	nodes[n].data = v;
	nodes[n].firstchild = NULL;
	n++;
	CtNode* p = new CtNode;
	int t = LocateNode(v);
	p->child = t;
	p->next = nodes[h].firstchild;
	nodes[h].firstchild = p;
}

🔭2.4孩子兄弟表示法

孩子兄弟表示法又称二叉链表表示法或二叉树表示法。即以二叉链表作为树的存储结构,链表中结点的两个链域分别指向结点的第一个孩子结点和下一个兄弟结点。
在这里插入图片描述

typedef char ElemType;
typedef struct CSNode
{
	ElemType data;
	CSNode* firstchild;
	CSNode* nextsibling;
}CSNode;

📖2.4.1例题

已知一棵树以孩子兄弟表示法为其存储结构,设计一个递归算法计算树的高度。

int CSTreeHeight(CSNode* t)
{
	int m, max = 0;
	CSNode* p;
	if (t == NULL)
		return 0;
	else
	{
		p = t->firstchild;
		while (p)
		{
			m = CSTreeHeight(p);
			if (max < m)
				max = m;
			p = p->nextsibling;
		}
		return 1 + max;
	}
}

🎈3.二叉树的小练笔

题目:递归创建一棵二叉树,中序输出二叉树序列,计算树的深度,计算度数为1的结点数,计算度数为1的结点数以及判断两棵树是否相似。

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
typedef struct BitNode
{
	char data;
	BitNode* lchild;
	BitNode* rchild;
}BitNode;
class BiTree
{
private:
	BitNode* bt;
	void Rcreate(BitNode*& t);//递归创建一棵二叉树
	void InTraverse(BitNode* t);//中序输出二叉树序列
	int BTNodeDepth(BitNode* t);//计算树的深度
	int CountNode1(BitNode* t);//计算度数为1的结点数
	int CountNode2(BitNode* t);//计算度数为1的结点数
public:
	BiTree()
	{
		bt = NULL;
	}
	void RecreateBiTree();
	void InTraverseBiTree();
	int BTNodeDepthBiTree();
	int CountNode1BiTree();
	int CountNode2BiTree();
	int Alike(BitNode* s, BitNode* t);//判断两棵树是否相似
	BitNode*& GetRoot()
	{
		return bt;
	}
};
void BiTree::Rcreate(BitNode*& t)
{
	char ch;
	cin >> ch;
	if (ch == '*')
	{
		t = NULL;
	}
	else
	{
		t = new BitNode;//申请空间
		t->data = ch;
		Rcreate(t->lchild);//递归创建左子树
		Rcreate(t->rchild);//递归创建右子树
	}
}
void BiTree::RecreateBiTree()
{
	BitNode* t;
	Rcreate(t);
	bt = t;
}
void BiTree::InTraverse(BitNode* t)
{
	if (t)
	{
		InTraverse(t->lchild);
		cout << t->data << " ";
		InTraverse(t->rchild);
	}
}
void BiTree::InTraverseBiTree()
{
	BitNode* p = bt;
	InTraverse(p);
}
int BiTree::BTNodeDepth(BitNode* t)
{
	if (t == NULL)
	{
		return 0;
	}
	else
	{
		int m = 1 + BTNodeDepth(t->lchild);
		int n = 1 + BTNodeDepth(t->rchild);
		if (m >= n)
			return m;
		else
			return n;
	}
}
int BiTree::BTNodeDepthBiTree()
{
	BitNode* p = bt;
	cout<< BTNodeDepth(p);
	return 1;
}
int BiTree::CountNode1(BitNode* t)
{
	if (t == NULL)
		return 0;
	if (t->lchild == NULL && t->rchild != NULL)
		return 1 + CountNode1(t->rchild);
	if (t->rchild == NULL && t->lchild != NULL)
		return 1 + CountNode1(t->lchild);
	return CountNode1(t->lchild) + CountNode1(t->rchild);
}
int BiTree::CountNode1BiTree()
{
	BitNode* p = bt;
	cout << CountNode1(p);
	return 1;
}
int BiTree::CountNode2(BitNode* t)
{
	if (t == NULL)
		return 0;
	if (t->lchild != NULL && t->rchild != NULL)
		return 1 + CountNode2(t->lchild) + CountNode2(t->rchild);
	return CountNode2(t->lchild) + CountNode2(t->rchild);
}
int BiTree::CountNode2BiTree()
{
	BitNode* p = bt;
	cout << CountNode2(p);
	return 1;
}
int BiTree::Alike(BitNode* s, BitNode* t)
{
	if (s == NULL && t == NULL)
	{
		return 1;
	}
	else if (s == NULL || t == NULL)
	{
		return 0;
	}
	else
		return Alike(s->lchild, t->lchild) && Alike(s->rchild, t->rchild);
}
int main()
{
	BiTree t,t1,t2;
	cout << "递归创建t: ";
	t.RecreateBiTree();
	cout << "中序遍历的序列为:";
	t.InTraverseBiTree();
	cout << endl;
	cout << "树的深度为:";
	t.BTNodeDepthBiTree();
	cout << endl;
	cout << "度为1的结点数为:";
	t.CountNode1BiTree();
	cout << endl;
	cout << "度为2的结点数为:";
	t.CountNode2BiTree();
	cout << endl;
	cout << "递归创建t1: ";
	t1.RecreateBiTree();
	cout << "递归创建t2: ";
	t2.RecreateBiTree();
	if (t.Alike(t1.GetRoot(), t2.GetRoot()))
		cout << "t1和t2相似" << endl;
	else
		cout << "t1和t2不相似" << endl;
	return 0;
}

✅运行示例:
在这里插入图片描述

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

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

相关文章

基于深度学习网络的美食检测系统matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 % 图像大小 image_size [224 224 3]; num_classes size(VD,2)-1;% 目标类别数量…

解决:Xshell连接服务器卡在To escape to local shell, press ‘Ctrl+Alt+]‘.很久才能够连接上

如下图&#xff1a;在输入服务器的账号密码后&#xff0c;会卡在这里没有任何反映需要几分钟才能连接上 造成这个情况的原因&#xff1a; 在SSH服务中&#xff0c;UseDNS用于指定当用户SSH登录一个域名时&#xff0c;服务器是否使用DNS来确认该域名对应的IP地址。如果UseDNS设置…

【约会云栖】从初中至大学,我见证了科技变革的历程。

前言 提起阿里云开发者大会&#xff0c; 你一定会觉得陌生&#xff1b;但提起云栖大会&#xff0c;你又会耳熟能详。实际上&#xff0c;云栖大会的前身就是阿里云开发者大会&#xff0c;2015年&#xff0c;它永久落户在杭州市西湖区云栖小镇。 2023年10月31日至11月2日&#xf…

echarts 饼图中心添加图片

需求 问题 - 暂时无法解决&#xff08;如果图标居中不存在该问题&#xff09; 由于此处饼图位置不处于当前 echarts 图表容器的中心位置&#xff0c;而是偏左一点&#xff0c;我们需要设置&#xff1a; 中心图片所在靠左位置【见 - 主要代码1】官方手册 https://echarts.apache…

记一次 logback 没有生成独立日志文件问题

背景 在新项目发布后发现日志文件并没有按照期望的方式独立开来&#xff0c;而是都写在了 application.log 文件中。 问题展示 日志文件&#xff1a; 项目引入展示&#xff1a; <include resource"paas/sendinfo/switch/client/sendinfo-paas-switch-client-log.…

全面解析C++ std::move

全面解析C std::move 本篇文章首发知识星球&#xff0c;感兴趣的可以点击下方加入即可。 std::move 是一个非常重要的函数&#xff0c;它提供了一种方式&#xff0c;可以将一个左值对象标记为一个特殊类型的右值对象&#xff0c;即 xvalue。这种转变是为了允许执行移动语义&…

通过wordpress能搭建有影响力的帮助中心

wordpress建站服务是一种提供简单易用的工具和功能&#xff0c;帮助用户轻松创建和管理网站的服务。它适用于各类网站管理员、个人博主和小型企业主&#xff0c;无论是想要搭建个人博客、展示作品集还是开设在线商店&#xff0c;都可以通过wordpress建站服务来实现。 | 一、搭建…

反转链表II(C++解法)

题目 给你单链表的头指针 head 和两个整数 left 和 right &#xff0c;其中 left < right 。请你反转从位置 left 到位置 right 的链表节点&#xff0c;返回 反转后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], left 2, right 4 输出&#xff1a;[1…

嘴尚绝:健康卤味风靡市场,美味与健康并行

随着人们生活水平的提高&#xff0c;健康饮食成为越来越多人的追求。在卤味市场&#xff0c;传统重口味卤味逐渐被健康卤味所取代。本文将探讨健康卤味如何逐步占领市场&#xff0c;以及其背后的原因和未来的发展趋势。 卤味&#xff0c;作为中国美食的代表之一&#xff0c;有…

【FastBond2阶段1——基于ESP32C3开发的简易IO调试设备】

【FastBond2阶段1——基于ESP32C3开发的简易IO调试设备】 1. 功能介绍2. 主要元器件介绍2.1 主控板&#xff1a;CORE ESP32-C3核心板2.2 传感器2.2.1 旋转编码器&#xff1a;2.2.2 模拟ADC&#xff1a;2.2.3 GPIO接口&#xff1a; 2.3 执行器2.3.1 WS2812:2.3.2 90舵机&#xf…

Linux期末复习——C编程基础

Linux下C语言编译环境概述 编译器&#xff1a;VI 编译器&#xff1a;GCC 调试器&#xff1a;GDB 项目管理器&#xff1a;make vi编辑器 三种模式 命令行模式&#xff1a;默认模式&#xff0c;不可以编辑&#xff0c;只可以上下移动光标“整行删除&#xff0c;删除字符”&…

【C++】多态 ⑨ ( vptr 指针初始化问题 | 构造函数 中 调用 虚函数 - 没有多态效果 )

文章目录 一、vptr 指针初始化问题1、vptr 指针与虚函数表2、vptr 指针初始化时机3、构造函数 中 调用 虚函数 - 没有多态效果4、代码示例 构造函数 的 作用就是 创建对象 , 构造函数 最后 一行代码 执行完成 , 才意味着 对象构建完成 , 对象构建完成后 , 才会将 vptr 指针 指向…

前端面试 面试多起来了

就在昨天 10.17 号,同时收到了三个同学面试的消息。他们的基本情况都是双非院校本科、没有实习经历、不会消息中间件和 Spring Cloud 微服务,做的都是单体项目。但他们投递简历还算积极,从今年 9 月初就开始投递简历了,到现在也有一个多月了。 来看看,这些消息。 为…

自定义表格的表头根据后端的数据进行筛选是否进行自定义表头添加按钮

自定义表格的表头根据后端的数据进行筛选是否进行自定义表头添加按钮 自定义表格的表头根据后端的数据进行筛选是否进行自定义表头添加按钮 <template><div class"box"><el-table :data"msgMapList" border class"table">&l…

药明合联港股IPO,能否撑起生物偶联药物市场的新希望?

据港交所10月29日披露&#xff0c;药明合联生物技术有限公司(简称&#xff1a;药明合联)通过港交所主板上市聆讯&#xff0c;大摩、小摩、高盛为其联席保荐人。 此消息公布后&#xff0c;进一步点燃了市场药明生物的热情&#xff0c;29-30日药明生物收获两根大阳线&#xff0c…

Linux————内置命令大全

&#xff08;一&#xff09;内置命令 Shell 内置命令&#xff0c;就是由 Bash Shell 自身提供的命令&#xff0c;而不是文件系统中的可执行脚本文件。内置命令的执行速度通常优于外部命令&#xff0c;因为执行外部命令不仅会导致磁盘I/O操作&#xff0c;而且还需要为其fork一个…

Rand-RCCA安全接收者匿名

只是学习过程记录供参考,SPHF部分未完 论文&#xff1a;Receiver-anonymity in rerandomizable RCCA-secure cryptosystems resolved(CRYPTO 2021) SPHF论文参考&#xff1a; A practical public key cryptosystem provably secure against adaptive chosen ciphertext attack…

SQLITE3 函数接口

简述 sqlite3 接口的核心元素: 两大对象&#xff0c;八大函数&#xff1b; 其中两个对象指的是: sqlite3 数据库连接对象 数据库的连接句柄(数据库的文件描述符) 代表你打开的那个 sqlite3 的数据库文件,后序对数据库的操作都需要用到这个对象 sqlite3_stmt SQL 语句对象…

android中的Package安装、卸载、更新替换流程

android系统在安装&#xff0c;删除&#xff0c;替换&#xff0c;清除数据等与应用相关的动作时&#xff0c;会发出对应的Broadcast&#xff0c;上层的应用通过注册相应的广播事件来做相应的处理。 官方文档中给出了详尽的罗列&#xff1a; ACTION_PACKAGE_ADDED 一个新应用包已…

批量修改文件名称(现学现卖版)

目录 一、复制所有文件路径二、批量修改 一、复制所有文件路径 ctrlA选中所有文件&#xff0c;点击主页&#xff0c;复制路径 粘贴到excal表格中 添加新文件名 组合命令&#xff0c;插入函数CONCATENATE ren空格<旧文件名>空格<新文件名><后缀名> …