漫画讲解C语言中最近公共祖先的三种类型

 更新时间:2021年11月24日 09:06:22   作者:2021dragon  
这篇文章主要总结了使用C语言查找最近公共祖先的三种方法类型,用漫画的方式讲解原理定义,看上去更生动形象,帮助你更好的理解透彻,快来跟着本文往下看吧

在这里插入图片描述

在这里插入图片描述

最近公共祖先定义

在这里插入图片描述

在这里插入图片描述

查找最近公共祖先

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

三叉链

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

代码如下:

//三叉链
struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
	TreeNode *parent;
    TreeNode(int x) : val(x), left(NULL), right(NULL), parent(NULL) {}
};
class Solution {
public:
	TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
		TreeNode* curp = p, *curq = q; //用于遍历p、q结点的祖先结点
		int lenp = 0, lenq = 0; //分别记录p、q结点各自的祖先结点个数
		//统计p结点的祖先结点个数
		while (curp != root)
		{
			lenp++;
			curp = curp->parent;
		}
		//统计q结点的祖先结点个数
		while (curq != root)
		{
			lenq++;
			curq = curq->parent;
		}
		//longpath和shortpath分别标记祖先路径较长和较短的结点
		TreeNode* longpath = p, *shortpath = q;
		if (lenp < lenq)
		{
			longpath = q;
			shortpath = p;
		}
		//p、q结点祖先结点个数的差值
		int count = abs(lenp - lenq);
		//先让longpath往上走count个结点
		while (count--)
		{
			longpath = longpath->parent;
		}
		//再让longpath和shortpath同时往上走,此时第一个相同的结点便是最近公共祖先结点
		while (longpath != shortpath)
		{
			longpath = longpath->parent;
			shortpath = shortpath->parent;
		}
		return longpath; //返回最近公共祖先结点
	}
};

二叉搜索树

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

代码如下:

//搜索二叉树
struct TreeNode {
	int val;
	TreeNode *left;
	TreeNode *right;
	TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
class Solution {
public:
	TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
		if (p->val == root->val || q->val == root->val) //p、q结点中某一个结点的值等于根结点的值,则根结点就是这两个结点的最近公共祖先
			return root;
		if (p->val < root->val&&q->val < root->val) //p、q结点的值都小于根结点的值,说明这两个结点的最近公共祖先在该树的左子树当中
			return lowestCommonAncestor(root->left, p, q);
		else if (p->val > root->val&&q->val > root->val) //p、q结点的值都大于根结点的值,说明这两个结点的最近公共祖先在该树的右子树当中
			return lowestCommonAncestor(root->right, p, q);
		else //p、q结点的值一个比根小一个比根大,说明根就是这两个结点的最近公共祖先
			return root;
	}
};

普通二叉树

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

代码如下:

//普通二叉树
struct TreeNode {
	int val;
	TreeNode *left;
	TreeNode *right;
	TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
class Solution {
public:
	bool Find(TreeNode* root, TreeNode* x)
	{
		if (root == nullptr) //空树,查找失败
			return false;
		if (root == x) //查找成功
			return true;

		return Find(root->left, x) || Find(root->right, x); //在左子树找到了或是右子树找到了,都说明该结点在该树当中
	}
	TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
		if (p == root || q == root) //p、q结点中某一个结点为根结点,则根结点就是这两个结点的最近公共祖先
			return root;
		//判断p、q结点是否在左右子树
		bool IspInLeft, IspInRight, IsqInLeft, IsqInRight;
		IspInLeft = Find(root->left, p);
		IspInRight = !IspInLeft;
		IsqInLeft = Find(root->left, q);
		IsqInRight = !IsqInLeft;

		if (IspInLeft&&IsqInLeft) //p、q结点都在左子树,说明这两个结点的最近公共祖先也在左子树当中
			return lowestCommonAncestor(root->left, p, q);
		else if (IspInRight&&IsqInRight) //p、q结点都在右子树,说明这两个结点的最近公共祖先也在右子树当中
			return lowestCommonAncestor(root->right, p, q);
		else //p、q结点一个在左子树一个在右子树,说明根就是这两个结点的最近公共祖先
			return root;
	}
};

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

看着似乎不太好理解,来看看下面的动图演示:

在这里插入图片描述

代码如下:

