数据结构与算法_二叉树(BST树)_面试题总结

news2025/8/8 20:39:30

这篇笔记记录二叉树相关的常考题。

1 BST树区间元素搜索问题

**解决方法:**利用BST树的中序遍历,中序遍历后输出的是从小到大的顺序。

	// 求满足区间的元素值 [i,j];
	void findValues(vector<T> &vec, int i, int j)
	{
		// 封装一个递归接口 
		findValues(root_, vec, i, j);
	
	}

	void findValues(Node *node, vector<T> &vec,int i,int j)
	{
		if (node != nullptr)
		{
			if (node->data_ > i) // BAT中当前节点值大于左子树中任何一个值,所以,当前节点的值小于区间下界不用访问; 
			{
				findValues(node->left_, vec, i, j);
			}
			
			// V 
			if (node->data_ >= i && node->data_ <= j)
			{
				vec.push_back(node->data_); // 存储满足区间元素的值
			}
			// 当前节点的右子树中。

			// BST树中当前节点的值小于右子树中的值;
			// 所以如果当前值区间上届j,所以当前节点小于j才访问,大于则不访问
			if (node->data_ < j)
			{
				findValues(node->right_, vec, i, j);
			}
		}
	}

2 判断二叉树是否是一颗BST树

这道题根据BST树的定义:
BST树称为一颗搜索树或者二叉排序树,它或者是一颗空树;或者具有下列性质:
1 、若左子树不为空,则左子树上所有节点的值均小于它的根节点的值
2 、若右子树不为空,则右子树上所有节点的值均大于它的根节点的值
3 、左右子树也分别满足二叉搜索树性质
特点 :每一个节点都满足 左孩子的值(不为空) < 父节点的值 < 右孩子的值(不为空)
在这里插入图片描述

		bool isBSTree()
	{
		Node *pre = nullptr;
		return isBSTree(root_, pre);
	}
	/*
	*	功能:判断二叉树是否为BST树
	*	思想:利用BST中序遍历后,按照升序的顺序。
	*	参数:
	*		 node: 当前处理的节点
	*		 &pre: 传递当前节点的引用
	*/
	bool isBSTree(Node *node, Node *&pre)
	{
		if (node == nullptr)
		{
			return true;
		}

		if (!isBSTree(node->left_, pre))  // 如果当前节点的左孩子节点与前序
		{
			return false;
		}

		if (pre != nullptr)		// 根节点的pre无法确认,所以判断根节点的pre是否为空
		{
			if (comp_(node->data_, pre->data_))
			{
				return false;
			}
		}
		pre = node;	 // 更新中序遍历的前驱节点

		return isBSTree(node->right_, pre);
	
	}

3 BST求子树问题

思想:先从大树中找到子树中的根节点,然后依次判断小树种根节点的左右子树。

bool isChildTree(BSTree<T, Comp> & child)
	{
		// 在当前二叉树找child根节点 
		if (child.root_ == nullptr)
		{
			return true;
		}

		Node *cur = root_;
		// 这个循环是为了在大树中找到与小树根节点相同的根节点
		while (cur != nullptr)
		{
			if (cur->data_ == child.root_->data_)
			{
				break;
			}
			else if (comp_(cur->data_,child.root_->data_))
			{
				cur = cur->right_;
			}
			else
			{
				cur = cur->left_;
			}
		}

		if (cur == nullptr)
		{
			return false;
		}

		return isChildTree(cur, child.root_);
	}
	
	/*
	*	功能:判断小树是否为大树的子树
	*
	*	参数:
	*		 father: 大树中的节点	
	*		 child : 小树中的节点
	*/
	bool isChildTree(Node *father, Node *child)
	{
		if (father == nullptr && child == nullptr)  // 如果孩子节点和父节点都是空
		{
			return true;
		}

		if (father == nullptr)	// 如果只有父节点是空,说明大树中不包含小树
		{
			return false;
		}

		if (child == nullptr)
		{
			return true;
		}

		// 判断大树与小树的根节点是否相同
		if (father->data_ != child->data_)
		{
			return false;
		}
	
		//return isChildTree(father->left_, child->left_) && isChildTree(father->right_, child->right_);
		if (isChildTree(father->left_, child->left_) && isChildTree(father->right_, child->right_))
		{
			return true;
		}
		else
		{
			return false;
		}
		
	}

4 BST的LCA(least Comment Ancestors,最近公共祖先问题) 问题:求寻找最近公共祖先节点

