ege库基于前中后序动态建立二叉树、序列检错以及查找公共父节点C++

2023-11-07

 一、需求分析

1、任意输入前序 + 中序序列或者中序 + 后序序列,生成二叉树
3、利用打印二叉树功能显示二叉树的逐步构造过程,使用自上而下的二叉树显示
4、使用EGE(xege.org) / SFML(www.sfml - dev.org / download / sfml / 2.5.1 / )库进行可视化
5、使用三叉链表,在构造链表的过程中同步更新每个节点的parent指针
6、输入两个节点值 找到共同祖先
7、检测输入的前序,中序,后续序列的有效性 例如当用户输入错误的序列时,程序应该有错误提示并构造二叉树至出错前状态

 二、详细设计(均以前中序建树为例)

(1)节点的定义

template <class T>
struct BTNode
{
	T data;
	int depth;//depth of a node
	BTNode<T> *lchild, *rchild, *parent;
	BTNode() :lchild(NULL), rchild(NULL), parent(NULL) {}
	BTNode(T x, int a = 0, int b = 0, BTNode<T> *l = NULL, BTNode<T> *r = NULL, BTNode<T> *p = NULL)
		:data(x), depth(b), lchild(l), rchild(r), parent(p) {}
};

template <class T>
class BT {
protected:
	BTNode<T>* root;
public:
	BT() :root(NULL) {}
	~BT() { destory(root); }
	void destory(BTNode<T>*& tree);
	BTNode<T>* GetRoot() { return root; }//get the address of the root node
	BTNode<T>* getParent(BTNode<T>* tree) { return tree->parent; }
	BTNode<T>* creatreeVVR(char* VLR, char* LVR, int size, BTNode<T>*& tree, BTNode<T>* &temptree,
		double x0, double y0, double x, double y, int n);//establish binary tree in preorder and inorder
	BTNode<T>* creatreeLVV(char* LVR, char* LRV, int size, BTNode<T>*& tree, BTNode<T>* &temptree,
		double x0, double y0, double x, double y, int n);//establish binary tree in inorder and preorder
	BTNode<T>* SearchNode(BTNode<T>* &tree, T data);//get the address by the a value T
	BTNode<T>* SearchParentNode(BTNode<T>* &tree, T data);
	char comparent(BTNode<T>* tree1, BTNode<T>* tree2);//get the value of two node's common ancestor
	int getDepth(BTNode<T>* tree);//get the depth of a node
	void PrintVLR(BTNode<T>* tree);
	void PrintLVR(BTNode<T>* tree);
	void PrintLRV(BTNode<T>* tree);
	friend int main();
};

(2)前序和中序的检错

检错的第一个组成部分:检查a序列的元素是否在b中都存在以及b序列的元素是否在a中都存在

通过使用\0,来控制只对前k个元素操作

bool errorDetectionRecursion(char* a, char* b, int size)
{
	char temp;
	for (int i = 0; i < size; i++) {//strchr:在一个串中查找给定字符的第一个匹配之处 函数原型为:char *strchr(const char *str, int c)
		temp = b[size];
		b[size] = '\0';
		if (!strchr(b, a[i])) {
			cerr << "序列错误\n";
			return 0;//序列有错则直接返回,将序列截断在出错之处,从而达到构造二叉树到出错之前的状态
		}
		b[size] = temp;
	}
	for (int i = 0; i < size; i++) {
		temp = a[size];
		a[size] = '\0';
		if (!strchr(a, b[i])) {
			cerr << "序列错误\n";//序列无错则将\0处的元素还原
			return 0;
		}
		a[size] = temp;
	}
	return 1;
}

检错的第二个组成部分:通过递归和调用第一个检错函数,对整个序列进行检错

