C++实现二叉树的创建删除,dfslfs,求叶子结点个数,求叶子结点个数,求树的高度

news2024/12/24 2:35:46

C++实现二叉树的创建删除,dfs/lfs,求叶子结点个数,求树的高度

基本算法:

用链栈建立二叉树,通过递归实现深度优先的三种遍历,用队列实现广度优先层次遍历。借助递归思想求解叶子结点个数和树的深度。

tree.h定义基本的框架,包括结点的定义,创建树时用的栈,lfs遍历用到的队列等。

在教材上经常出现用数组实现栈,这里不妨用链表实现。

例子

A(B(D(,G)),C(E,F))
在这里插入图片描述

//tree.h
#pragma once
typedef char BTNodeDataType;
struct 	BTNode
{
	BTNodeDataType data;
	struct BTNode* lchild;
	struct BTNode* rchild;
	struct BTNode* parent;

};

struct TreeStackNode
{
	BTNode* treenode;
	TreeStackNode* next;
};

struct BTQueueNode
{
	BTNode* data;
	BTQueueNode* next;
};

struct BTQueue
{
	BTQueueNode* front;
	BTQueueNode* rear;
};

TreeStackNode* InitTreeStackNode();

//全局变量ts,便于多文件调用
extern TreeStackNode* ts = InitTreeStackNode();

void PushStack(TreeStackNode*& root,
	TreeStackNode*& decendent);

void DestroyStack(TreeStackNode*& s);
void PopStack(TreeStackNode*& root);

BTNode* InitBTNode();
void InsertBT(BTNode*& n, BTNodeDataType d, int i);
void DispBT(BTNode*& root);

string GetBTString(BTNode*& root);
BTQueueNode* InitBTQueueNode();

BTQueue* InitBTQueue();
void EnQueue(BTQueue*& queue, BTNode* data);
void DeQueue(BTQueue*& queue);
BTQueueNode* GetQueueFront(BTQueue*& queue);

void PreOrder(BTNode*& root);
void InOrder(BTNode*& root);
void PostOrder(BTNode*& root);

int CountLeaf(BTNode* root);
int GetHeight(BTNode* root);

定义组成元素为结点的队列

//BTNodeQueue.cpp文件
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
#include"tree.h"
BTQueue* InitBTQueue()
{
	BTQueue* queue= (BTQueue*)malloc(sizeof(BTQueue*));
	queue->front = NULL;
	queue->rear = NULL;
	return queue;

}


void EnQueue(BTQueue*& queue,BTNode* data)
{
	BTQueueNode* newnode;
	newnode =
		(BTQueueNode*)malloc(sizeof(BTQueueNode*));
	newnode->data = data;
	newnode->next = NULL;
	
	if (queue->front == NULL && queue->rear == NULL)
	{
		queue->front = queue->rear = newnode;
	}
	else
	{
		queue->rear->next = newnode;
		queue->rear = queue->rear->next;
	}

}
void DeQueue(BTQueue*& queue)
{
	if (queue->front == NULL)
	{
		cout << "Queue is empty" << endl;
		return;
	}
	if (queue->front == queue->rear )
	{
		queue->front = queue->rear = NULL;
		return;
	}
	BTQueueNode* q = queue->front;
	queue->front = queue->front->next;
	q->data = NULL;
	free(q->data);
	q->next = NULL;
	free(q->next);
	q->next = NULL;
	q = NULL;

}

BTQueueNode* GetQueueFront(BTQueue*& queue)
{
	return queue->front;
}

插入结点过程:

先构建根结点,用left_value判断是否有左节点,如果有就退栈;(x,x)插入右节点前先退栈,之后新节点入栈,(,x)插入右节点,之后新节点入栈。k判断下一个要插入的是左节点还是右节点。

1是左,2是右。

画图理解:G的插入:插入G,然后G入栈、

在这里插入图片描述

C的插入,G,D,B依次退栈,然后C插入后入栈。

在这里插入图片描述

E,F插入:插入E,然后E入栈,遇到逗号,E退栈,插入F,然后F入栈