公共节点判断:如果当前节点介于val1和val2之间,就认为是LCA;
在这里插入图片描述

	/*
	*	功能:最近公共祖先节点 
	*
	*	参数:
	*		val1: 二叉树中的节点1
	*		val2: 二叉树中的节点2
	*/
	int getLCA(int val1, int val2)
	{
		Node * node = getLCA(root_, val1, val2);
		if (node == nullptr)
		{
			throw "no LCA";
		}
		else
		{
			return node->data_;
		}
	}	}
	}
Node * getLCA(Node *node,int  val1,int val2)
	{
		if (node == nullptr)
		{
			return nullptr;
		}

		// 如果当前节点 小于两个节点 
		if (comp_(node->data_, val1) && comp_(node->data_, val2))
		{
			return getLCA(node->right_, val1, val2);
		}
		else if (comp_(val1, node->data_) && comp_(val2, node->data_))
		{
			return getLCA(node->left_, val1, val2);
		}
		else
		{
			return node;
		}
	}

5 二叉树镜像对称问题

思想:node1的左孩子节点与node2的右孩子节点相同;node2的左孩子节点与node1的右孩子节点相同。
在这里插入图片描述

	bool mirror02(Node *node1, Node *node2)
	{
		if (node1 == nullptr && node2 == nullptr)
		{
			return true;
		}
		if (node1 == nullptr || node2 == nullptr) // 如果有一个不对称,则认为是非对称的。
		{
			return false;
		}

		if (node1->data_ != node2->data_)
		{
			return false;
		}
						// 同时满足,一个node1的左孩子等于node2的右孩子,node2的右孩子等于node1的左孩子
		return mirror02(node1->left_, node2->right_) && mirror02(node1->right_, node2->left_);
	}

6 根据前序和中序重构二叉树

在这里插入图片描述

   /*	功能:根据前序中序序列,构建二叉树
	*
	*   参数:
	*		 pre: 前序遍历序列
	*	     i  : 前序序列中的开始索引 , i+1 --- i + (k-m) 左子树中的节点
	*		 j  : 前序序列中的末尾索引	  i + (k-m)+1 --- j 右子树的节点
	*		 in :中序遍历序列	, k表示中序序列中根节点的索引下标。
	*		 m  : 中序序列中的开始索引   m --- k-1:中序左子树中节点
	*		 n  : 中序序列中的末尾索引   k+1 --- n : 中序右子树中节点
	*/
	Node * _rebuild(int pre[], int i, int j,int in[], int m, int n)
	{
		if (i > j || m > n)
		{
			return nullptr;
		}
			// 递归时候只需考虑当前节点以及当前节点的左右孩子节点。
		Node *node = new Node(pre[i]);  // 先根据pre序列中的第一个i节点,创建新树的根节点。
		for (int k = m; k <= n; ++k)	// 在中序中找根节点的左右孩子
		{
			if (pre[i] == in[k])		// 在中序中找子树根节点的下标k;
			{							
				node->left_ = _rebuild(pre, i + 1, i + (k - m),in, m, k - 1);
				node->right_ = _rebuild(pre, i + (k - m) + 1, j, in, k + 1, n);
				return node;
			}
		}

		return node;
	}

7 判断一颗二叉树是否为平衡二叉树

平衡: 任意节点的左右子树高度差,不能查过1 (0 1 -1 )
什么时候检测呢?递归回溯的时候;

	/*	功能:判断一颗二叉树是否平衡二叉树
	*
	*	参数:
	*		node: 节点
	*	     l  : 记录层数
	*		flag: 记录是否平衡二叉树
	*/
	int isBalance(Node *node, int l, bool &flag)
	{
		if (node == nullptr)
		{
			return l;
		}
	
		int left = isBalance02(node->left_, l + 1, flag);
		int right = isBalance02(node->right_, l + 1, flag);

		if (abs(left - right) > 1)
		{
			flag = false;
		}
		return max(left, right);
	}

8 二叉树镜像翻转问题

问题描述:求镜子中的二叉树。
思想:递归处理遍历节点时候,交换根节点的左右节点。
在这里插入图片描述

	/*	功能:求镜子中的二叉树
	*	思想:节点的左右孩子交换位置
	*	参数:
	*		  Node: 当前节点
	*/
	void mirror01(Node *node)
	{
		if (node == nullptr)
		{
			return;
		}
		// 处理V节点
		Node *tmp = node->left_;
		node->left_ = node->right_;
		node->right_ = tmp;
		
		mirror01(node->left_);
		mirror01(node->right_);
	}

