【数据结构】实验九:二叉树

实验九 二叉树

一、实验目的与要求

1)理解二叉树的类型定义;

2掌握二叉树的存储方式及基于存储结构的基本操作实现;

二、 实验内容

1. 二叉树的结点定义如下:

struct TreeNode

{

int m_nvalue;

TreeNode* m_pLeft;

TreeNode* m_pRight;

};

输入二叉树中的两个结点,输出这两个结点在树中的最近公共祖先结点。

说明:最近公共祖先定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个结点也可以是它自己的祖先)。

2. 某同学非常喜欢玩二叉树。最喜欢的游戏是用结点中的大写字母构造查找二叉树。这是他构造的二叉树:

他为每棵树写下先序遍历和中序遍历两个字符串,例如:对于上面构造的树,先序遍历为DBACEGF中序遍历为ABCDEFG几年后,他想重新构造这棵树,请你来编写一个程序帮他实现基于上述遍历序列构造树。

题意解析:根据所给的两串序列,分别是前序和中序,求出二叉树的后序。

三、实验结果

1)简述算法步骤:

2)分析算法时间复杂度:

 


题目1:

0 实验代码及结果

#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;

#define Max 100
vector<int> E[Max]; 
int parent[Max];     
int depth[Max];     

//构造递归的树  v->当前结点 p->当前的双亲结点 d->当前结点深度 
void BuildTree(int v,int p,int d){
	parent[v]=p;
	depth[v]=d;
	for(int i=0;i<E[v].size();i++){
		if(E[v][i]!=p){
			BuildTree(E[v][i],v,d+1);
		}
	}
}

//lowest common ancestor的寻找函数 
int LCA(int u,int v){
	//深度不同时,用双亲结点替换 
	while(depth[u]!=depth[v]){
		if(depth[v]<depth[u]){
			u=parent[u];
		}
		else{
			v=parent[v];
		}
	}
	//同深度时,同时迭代寻找ancestor 
	while(u!=v){
		u=parent[u];
		v=parent[v];
	}
	return v;//返回公共祖先 
}

int main(){
	int n,root=1;//n->总结点数  root->根结点 
	//root需要定义!!!!!!!!!!!!! 
	cout<<"请输入总结点数:"<<endl;
	cin>>n;
	if(n==1){
		cout<<"输入错误!不能只有一个结点!"<<endl;
		return 0;
	}
	//i<n-1 根结点无双亲,所以少输入一次 
	for(int i=0;i<n-1;i++){
		int u,v;
		cout<<"请输入双亲结点编号及其孩子结点编号:"<<endl;
		cin>>u>>v;
		E[u].push_back(v);
		E[v].push_back(u);  
	}
	BuildTree(root,-1,0);//根结点双亲为-1,深度为0 
	int u,v;
	cout<<"请输入两个待测结点的编号:" <<endl;
	cin>>u>>v;
	cout<<"其LCA为:"<<LCA(u,v)<<endl;
	return 0;
}

实验报告测试用例的二叉树如下图所示:

 代码测试结果如下图所示:

 

 

 

1 简述算法步骤

    定义存储当前结点数据、双亲结点、当前结点深度的数组,并规定最大范围为100。

    构造递归结构存储的数,存储当前结点的双亲结点和深度,然后通过for循环遍历,利用递归构造子树。在for循环中,如果遍历发现当前结点与双亲结点不同,即当前结点不是叶子结点,那么继续调用BuildTree函数构造子树,并将当前深度加一。

 

    寻找最近公共祖先时,先判断两个结点的深度是否相同。如果深度不同,则先回溯深度较深的结点,寻找其与另外一个结点深度相同时的祖先。回溯完以后,此时u、v深度相同,直接比较u、v结点是否相同。如果结点不同,则分别向上回溯一个祖先,再判断其祖先是否相同。最后两个结点回溯到相同值,返回其中一个结点即可。

    最后通过vector自带函数和for循环,将预设的树进行入栈并构造。

 

2 分析算法时间复杂度

    在利用递归创建树时,利用了for循环遍历双亲合集,来判断当前结点的双亲结点是否已经被存入。由此可见,时间复杂度为O(n^2)。

    在LCA函数中,通过第一个while循环收缩较远结点的深度进行回溯,通过第二个while循环同时收缩两个结点的深度进行回溯。由此可见,时间复杂度均为O(n)。

    在主函数输入预设树的基本信息时,利用了for循环将每一组【双亲结点+孩子结点】存入vector中。由此可见,时间复杂度为O(n)。

 