在这里插入图片描述

	//main.cpp
	BTNode* root = InitBTNode();
	
    //树的根节点root从ts_next开始
	TreeStackNode* n = InitTreeStackNode();
	ts->next = n;
	ts->next->treenode = root;
	string s = "A(B(D(,G)),C(E,F))";
	char* c = &s[0]; int k = 1; 
	//用left_value判断是否有左节点,如果有就退栈
	//(_,_)插入右节点先退栈,(,_)插入右节点不退栈
	bool left_value=false;
	for (int i = 0; i < s.length(); i++)
	{
		if (*c == '(')
		{
			left_value = false;
			k = 1;
		}
		else if (*c == ')')
		{
			PopStack(ts);
		}
		else if (*c == ',')
		{
			if (left_value)
			{
				PopStack(ts);	
			}
			k = 2;
		}
		else
		{
			InsertBT(ts->next->treenode, *c, k);
			left_value = true;
		}
		c++;
	}

链栈对应的push,pop操作

void PushStack(TreeStackNode*& root,TreeStackNode*& decendent)
{
	//头插法进栈,带头结点
	if (root->next == NULL)
	{
		root->next = decendent;
	}
	else
	{
		TreeStackNode* q = root->next;
		root->next = decendent;
		decendent->next = q;
	}
}

void PopStack(TreeStackNode*& root)
{
	//退栈
	if (root->next == NULL)
	{
		cout << "Stack is Empty" << endl;
		return ;
	}
	else if (root->next->next == NULL)
	{

		TreeStackNode* p = root->next;
		root->next = NULL;
		//这里不能随便free掉,毕竟结点已经加进去二叉树了
        //free(p);
		//p = NULL;
	
	}
	else
	{
		TreeStackNode* p = root->next;
		TreeStackNode* q = p->next;
		root->next = q;
        //free(p);
		//p = NULL;

	}
}

在二叉树中插入结点的过程,k判断下一个要插入的是左节点还是右节点。1是左,2是右。

//tree.cpp
void InsertBT(BTNode*& n, BTNodeDataType d, int i)
{
	TreeStackNode* newstacknode =
		InitTreeStackNode();
	if (n->data == NULL)
	{
		n->data = d;
		newstacknode->treenode = n;
	}
	else
	{
		BTNode* new_node = InitBTNode();
		new_node->data = d;
		//new_node->parent = n;
		switch (i)
		{
		case 1:
			n->lchild = new_node;
			break;
		case 2:
			n->rchild = new_node;
			break;
		}
		newstacknode->treenode = new_node;
	}
	//新插入的结点进栈
	
	PushStack(ts,newstacknode);

}

从一个结点获得二叉树的字符串表示,

利用递归的思想,如果有孩子,先加左括号,然后如果有左节点,递归到左节点;如果有右节点,加逗号,递归到右节点,加括号:

void DispBT(BTNode*& root)
{
    if(root==nullptr) return;
	cout << root->data;
	if (root->lchild != NULL || root->rchild != NULL)
	{
		cout << "(";
		if (root->lchild != NULL)
			DispBT(root->lchild);
		if (root->rchild != NULL)
		{
			cout << ",";
			DispBT(root->rchild);
		}
		cout << ")";

	}
	
}

string GetBTString(BTNode*& root)
{
	static string s= "";
	
	s+= root->data;
	if (root->lchild != NULL || root->rchild != NULL)
	{
		s += "(";
		if (root->lchild != NULL)
			GetBTString(root->lchild);
		if (root->rchild != NULL)
		{
			s += ",";
			GetBTString(root->rchild);
		}
		s += ")";

	}
	return s;
}

层次遍历

如果有孩子,就加入队列;然后自己退出队列。

cout << "层次遍历:";
	BTQueue* queue = InitBTQueue();
	BTNode* p = root;
	EnQueue(queue, p);
	while (queue->front != NULL)
	{
		cout << p->data;
		DeQueue(queue);
		if(p->lchild!=NULL)
			EnQueue(queue, p->lchild);
		if (p->rchild != NULL)
			EnQueue(queue, p->rchild);
		if (queue->front != NULL)
		{
			p = queue->front->data;
		}
	}
	cout << endl;

完整代码

//tree.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
#include"tree.h"
#include<math.h>

BTNode* InitBTNode()
{
	BTNode* n = (BTNode*)malloc(sizeof(BTNode*));
	n->data = NULL;
	n->lchild = NULL;
	//n->parent = NULL;
	n->rchild = NULL;
	return n;

}

void InsertBT(BTNode*& n, BTNodeDataType d, int i)
{
	TreeStackNode* newstacknode =
		InitTreeStackNode();
	if (n->data == NULL)
	{
		n->data = d;
		newstacknode->treenode = n;
	}
	else
	{
		BTNode* new_node = InitBTNode();
		new_node->data = d;
		//new_node->parent = n;
		switch (i)
		{
		case 1:
			n->lchild = new_node;
			break;
		case 2:
			n->rchild = new_node;
			break;
		}
		newstacknode->treenode = new_node;
	}
	//新插入的结点进栈
	
	PushStack(ts,newstacknode);

}