9 求中序遍历倒数第K个节点

思想:将中序遍历LVR 转为 RVL,将求倒数第K个节点转为在RVL中求正数第k个节点

	/*	功能:求中序倒数第K个节点
	*	思想:将中序遍历LVR 转为 RVL,将求倒数第K个节点转为在RVL中求正数第k个节点
	*	参数:
	*		 node : 节点
	*		    k : 找到正数第K个元素
	*/

	int i = 1;
	Node *getVal(Node * node, int k)
	{
		if (node == nullptr)
		{
			return nullptr;
		}

		Node *right = getVal(node->right_, k);	// R
		if (right != nullptr)					// V
		{
			return right;
		}
		if (i++ == k)
		{
			return node;
		}

		return getVal(node->left_, k);			// L
	}

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

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

相关文章

精华推荐 | 【深入浅出RocketMQ原理及实战】「性能原理挖掘系列」透彻剖析贯穿RocketMQ的系统服务底层原理以及高性能存储设计挖掘深入

设计背景 消息中间件的本身定义来考虑&#xff0c;应该尽量减少对于外部第三方中间件的依赖。一般来说依赖的外部系统越多&#xff0c;也会使得本身的设计越复杂&#xff0c;采用文件系统作为消息存储的方式。 RocketMQ存储机制 消息中间件的存储一般都是利用磁盘&#xff0…

基于node.js的学生管理系统设计

目 录 摘 要 I Abstract II 第1章 绪论 1 1.1选题背景和意义 1 1.1.1选题背景 1 1.1.2选题意义 1 1.2国内外研究现状、发展动态 2 1.2.1国内研究现状 2 1.2.2国外研究现状 3 1.2.3发展动态 3 1.3研究内容 4 第2章 Node.js软件说明 5 2.1 Node.js概述 5 2.2 Node.js的模块 6 2.3…

语义信息概述

语义信息概述 什么叫语义信息 无论在图像&#xff0c;文本&#xff0c;语音处理领域等&#xff0c;我们常看到一个词&#xff0c;“语义信息”。&#xff08;有意义的数据提供的信息&#xff09; 维基百科中的解释&#xff1a; 语义信息&#xff08;英语&#xff1a;semantic…

【基础算法Ⅰ】算法入门篇

目录 进入算法世界 1.输入输出 1.1输入输出 1.2快读 2.位运算 2.1运算符 2.2位运算 3.枚举 3.1枚举的引入 3.2枚举的简单理解 3.3枚举简介 3.4 枚举算法实例 算法复杂度 时间复杂度 进入算法世界 瑞士著名的科学家Niklaus Wirth教授曾提出&#xff1a;数据结构算…

在C#方法中 out、ref、in、params 关键字的小结

out&#xff1a;关键字&#xff1a; 指定的参数在进入函数时会清空自己&#xff0c;必须在函数内部赋初值 ref关键字&#xff1a; 指定的参数必须在进入函数时赋初值&#xff0c;在函数内部可以重新赋值 In关键字&#xff1a; 指定的参数必须在进入函数时赋初值&#xff0c;…

C++入门教程||C++while循环

whlie 语法 C 中 while 循环的语法&#xff1a; while(condition) {statement(s); } 在这里&#xff0c;statement(s) 可以是一个单独的语句&#xff0c;也可以是几个语句组成的代码块。condition 可以是任意的表达式&#xff0c;当为任意非零值时都为真。当条件为真时执行…

Java.md

sa一、基础篇 网络基础 TCP三次握手 1、OSI与TCP/IP 模型2、常见网络服务分层3、TCP与UDP区别及场景4、TCP滑动窗口&#xff0c;拥塞控制5、TCP粘包原因和解决方法6、TCP、UDP报文格式 HTTP协议 1、HTTP协议1.0_1.1_2.02、HTTP与HTTPS之间的区别3、Get和Post请求区别4、HTTP常见…

Python实现BP神经网络ANN单隐层回归模型项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 20世纪80年代中期&#xff0c;David Runelhart。Geoffrey Hinton和Ronald W-llians、DavidParker等人分…

SpringCloud 组件Gateway服务网关【gateway快速入门】

目录 1&#xff1a;Gateway服务网关 1.1&#xff1a;为什么需要网关 1.2&#xff1a;gateway快速入门 1&#xff09;&#xff1a;创建gateway服务&#xff0c;引入依赖 2&#xff09;&#xff1a;编写启动类 3&#xff09;&#xff1a;编写基础配置和路由规则 4&#xf…