bool errorDetectionVVR(char* VLR, char* LVR, int size)
{
	if (size <= 0) return 1;
	//如果两个序列元素一致,就对比其左右子树
	if (errorDetectionRecursion(VLR, LVR, size))
	{
		int k = 0;
		while (VLR[0] != LVR[k])k++;
		//对比左子树两个序列元素
		//从前序的左子树开始,前序的左子树从第k+1个元素开始,中序的左子树在前k个元素位上
		if (errorDetectionVVR(VLR + 1, LVR, k))
		{//如果左子树两个序列元素相同,继续比较右子树
		 //前序的右子树从第k+2位开始,共size-k-1位
         //中序的右子树从第k+2位开始,共size-k-1位
			if (errorDetectionVVR(VLR + k + 1, LVR + k + 1, size - k - 1))
				return 1;//右子树也相同,返回1
			else return 0;//右子树两个序列不同,返回0
		}
		else return 0;//如果左子树两个序列元素不同,返回0
	}
	else return 0;//如果两个序列元素不同,返回0
}

思路来自于一位大佬,代码有所简化

(3)前序和中序的建树

参数BTNode<T>* &temptree用于同步更新parent指针

template<class T>
BTNode<T>*BT<T>::creatreeVVR(char* VLR, char* LVR, int size, BTNode<T>* &tree, BTNode<T>* &temptree,
	double x0, double y0, double x, double y, int n)
//传入的参数分别为:前序中序序列,目标树的根节点,辅助建树的树的节点,ege库函数里节点的当前x,y坐标,节点的下一次递归的x,y坐标
{
	if (size <= 0)return NULL;
	tree = new BTNode<T>(*VLR);//VLR[0]
	tree->parent = temptree;
	//ege操作
	setcaption("以前序和中序创建二叉树");
	initgraph(700, 500/*, INIT_WITHLOGO*/);//初始化图形界面
	setfont(20, 0, "微软雅黑");
	setbkcolor(WHITE);	//设置背景为白色
	//movewindow(800, 300, true);//罪恶之源
	setcolor(RED);
	circle(x, y, 22);//画圈
	setcolor(BLACK);
	outtextxy(x, y, tree->data);//outtextxy不支持\t \n这类格式化用的特殊字符//要使用特殊格式化字符请用outtextrect
	Sleep(30);//delay_ms(0);
	line(x0, y0, x, y);
	Sleep(150);//Sleep(300);
	//利用pow函数,每一次递归,都能得到不同的且合适的节点的x坐标,y坐标每次下沉100
	int t = pow(2, n);//1
	int x1 = x - 400 / t;
	int x2 = x + 400 / t;
	//找根节点
	int k = 0;
	while (VLR[0] != LVR[k]) {
		k++;
		if (k > size - 1) {//when the sequence is wrong, avoid entering the dead loop of k++
			system("pause");
		}
	}
	creatreeVVR(VLR + 1, LVR, k, tree->lchild, tree,
		x, y, x1, 100.0 * n, n + 1);
	//从前序的左子树开始,前序的左子树从第k+1个元素开始,中序的左子树在前k个元素位上
	creatreeVVR(VLR + 1 + k, LVR + 1 + k, size - 1 - k, tree->rchild, tree,
		x, y, x2, 100.0 * n, n + 1);
	//前序的右子树从第k+2位开始,共size-k-1位
    //中序的右子树从第k+2位开始,共size-k-1位
}

(4)查找共同祖先(父节点)

算法思路:

需要先设计一个按值搜索节点的函数BTNode<T>* BT<T>::SearchNode(BTNode<T>* &tree, T data)得到两个节点的地址

再设计一个由两个节点找出其公共父节点的函数char BT<T>::comparent(BTNode<T>* tree1, BTNode<T>* tree2)

问题等价于:查找两个链表的交叉(相同)元素

则需要知道两个节点的深度,所以还需要一个获取节点深度的函数int BT<T>::getDepth(BTNode<T>* tree)

1)SearchNode函数

template<class T>
BTNode<T>* BT<T>::SearchNode(BTNode<T>* &tree, T data)
{
	if (tree == NULL) return NULL;
	BTNode<T>* pTemp = NULL;
	if (tree->data == data) pTemp = tree;
	else {
		if (!pTemp) pTemp = SearchNode(tree->lchild, data);//递归到左子树
		if (!pTemp) pTemp = SearchNode(tree->rchild, data);
	}
	return pTemp;
}