void DispBT(BTNode*& root)
{
    if(root==nullptr) return;
	cout << root->data;
	if (root->lchild != NULL || root->rchild != NULL)
	{
		cout << "(";
		if (root->lchild != NULL)
			DispBT(root->lchild);
		if (root->rchild != NULL)
		{
			cout << ",";
			DispBT(root->rchild);
		}
		cout << ")";

	}
	
}

string GetBTString(BTNode*& root)
{
	static string s= "";
	
	s+= root->data;
	if (root->lchild != NULL || root->rchild != NULL)
	{
		s += "(";
		if (root->lchild != NULL)
			GetBTString(root->lchild);
		if (root->rchild != NULL)
		{
			s += ",";
			GetBTString(root->rchild);
		}
		s += ")";

	}
	return s;
}

void PreOrder(BTNode*& root)
{
	if (root == NULL)
	{
		return;
	}
	cout << root->data;
	PreOrder(root->lchild);
	PreOrder(root->rchild);

}

void InOrder(BTNode*& root)
{
	if (root == NULL)
	{
		return;
	}
	InOrder(root->lchild);
	cout << root->data;
	InOrder(root->rchild);

}
void PostOrder(BTNode*& root)
{
	if (root == NULL)
	{
		return;
	}
	PostOrder(root->lchild);
	PostOrder(root->rchild);
	cout << root->data;

}

int CountLeaf(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	if (root->lchild == NULL && root->lchild == NULL)
		return 1;

	return CountLeaf(root->lchild) + CountLeaf(root->rchild);
}

int GetHeight(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	return max(GetHeight(root->lchild), GetHeight(root->rchild)) + 1;
}


TreeStackNode* InitTreeStackNode()
{
	TreeStackNode* s;
	s=(TreeStackNode*)malloc(sizeof(TreeStackNode*));
	s->treenode = (BTNode*)malloc(sizeof(BTNode*));
	s->treenode = NULL;
	s->next = NULL;
	return s;
}

void PushStack(TreeStackNode*& root,TreeStackNode*& decendent)
{
	//头插法进栈,带头结点
	if (root->next == NULL)
	{
		root->next = decendent;
	}
	else
	{
		TreeStackNode* q = root->next;
		root->next = decendent;
		decendent->next = q;
	}
}

void PopStack(TreeStackNode*& root)
{
	//退栈
	if (root->next == NULL)
	{
		cout << "Stack is Empty" << endl;
		return ;
	}
	else if (root->next->next == NULL)
	{

		TreeStackNode* p = root->next;
		root->next = NULL;
        free(p);
		p = NULL;
	
	}
	else
	{
		TreeStackNode* p = root->next;
		TreeStackNode* q = p->next;
		root->next = q;
        free(p);
		p = NULL;

	}
}

//main.cpp文件
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
#include"tree.h"
void test1()
{
	BTNode* root = InitBTNode();
	
    //树的根节点root从ts_next开始
	TreeStackNode* n = InitTreeStackNode();
	ts->next = n;
	ts->next->treenode = root;
	string s = "A(B(D(,G)),C(E,F))";
	char* c = &s[0]; int k = 1; 
	//用left_value判断是否有左节点,如果有就退栈
	//(_,_)插入右节点先退栈,(,_)插入右节点不退栈
	bool left_value=false;
	for (int i = 0; i < s.length(); i++)
	{
		if (*c == '(')
		{
			left_value = false;
			k = 1;
		}
		else if (*c == ')')
		{
			PopStack(ts);
		}
		else if (*c == ',')
		{
			if (left_value)
			{
				PopStack(ts);	
			}
			k = 2;
		}
		else
		{
			InsertBT(ts->next->treenode, *c, k);
			left_value = true;
		}
		c++;
	}
	string  BTString = GetBTString(root);
	cout << BTString << endl;
	
	cout << "层次遍历:";
	BTQueue* queue = InitBTQueue();
	BTNode* p = root;
	EnQueue(queue, p);
	while (queue->front != NULL)
	{
		cout << p->data;
		DeQueue(queue);
		if(p->lchild!=NULL)
			EnQueue(queue, p->lchild);
		if (p->rchild != NULL)
			EnQueue(queue, p->rchild);
		if (queue->front != NULL)
		{
			p = queue->front->data;
		}
	}
	cout << endl;

	//DLR
	cout << "DLR:";
	PreOrder(root);
	cout<<endl;

	//LDR
	cout << "LDR:";

	InOrder(root);
	cout << endl;
	//LRD
	cout << "LRD:";

	PostOrder(root);
	cout << endl;

	int Count =CountLeaf(root);
	cout << "叶子结点有" << Count << "个" << endl;

	int height = GetHeight(root);
	cout << "树的高度是:" << height << endl;
}