啥牌子的无线蓝牙耳机好用?无线蓝牙耳机推荐2022

蓝牙耳机这几年技术越好越高&#xff0c;其最大的魅力就是随时随地听音乐&#xff0c;无论是上下班还是日常使用&#xff0c;出门携带也方便&#xff0c;市面上的蓝牙耳机众多&#xff0c;很多人不知道该如何选择&#xff0c;下面整理了几款音质清晰&#xff0c;综合性能优秀的…

分享25个JSP源码,总有一款适合您

链接&#xff1a;https://pan.baidu.com/s/17ug7A_b2nHgu-x1K-GIVlQ?pwd6367 提取码&#xff1a;6367 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c;大家下载后可以看到。 renren-security轻量级权限管理系统 renr…

Linux C应用编程-1-文件IO

1.open与close #include <stdio.h> //IO操作需要包含的头文件 #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h>char filename[] "text.txt";int main(void) {int fd;fd open(filename, O_RD…

systemd 252 如预期的锁定了 Linux 引导过程

导读今天给大家介绍一下systemd 252锁定 Linux 引导过程systemd 252 如预期的锁定了 Linux 引导过程 之前&#xff0c;我们 报道 过&#xff0c;systemd 创始人发文指出 Linux 引导过程不安全&#xff0c;并提出采用加密签名的统一内核镜像&#xff08;UKI&#xff09;&#x…

SA实战 · 《SpringCloud Alibaba实战》第02章-专栏设计

作者:冰河 星球:http://m6z.cn/6aeFbs 博客:https://binghe001.github.io 文章汇总:https://binghe001.github.io/md/all/all.html 大家好,我是冰河~~ 从今天开始,我们正式进入《SpringCloud Alibaba实战》专栏的学习,在《开篇》一文中,我们大体介绍了整个专栏的结构安…

html一个案例学会所有常用HTML(H5)标签

目录 前言 HTML5声明 HTML框架 head头部 声明编码格式 告诉IE浏览器&#xff0c;IE8/9及以后的版本都会以最高版本IE来渲染页面。 移动端适配 网站标题 网站正文 网站内容的组成 文字有关标签 音频视频标签 表单标签与input属性 前言 HTML没有什么难度&#xf…

计算机网络笔记6应用层

前言 站在巨人的肩膀上&#xff0c;让知识的获得更加容易&#xff01;本文为学习计算机网络后,自顶向下的学习笔记&#xff1b; 学习视频来源&#xff1a; 计算机网络微课堂&#xff08;有字幕无背景音乐版&#xff09;课件pdf来源&#xff1a;评论区up bili_68567544整理目录…

Linux(基于Centos7)(三)

文章目录一、任务介绍二、任务实施2-1、管理用户账号与密码2-2、用户组管理一、任务介绍 知识目标 1.了解用户角色的类型。 2.理解用户和用户组的关系。 3.了解用户账号文件、用户密码文件和用户组账号文件。 能力目标 1.能够通过命令来创建和管理用户与用户组。 2.能够通过命…

面向对象编程·下

面向对象编程下⭐小提问解答⭐3.多态3.1向上转型 - 父类引用子类对象3.1.1方法传参3.1.2方法返回3.2动态绑定3.3方法重写3.4理解多态3.5向下转型 - 子类引用父类对象3.6super 关键字3.7在构造方法中调用重写的方法(一个坑)3.8总结4.抽象类4.1语法规则4.2抽象类的作用5.接口5.1语…

基于2D连续图像序列的行人骨架关节角度估计

目 录 第1章 绪 论 1 1.1 行人骨架关节角度估计 1 1.2 行人骨架关节角度估计的应用领域 2 1.3 行人骨架关节角度估计方法简述 3 1.3. 1 基于概率统计的方法 3 1.3.2 基于语法的方法 4 1.3.3 基于模型的方法 4 1.4 行人骨架关节角度估计的难点和面临的挑战 5 1.5 本文的研究意义…

xinput1_4.dll丢失怎么修复?修复方法分享

对于电脑系统来说牵一发而动全身。电脑系统当中的任何一个小小的文件都关系着整个电脑系统的运行&#xff0c;大家都明白&#xff0c;电脑系统以及很多的大型系统软件都是安装在电脑C盘当中的&#xff0c;所以C盘也叫做系统盘&#xff0c;系统盘中有很多非常重要的软件&#xf…