//普通二叉树
struct TreeNode {
	int val;
	TreeNode *left;
	TreeNode *right;
	TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
class Solution {
public:
	bool FindPath(TreeNode* root, TreeNode* x, stack<TreeNode*>& path)
	{
		if (root == nullptr)
			return false;
		path.push(root); //该结点可能是路径当中的结点,先入栈

		if (root == x) //该结点是最终结点,查找结束
			return true;

		if (FindPath(root->left, x, path)) //在该结点的左子树找到了最终结点,查找结束
			return true;
		if (FindPath(root->right, x, path)) //在该结点的右子树找到了最终结点,查找结束
			return true;

		path.pop(); //在该结点的左右子树均没有找到最终结点,该结点不可能是路径当中的结点,该结点出栈
		return false; //在该结点处查找失败
	}
	TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
		stack<TreeNode*> pPath, qPath;
		FindPath(root, p, pPath); //将从根到p结点的路径存放到pPath当中
		FindPath(root, q, qPath); //将从根到q结点的路径存放到qPath当中
		//longpath和shortpath分别标记长路径和短路径
		stack<TreeNode*>* longPath = &pPath, *shortPath = &qPath;
		if (pPath.size() < qPath.size())
		{
			longPath = &qPath;
			shortPath = &pPath;
		}
		//让longPath先弹出差值个数据
		int count = longPath->size() - shortPath->size();
		while (count--)
		{
			longPath->pop();
		}
		//longPath和shortPath一起弹数据,直到两个栈顶的结点相同
		while (longPath->top() != shortPath->top())
		{
			longPath->pop();
			shortPath->pop();
		}
		return longPath->top(); //返回这个相同的结点,即最近公共祖先
	}
};

在这里插入图片描述

到此这篇关于漫画讲解C语言中最近公共祖先的三种类型的文章就介绍到这了,更多相关C语言 公共祖先内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++中关键字 override 的简析

    C++中关键字 override 的简析

    这篇小文来聊聊 C++中的关键字 override,它的含义其实两句话就说完了,但为了叙述的完整性,让我们从虚函数说起。感兴趣的小伙伴可以跟着小编一起学习下面文章内容
    2021-09-09
  • 利用QDir实现删除选定文件目录下的空文件夹

    利用QDir实现删除选定文件目录下的空文件夹

    这篇文章主要为大家详细介绍了如何利用QDir实现删除选定文件目录下的空文件夹功能,文中的示例代码讲解详细,感兴趣的小伙伴可以动手尝试一下
    2022-08-08
  • C语言const关键字的用法详解

    C语言const关键字的用法详解

    今天探讨const,首先来说是将变量常量化。为什么要将变量常量化,原因有诸多好处有诸多。比如可以使数据更加安全不会被修改
    2022-08-08
  • Qt音视频开发之视频文件保存功能的实现

    Qt音视频开发之视频文件保存功能的实现

    和音频存储类似,视频的存储也对应三种格式,视频最原始的数据是yuv(音频对应pcm),视频压缩后的数据是h264(音频对应aac)。本文将利用Qt实现视频文件保存功能,感兴趣的可以了解一下
    2022-12-12
  • 关于C++中0是十进制还是八进制的问题

    关于C++中0是十进制还是八进制的问题

    本篇文章中,小编将为大家介绍关于C++中0是十进制还是八进制的问题,有需要的朋友可以参考一下
    2013-04-04
  • C语言基础全局变量与局部变量教程详解

    C语言基础全局变量与局部变量教程详解

    此处对于全局与局部做一些简要的介绍,包括全局变量与局部变量,静态全局变量与静态局部变量,全局函数与静态函数,作者实属初学,文中若有理解不当之处,还请朋友们不吝指正
    2021-11-11
  • C++11语法之右值引用的示例讲解

    C++11语法之右值引用的示例讲解

    右值引用,一般是在深拷贝的类,实现移动构造和移动赋值,能够解决左值引用无法做到的传返回值的效率问题,下面跟随小编一起学习下C++11语法之右值引用的问题
    2022-04-04
  • C++中的内存对齐实例详解

    C++中的内存对齐实例详解

    这篇文章主要介绍了C++中的内存对齐实例详解的相关资料,这里不仅提供实现方法及代码还提供了手工制作图,来帮助到大家理解这部分知识,需要的朋友可以参考下
    2017-07-07
  • C++实现一个简易版的事件(Event)的示例代码

    C++实现一个简易版的事件(Event)的示例代码

    之前在 windows系统中开发应用时, 遇到需要进行线程同步的时候几乎都是使用的事件内核对象 Event。本文为大家整理了C++实现一个简易版的事件(Event)的相关资料,需要的可以参考一下
    2022-11-11
  • 用C语言实现猜数字游戏

    用C语言实现猜数字游戏

    这篇文章主要为大家详细介绍了用C语言实现猜数字游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-10-10

最新评论