int main()
{
	test1();
	return 0;
}

结果展示

在这里插入图片描述

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

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

相关文章

sysbench 命令:跨平台的基准测试工具

一、命令简介 sysbench 是一个跨平台的基准测试工具&#xff0c;用于评估系统性能&#xff0c;包括 CPU、内存、文件 I/O、数据库等性能。 ‍ 比较同类测试工具 bench.sh 在上文 bench.sh&#xff1a;Linux 服务器基准测试中介绍了 bench.sh 一键测试脚本&#xff0c;它对…

CAT1 RTU软硬件设计开源资料分析(TCP协议+Modbus协议+GNSS定位版本 )

01 CAT1 RTU方案简介&#xff1a; 远程终端单元( Remote Terminal Unit&#xff0c;RTU)&#xff0c;一种针对通信距离较长和工业现场环境恶劣而设计的具有模块化结构的、特殊的计算机测控单元&#xff0c;它将末端检测仪表和执行机构与远程控制中心相连接。 奇迹TCP RTUGNS…

【MySQL】数据库--索引

索引 1.索引 在数据中索引最核心的作用就是&#xff1a;加速查找 1.1 索引原理 索引的底层是基于BTree的数据存储结构 如图所示&#xff1a; 很明显&#xff0c;如果有了索引结构的查询效率比表中逐行查询的速度要快很多且数据越大越明显。 数据库的索引是基于上述BTree的…

C--结构体和位段的使用方法

各位看官如果您觉得这篇文章对您有帮助的话 欢迎您分享给更多人哦 感谢大家的点赞收藏评论&#xff0c;感谢您的支持&#xff01;&#xff01;&#xff01; 一&#xff1a;结构体 首先结构体我们有一个非常重要的规则 非常重要&#xff1a; 我们允许在初始化时自动将字符串字面…

Jmeter关联,断言,参数化

一、关联 常用的关联有三种 1.边界提取器 2.JSON提取器 3.正则表达式提取器 接下来就详细讲述一下这三种的用法 这里提供两个接口方便练习 登录接口 接口名称&#xff1a;登录 接口提交方式&#xff1a;POST 接口的url地址&#xff1a;https://admin-api.macrozheng.com/a…

部署Tomcat服务

一、部署过程 1. 节点规划 节点IP 主机名 节点 192.168.20.20 tomcat Tomcat 2. 基础环境配置 2.1. 修改主机名 [rootlocalhost ~]# hostnamectl set-hostname tamcat [rootlocalhost ~]# bash 2.2. 关闭防火墙 [roottamcat ~]# systemctl stop firewalld [roott…

嵌入式单片机底层原理详解

前言 此笔记面向有C语言基础、学习过数字电路、对单片机有一定了解且尚在学习阶段的群体编写,笔记中会介绍单片机的结构、工作原理,以及一些C语言编程技巧,对于还停留在复制模板、copy代码阶段的读者会有比较大的帮助,待学习完成后可以独立完成几乎所有单片机的驱动开发。 …

macOS安装MySQL教程, 2024年9月26日更新, 亲测有效, 附有百度网盘下载链接

下载: https://dev.mysql.com/downloads/mysql/ 选第一个 DMG版本的. 这一步可能需要登录一下, 比较麻烦, 一会儿我传到百度网盘, 文末发百度网盘的链接. 点击下载按钮, 会弹出下载提示. 开始下载了, 很慢. 复制链接地址, 使用迅雷下载. 稍微快点. 我传到了百度网盘: 通过网…

Java List类

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;折纸花满衣 &#x1f3e0;个人专栏&#xff1a;Java 目录 &#x1f449;&#x1f3fb;List1. 接口与实现2. 特性3. 常用方法4. 示例代码5. 遍历6. 线程安全 &#x1f449;&#x1f3fb;List Java的 List …