2)getDepth函数

template<class T>
int BT<T>::getDepth(BTNode<T>* tree)
{
	int depth = 0;
	BTNode<T>* pTemp = tree;
	while (pTemp)
	{
		depth++;
		pTemp = pTemp->parent;//不断往上寻找父节点
	}
	return depth;
}

3)Comparent函数

template<class T>
char BT<T>::comparent(BTNode<T>* tree1, BTNode<T>* tree2)
{
	int length1 = getDepth(tree1);
	int length2 = getDepth(tree2);
	BTNode<T>* p1 = tree1;
	BTNode<T>* p2 = tree2;
	int oversize = length1 - length2;
	//为了始终让p1指向更深的节点
	if (length1 < length2) {
		oversize = length2 - length1;
		p1 = tree2;
		p2 = tree1;
	}
//需要等更深的节点上移oversize个节点之后
//两个节点才一起移动
	for (int i = 0; i < oversize; i++)
		p1 = p1->parent;
//中止条件包括p1、p2相遇时
	while (p1&&p2&&p1 != p2)
	{
		p1 = p1->parent;
		p2 = p2->parent;
	}
	return p1->data;//返回共同父节点的值
}

三、注意事项

ege库安装网站:xege.org

建树过程使用了ege库,需要在头文件里include

需要提前#define SHOW_CONSOLE,否则控制台黑窗口可能被禁用

Ps:由于本人才疏学浅,错误纰漏之处在所难免,如果您在阅读的过程中发现了文章的错误和不足,欢迎交流学习与指正。

附完整代码:

BinaryTree.rar-C/C++文档类资源-CSDN下载

内置ege的版本:

ege库基于前中后序动态建立二叉树源码(内附ege)-以太坊资源-CSDN下载

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ege库基于前中后序动态建立二叉树、序列检错以及查找公共父节点C++ 的相关文章

  • ROC,AUC及其基于Sklearn的实现

    ROC AUC及其基于Sklearn的实现 ROC和AUC的概念 sklearn的实现 from sklearn metrics import roc curve auc 多分类问题的ROC绘制 代码实现sklearn官方文档 API文档