题目2:

0 实验代码及结果

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;

typedef struct Node{
    char data;//数据域 
    struct Node *lchild,*rchild;//左孩子结点+右孩子结点 
}Node,*BiTree;
 
char PreString[30],InString[30];//先序和中序遍历字符串 maxsize=30 

//根据先序+中序,重新构造原来的树,即BiTree T = new Node(); 
BiTree Build(char *PreString,char *InString,int s1,int e1,int s2,int e2){
	//s:start e:end 
    BiTree T = new Node();
    T -> data = PreString[s1];
    int rootIdx;//根结点所在序号
    for(int i = s2;i <= e2;i++){
        if(PreString[s1] == InString[i]){
            rootIdx = i;//寻找先序字符串中当前元素在中序字符串中的位置 
            break;//寻觅结束 
        }
    }
    int llen = rootIdx - s2;//左 为 根-初始 
    int rlen = e2 - rootIdx;//右 为 len(in)-根 
    if(llen != 0){//左 非空 
        T -> lchild = new Node();
        T -> lchild = Build(PreString,InString,s1 + 1,s1 + llen,s2,s2 + llen - 1);
		//继续在左子树里面重复上述操作;
		//prestring: start=s1+1; end=s1+llen
		//instring: start=s2; end=s2+llen-1 
    }
    else{
    	T -> lchild = NULL;
	}
    if(rlen != 0){//右 非空 
        T -> rchild = new Node();
        T -> rchild = Build(PreString,InString,e1 - rlen + 1,e1,e2 - rlen + 1,e2);
        //继续在右子树里面重复上述操作;
        //pre: start=e1-rlen+1; end=e1
        //in: start=e2-rlen+1; end=e2
    }
    else{
        T -> rchild = NULL;
    }
    return T;
}

//后序遍历 -> 递归输出 
void PostOrder(BiTree T){
    if(T != NULL){ //树非空 
        PostOrder(T -> lchild); //走左子树 
        PostOrder(T -> rchild); //走右子树 
        cout<<T -> data; //走根 or 叶子结点 
    }
}
 
int main(){
    cout<<"请输入先序遍历字符串:";
    cin>>PreString;
    cout<<"请输入中序遍历字符串:";
    cin>>InString;
    BiTree T = NULL; //构建空树 
    int e1=strlen(PreString)-1,e2=strlen(InString)-1;//两个字符串下标位数 
    T = Build(PreString,InString,0,e1,0,e2); //通过先序遍历+中序遍历推断树结构 
    cout<<"此二叉树的后序遍历为:";
	PostOrder(T);//后序遍历输出该树 
    return 0;
}

题干给的先序遍历+中序遍历构成的二叉树如下图所示:

代码测试结果如下图所示:

 

 

1 简述算法步骤

构造一个二叉树,属性携带当前结点数据、当前结点左孩子指针和当前结点右孩子指针。

根据先序遍历【根->左子树->右子树】的特点可知,先序遍历字符串中的第一个结点必然为根,然后通过for循环在中序遍历字符串中寻找与当前结点数据相同的结点,并锁定其在中序遍历字符串中的位置为rootIdx。此时,在中序遍历字符串中,rootIdx左侧的字符串为左子树的内容,rootIdx右侧的字符串为右子树的内容。同时回溯到先序遍历字符串中,可锁定左子树的始末下标和右子树的始末下标。

根据树的定义,每一个子树可作为一棵新的树。于是我们将左子树和右子树分别看作新的两个树,确定好新的prestring和instring起始下标之后,重新进行上述操作来确定整个树的空间结构,直至左子树或右子树为空树。最后返回整个树。

在确定整个树的空间结构后,通过递归的后序遍历法【左子树->右子树->根】输出整个树的结点数据。

最后通过主函数依次调用上述算法函数。

2 分析算法时间复杂度