【含文档】基于Springboot+微信小程序 的高校社团管理小程序(含源码+数据库+lw)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 系统定…

菱形继承、菱形虚拟继承、菱形继承中多态问题、菱形虚拟继承中多态问题

菱形继承以及菱形继承中的多态问题 一、对象模型&#xff08;一&#xff09;菱形继承 & 菱形虚拟继承&#xff08;一&#xff09;菱形继承中多态 & 菱形虚拟继承中多态 二、总结 本文主要叙述菱形继承、菱形虚拟继承、菱形继承中多态、菱形虚拟继承中多态&#xff0c;这…

JavaWeb 13.HTTP协议

和自己的情绪共处&#xff0c;永远保持乐观 —— 24.9.26 一、HTTP简介 HTTP 超文本传输协议 (HTTP-Hyper Text transfer protocol)&#xff0c;是一个属于应用层的面向对象的协议&#xff0c;由于其简捷、快速的方式&#xff0c;适用于分布式超媒体信息系统。它于1990年提出&a…

STL之vector篇(下)(手撕底层代码,从零实现vector的常用指令,深度剖析并优化其核心代码)

文章目录 1.基本结构与初始化1.1 空构造函数的实现与测试1.2 带大小和默认值的构造函数1.3 使用迭代器范围初始化的构造函数(建议先看完后面的reserve和push_back)1.4 拷贝构造函数1.5 赋值操作符的实现&#xff08;深拷贝&#xff09;1.6 析构函数1.7 begin 与 end 迭代器 2. …

jQuery——层次选择器

1、层次选择器&#xff1a;查找子元素&#xff0c;后代元素&#xff0c;兄弟元素的选择器。 ancestor descendant&#xff1a;在给定的祖先元素下匹配所有的后代元素 parent > child&#xff1a;在给定的父元素下匹配所有的子元素 prev next&#xff1a;匹配所有紧接在…

每日一练:二叉树的右视图

199. 二叉树的右视图 - 力扣&#xff08;LeetCode&#xff09; 一、题目要求 给定一个二叉树的 根节点 root&#xff0c;想象自己站在它的右侧&#xff0c;按照从顶部到底部的顺序&#xff0c;返回从右侧所能看到的节点值。 示例 1: 输入: [1,2,3,null,5,null,4] 输出: [1,3,…

超详细的 pytest教程 之前后置方法和 fixture 机制

前言 这一篇文章专门给大家讲解pytest中关于用例执行的前后置步骤处理,pytest中用例执行的前后置处理既可以通过测试夹具(fixtrue)来实现&#xff0c;也可以通过xunit 风格的前后置方法来实现。接下来我们一起看看如何具体使用。 一、xunit 风格的前后置方法 1、函数用例的前…

基于STM32的智能家庭安全监控系统

目录 引言项目背景环境准备 硬件准备软件安装与配置系统设计 系统架构关键技术代码示例 传感器数据采集摄像头监控与数据处理实时报警功能实现应用场景结论 1. 引言 智能家庭安全监控系统使用嵌入式设备&#xff0c;如STM32微控制器&#xff0c;来实时监控家庭环境。通过集成…

[教程]如何在iPhone上启用中国移动/联通/电信RCS消息

目前 苹果已经在 iOS 18 中带来 RCS 富媒体消息的支持&#xff0c;该消息基于网络传递&#xff0c;用户可以通过 RCS 免费将消息发送到其他 iPhone 或 Android 设备。在苹果面向测试版用户推出的 iOS 18.1 Beta 版中&#xff0c;中国网络运营商包括中国移动、中国联通、中国电信…

文献笔记 - Ground effect on rotorcraft unmanned aerial vehicles: a review

这篇博文是自己看文章顺手做的笔记 只是简单翻译和整理 仅做个人参考学习和分享 如果作者看到觉得内容不妥请联系我 我会及时处理 本人非文章作者&#xff0c;文献的引用格式如下&#xff0c;原文更有价值 摘要—— 收集和讨论小型多旋翼无人机受地面效应的影响&#xff0c;…

阿b的弹幕如何获取?这个可以帮到你!

弹幕 前几天&#xff0c;做了一个b站弹幕的爬取&#xff0c;只需要输入一个bv号&#xff0c;就可以查看这个视频的弹幕&#xff0c;并且提供了一种可以写入到文件的方法。但是有人反应&#xff0c;这种使用仍然非常困难&#xff0c;应该提供一个更加友好的用户界面。 因此本期…