随机推荐

  • Python之定时器的使用

    python中的定时器的使用 一 必须引入库 import threading 引入库 二 上代码 usr bin python coding UTF 8 import threading 引入库 def name timer print
  • 命令登陆mysql数据库_命令操作Mysql数据库

    MySql中添加用户 新建数据库 用户授权 删除用户 修改密码 注意每行后边都跟个 表示一个命令语句结束 1 新建用户 1 1 登录MYSQL gt mysql u root p gt 密码 1 2 创建用户 登录mysql后创建新用户 后
  • Android屏幕适配全攻略

    Android屏幕适配出现的原因 在我们学习如何进行屏幕适配之前 我们需要先了解下为什么Android需要进行屏幕适配 由于Android系统的开放性 任何用户 开发者 OEM厂商 运营商都可以对Android进行定制 修改成他们想要的样子
  • 2020运营商SDN和NFV的投入超200亿美元

    近两年 在网络领域最火热的非软件定义网络SDN和网络功能虚拟化NFV莫属 并且可以预计 在未来的一段时间内 SDN和NFV都将成为网络世界的 主角 其中SDN将让网络具备可灵活调配资源的能力 从而提高网络利用率 并降低网络服务成本 是未来新
  • 复现ThinkPHP5 5.0.23远程代码执行漏洞

    访问 index php s captcha页面 会出现如下报错 执行whoami 查看当前目录 method construct filter system method get server REQUEST METHOD pwd 写入一
  • 最大公约数和最小公倍数问题

    等差数列 蓝桥杯192 gcd问题 题目描述 数学老师给小明出了一道等差数列求和的题目 但是粗心的小明忘记了一 部分的数列 只记得其中 N 个整数 现在给出这 N 个整数 小明想知道包含这 N 个整数的最短的等差数列有几项 思路 求出每一项
  • Web学习笔记4:html初级篇-基础标签(1)

    话接上次 一 基本框架 在html语言中 也会有所谓的基本框架 我们来看一下 我们来一个一个解释 首先 我们要明确一点 框架中的标签都是一对的 这是什么意思 我们可以看到 在框架中有和 有和 有和 这些 只要是中间的文字一样 且标签形式为前
  • nginx中斜杠(/)详解

    本文主要介绍了nginx中斜杠 详解 配置location proxy pass时 加 与不加 的区别 文中通过示例代码介绍的非常详细 具有一定的参考价值 感兴趣的小伙伴们可以参考一下 不知大家日常在nginx配置时 是不是会对是否加斜杠充
  • 练习:字符串统计(坑:f‘string‘报错)

    练习 字符串统计 今天刷到字符串统计的题目 能看懂了 用自己的代码也来实现一次 题目 代码实现 re代码实现 f str 报错 我的博文推荐 练习题目 回首页 代码运行效果 python代码 如果从语句注释不能清楚作用 请评论区留言指教和探
  • android中的UI视图更新不能放在子线程中操作

    surfaceview不能再子线程里更新 需要通过Handler更新
  • 部署Node节点 配置kubelet证书自动申请 CSR、审核及自动续期

    k8s1 18 8版本 kubelet首次启动流程 第一次启动时没有证书如何连接 apiserver 这个问题实际上可以去查看一下 bootstrap kubeconfig 和 token csv 得到答案 在 apiserver 配置中指
  • vite+vue+cesium搭建

    vite vue cesium搭建 学习教程 https www bilibili com video BV1X44y1x7J2 p 1 npm install g yarn npm安装yarn yarn v 查看yarn版本 cmd Wi
  • 服务器 分布式 虚拟化,「云计算」云计算的两大特性:虚拟化、分布式

    云计算技术出现以后 它会加速电信和互联网业务的融合 这个融合除了技术和运营方式的融合 或者创新模式的转变 主要是电信业务网络的全IP化和宽带化的发展 相互之间的渗透趋势越来越明显 借鉴互联网云计算发展思路 可以将电信网络现在的很多资源 包括
  • 系统提示缺少xinput1_3.dll怎么办?

    我们在使用电脑的过程中 总会遇到一些dll文件丢失的情况 大概是因为系统的内部组件受损或者是出现了某种冲突引起的 比如系统提示xinput1 3 dll丢失要如何解决呢 缺少xinput1 3 dll丢失怎么修复 1 出现如下的窗口提示 不
  • 【数据结构-队列】阻塞队列

    欢迎来到我的博客 很高兴能够在这里和您见面 希望您在这里可以感受到一份轻松愉快的氛围 不仅可以获得有趣的内容和知识 也可以畅所欲言 分享您的想法和见解 推荐 kuan 的首页 持续学习 不断总结 共同进步 活到老学到老 导航 檀越剑指大厂系
  • c++中 string 和 int 类型转换

    一 int 类型转换为 string 类型 示例 include
  • 逻辑综合——优化电路

    对进行时序路径 工作环境 设计规则等进行约束完成之后 DC就可以进行综合 优化时序了 DC在优化过程中主要的策略将在下面进行说明 然而 当普通模式下不能进行优化的 就需要我们进行编写脚本来改进DC的优化来达到时序要求 DC进行优化的目的是权
  • CTFSHOW萌新计划 web16-17

    题目地址 https ctf show 0x01 web16 这个直接爆破就可以了 但是如果你是官网群里的成员 就会知道有个36d的梗 payload 36d 爆破的话给个脚本 import hashlib str1 abcdefghijk
  • emulator: ERROR: x86 emulation currently requires hardware acceleration! Please ensure Intel HAXM is

    原文错误提示 emulator ERROR x86 emulation currently requires hardware acceleration Please ensure Intel HAXM is properly instal
  • ege库基于前中后序动态建立二叉树、序列检错以及查找公共父节点C++

    一 需求分析 1 任意输入前序 中序序列或者中序 后序序列 生成二叉树 3 利用打印二叉树功能显示二叉树的逐步构造过程 使用自上而下的二叉树显示 4 使用EGE xege org SFML www sfml dev org download