在寻找先序字符串中当前元素在中序字符串中的位置的时候,使用了for循环遍历instring里面的所有结点数据。由此可见,时间复杂度为O(n)。整个递归调用的时间复杂度为O(n logn)。

    前俩个递归调用的时候,均通过二分法处理两个遍历字符串,从而进行下一次函数调用。第三个递归调用的时候,也与上述两个递归类似,先通过锁定根结点,分为左子树和右子树继续遍历。由此可见,时间复杂度均为O(n/2)。

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【梯度下降在波士顿房价预测中的应用】

数据准备 我们首先需要加载波士顿房价数据集。该数据集包含房屋特征信息和对应的房价标签。 import pandas as pd import numpy as npdata_url "http://lib.stat.cmu.edu/datasets/boston" raw_df pd.read_csv(data_url, sep"\s", skiprows22, headerN…

“可以黑掉整个宇宙”的Metasploit Framework

0x01、 简述 Metasploit Framework(MSF)是一款开源安全漏洞检测工具&#xff0c;他带有数千个已知的软件漏洞&#xff0c;目前人在持续更新。Metasploit可以用来信息收集、漏洞探测、漏洞利用等渗透测试的全流程&#xff0c;被安全社区冠以“可以黑掉整个宇宙”之名。在普通的…

又一“邪恶版”ChatGPT出现,专为网络犯罪而生

最近&#xff0c;Hackread 分享了一个恶意聊天机器人 WormGPT 的详细信息&#xff0c;该聊天机器人是为帮助网络犯罪分子进行非法活动而创建的。现在&#xff0c;暗网上又出现了一个名为 FraudGPT 的聊天机器人。这是一个基于订阅的人工智能聊天机器人&#xff0c;可以为网络犯…

解密C++多态机制:发挥对象的多样性,实现更加智能的程序设计

目录 一.多态1.多态的用处2.多态的实现3.虚函数4.override 和 final5.重载重写与重定义6.虚函数表 一.多态 1.多态的用处 众所周知C语言的三大特性&#xff1a;封装、多态、继承。其中多态就是去完成某个行为&#xff0c;但是会根据不同的对象产生不同的状态&#xff0c;所以…

C语言每天一练:输出杨辉三角

题目&#xff1a;请输出以下杨辉三角(要求输出前10行) 列&#xff1a; 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 ...... 题解析&#xff1a;不了解杨辉三角的可以百度看一下&#xff0c;大概是这样的&#xff0c;咱们就可以解…

SpringBoot集成kafka全面实战

本文是SpringBootKafka的实战讲解&#xff0c;如果对kafka的架构原理还不了解的读者&#xff0c;建议先看一下《大白话kafka架构原理》、《秒懂kafka HA&#xff08;高可用&#xff09;》两篇文章。 一、生产者实践 普通生产者 带回调的生产者 自定义分区器 kafka事务提交…

微信联系人批量删除功能如何操作?删除的联系人如何恢复?

继微信推出了朋友圈置顶功能后&#xff0c;微信又推出了"批量删除好友的功能" &#xff0c;具体的操作步骤如下&#xff1a; 第一步 是点击聊天界面上的搜索框"搜索" 第二步 "搜索"排序字母&#xff0c;点击"更多联系人" 第三步 搜…

openEuler 22.03 LTS系统搭建局域网上网代理服务器

生产网环境的一个痛点就是与外网隔离&#xff0c;内网的服务器如果需要进行补丁升级或者下载更新软件&#xff0c;比较困难&#xff0c;本文讲解在生产网中能访问公网的openEuler 22.03 LTS系统服务器上搭建代理服务器&#xff0c;供内网其它服务器连接公网&#xff0c;同时介绍…

SpringBoot实战(二十三)集成 SkyWalking

目录 一、简介二、拉取镜像并部署1.拉取镜像2.运行skywalking-oap容器3.运行skywalking-ui容器4.访问页面 三、下载解压 agent1.下载2.解压 四、创建 skywalking-demo 项目1.Maven依赖2.application.yml3.DemoController.java 五、构建启动脚本1.startup.bat2.执行启动脚本3.发…

hive之文件格式与压缩

hive文件格式&#xff1a; 概述&#xff1a; 为Hive表中的数据选择一个合适的文件格式&#xff0c;对提高查询性能的提高是十分有益的。Hive表数据的存储格式&#xff0c;可以选择text file、orc、parquet、sequence file等。 文本文件&#xff1a; 文本文件就是txt文件&…

【SpirngCloud】分布式事务解决方案

【SpirngCloud】分布式事务解决方案 文章目录 【SpirngCloud】分布式事务解决方案1. 理论基础1.1 CAP 理论1.2 BASE 理论1.3 分布式事务模型 2. Seata 架构2.1 项目引入 Seata 3. 强一致性分布式事务解决方案3.1 XA 模式3.1.1 seata的XA模式3.1.2 XA 模式实践3.1.3 总结 4. 最终…

JavaScript --简介

目录 JS可以用来做什么&#xff1f; JS在前端中几种写法: 1. 文件引用&#xff1a; 2. 页面样式 3. 行内样式 集中常见的弹框: JS基本语法&#xff1a; 变量&#xff1a; 常量&#xff1a; 数据类型&#xff1a; 基本数据类型&#xff1a; 引用数据类型&#xff1a…

微信批量删除好友怎么删除

微信好友太多想要批量删除不知道怎么删除&#xff0c;相信这个问题也困扰了不少人。那么怎样才能批量的删除微信好友&#xff1f;其实不难&#xff0c;可以通过新建标签删除的方式来实现批量删除好友。 怎么批量删除 微信批量删除好友的具体步骤如下&#xff1a; 1、新建标签 首…

《零基础入门学习Python》第056讲:论一只爬虫的自我修养4:网络爬图

今天我们结合前面学习的知识&#xff0c;进行一个实例&#xff0c;从网络上下载图片&#xff0c;话说我们平时闲来无事会上煎蛋网看看新鲜事&#xff0c;那么&#xff0c;熟悉煎蛋网的朋友一定知道&#xff0c;这里有一个 随手拍 的栏目&#xff0c;我们今天就来写一个爬虫&…

Spring依赖注入方式,自动装配及自动装配特征

Spring依赖注入方式 一、setter注入1.1简单类型1.2引用类型&#xff08;基本数据类型与String&#xff09; 二、构造器注入1.1简单类型1.2引用类型&#xff08;基本数据类型与String&#xff09; 三、依赖注入方式选择四、自动装配依赖自动装配特征 总结 一、setter注入 依赖注…

【ARMv8 SIMD和浮点指令编程】NEON 移位指令——左右移位之术

NEON 移位指令主要涉及逻辑移位、算术移位两大类,同时下面还介绍了两个移位插入指令。 一、逻辑移位 1.1 SHL 左移(立即数)。该指令从向量中读取每个值,将每个结果左移一个立即值,将最终结果写入向量,并将向量写入目标 SIMD&FP 寄存器。 标量 SHL <V><d…

SQL注入--题目

联合查询注入&#xff1a; bugku-这是一个神奇的登录框 手工注入&#xff1a; 点吧&#xff0c;输入0’发现还是&#xff1a; 输入0" 发现报错&#xff1a; 确定可以注入&#xff0c;判断字段有多少个 0"order by 1,2,3# 发现&#xff1a; 说明有两列。 输入 0&qu…

ARM day8 key1/2/3led

key_led.h #ifndef _KEY_H_ #define _KEY_H_#include "stm32mp1xx_rcc.h" #include "stm32mp1xx_gpio.h" #include "stm32mp1xx_exti.h" #include "stm32mp1xx_gic.h"//EXTI编号 typedef enum {EXTI0,EXTI1,EXTI2,EXTI3,EXTI4,EXTI5,…

陪诊小程序软件|陪诊系统定制|医院陪诊小程序

开发一个陪诊小程序需要投入一定的费用&#xff0c;具体金额会因项目的复杂程度、功能需求和推广政策而有所差异在投入资金之前&#xff0c;建议进行市场调研和需求分析&#xff0c;制定出合理的预算&#xff0c;并选择专业的开发团队进行合作&#xff0c;那么开发陪诊小程序需…

SpringBoot-6

Spring Boot 中的 MVC 支持 Spring Boot 的 MVC 支持主要来最常用的几个注解&#xff0c;包括RestController 用于声明控制器、RequestMapping用于实现方法映射地址、PathVariable 用于接受路径中的参数、RequestParam 用于接受 request 请求中的参数以及RequestBody 用于接受…