【数据结构】二叉树经典题目

这篇具有很好参考价值的文章主要介绍了【数据结构】二叉树经典题目。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 二叉树创建字符串

相信大部分人看了题目描述之后,都会和我一样一脸的懵逼。直到我看到了一个描述才恍然大悟
【数据结构】二叉树经典题目
分为3种情况:

  1. 左右都为空 --省略
  2. 右为空,左不为空 – 省略
  3. 左为空,右不为空–不省略

这里复习一下二叉树的前序遍历、中序遍历、和后序遍历
【数据结构】二叉树经典题目
前序的结果是:ABDEGCF
中序的结果是:DBGEACF
后序的结果是:DGEBFCA

class Solution {
public:
	string tree2str(TreeNode* root) {
		if (root == nullptr)
		{
			return "";
		}
		string str = to_string(root->val);
		if (root->left || root->right) // 特别注意这个条件
		{
			str += "(";
			str += tree2str(root->left);
			str += ")";
		}
		if (root->right)
		{
			str += "(";
			str += tree2str(root->right);
			str += ")";
		}
		return str;
	}
};

2. 二叉树的层序遍历

【数据结构】二叉树经典题目

思路大致是这样的:
一个队列,接着一个levelSize来记录每层有几个数据,如果这个数字是0,则表示这层的数据出完

【数据结构】二叉树经典题目
出3将9和20带到队列,levelSize为2 。如此循环下去。
如果这个队列不为空,就一直循环下去,直到这个队列为空为止。
代码实现:

class Solution {
public:
	vector<vector<int>> levelOrder(TreeNode* root) {
		queue<TreeNode*> q;
		int levelSize = 0;
		if (root)
		{
			q.push(root);
			levelSize = 1;
		}
		vector<vector<int>> vv;
		while (!q.empty()) // 如果队列不为空,就继续
		{
			// 通过levelSize控制一层一层的出
			vector<int> v;
			while (levelSize--)
			{
				TreeNode* front = q.front();
				q.pop();
				v.push_back(front->val);
				if (front->left)
				{
					q.push(front->left);
				}
				if (front->right)
				{
					q.push(front->right);
				}
			}
			vv.push_back(v);
			// 更新下一层的个数
			levelSize = q.size();
		}
		return vv;
	}
};

3. 二叉树的层序遍历Ⅱ

【数据结构】二叉树经典题目
这个题目与上一题目,差不多,我们只需要将最后的答案逆置即可

4. 二叉树的最近公共祖先

【数据结构】二叉树经典题目
【数据结构】二叉树经典题目
思路一:公共祖先的特征,如果一个在左子树,一个在右子树。那么这个节点就是公共祖先。

class Solution {
public:
	bool isInTree(TreeNode* root, TreeNode* x) {
		if (root == nullptr) {
			return false;
		}
		return x == root
			|| isInTree(root->left, x)
			|| isInTree(root->right, x);
	}
	TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
		if (root == nullptr) {
			return nullptr;
		}
		if (p == root || q == root) {
			return root;
		}
		// 判断p节点是在root的左边还是右边
		bool pInLeft = isInTree(root->left, p);
		bool pInRight = !pInLeft;
		// 判断q节点是在root的左边还是右边
		bool qInLeft = isInTree(root->left, q);
		bool qInRight = !qInLeft;

		if ((pInLeft && qInRight) || (pInRight && qInLeft)) {
			return root;
		}
		// 如果都在左边,则转换为在左树寻找公共祖先
		else if (pInLeft && qInLeft) {
			return lowestCommonAncestor(root->left, p, q);
		}
		else {
			return lowestCommonAncestor(root->right, p, q);
		}
	}
};

思路二:公共祖先的特征,如果一个在我的左子树,一个在我的右子树,我就是公共祖先
如果是搜索二叉树可以优化到O(N)

  1. 一个比根小,一个比根大,根就是公共祖先
  2. 都比根小,递归左树查找
  3. 都比根大,递归右树查找
    但是这个题目我们并不是搜索二叉树,要求优化到O(N)
    这里只能使用另外一种思路,将p和q的路径求出来,放到容器当中,转换为路径相交问题
class Solution {
public:
	bool getPath(TreeNode* root, TreeNode* x, stack<TreeNode*>& path) {
		if (root == nullptr) {
			return false;
		}
		path.push(root);
		if (root == x) {
			return true;
		}
		if (getPath(root->left, x, path)) {
			return true;
		}
		if (getPath(root->right, x, path)) {
			return true;
		}
		path.pop();
		return false;
	}
	TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
		stack<TreeNode*> pPath, qPath;
		getPath(root, p, pPath);
		getPath(root, q, qPath);
		while (pPath.size() != qPath.size()) {
			if (pPath.size() > qPath.size()) {
				pPath.pop();
			}
			else {
				qPath.pop();
			}
		}
		while (pPath.top() != qPath.top()) {
			pPath.pop();
			qPath.pop();
		}
		return pPath.top();
	}
};

上述代码的关键在于找到每个节点的路径

5. 二叉搜索树与双向链表

【数据结构】二叉树经典题目
看到这个题目我们的第一个想法可能是把所有的节点拿出来,然后尾插到一个双向链表上,其实并没有这么简单,我们能够想到的出题人当然也能够想到。
这个题目有以下几个要求:
【数据结构】二叉树经典题目
我们需要在原树上进行操作。

class Solution {
public:
	void inorderTraversal(TreeNode* cur, TreeNode*& prev) {
		if (cur == nullptr) {
			return;
		}
		inorderTraversal(cur->left, prev);
		cur->left = prev;
		if (prev) {
			prev->right = cur;
		}
		prev = cur;
		inorderTraversal(cur->right, prev);
	}
	TreeNode* Convert(TreeNode* pRootOfTree) {
		TreeNode* prev = nullptr;
		inorderTraversal(pRootOfTree, prev);
		TreeNode* head = pRootOfTree;
		while (head && head->left) {
			head = head->left;
		}
		return head;
	}
};

【数据结构】二叉树经典题目
以上的这幅图是精髓所在

6. 从前序与中序遍历序列构造二叉树

【数据结构】二叉树经典题目
【数据结构】二叉树经典题目

class Solution {
public:
	TreeNode* _buildTree(vector<int>& preorder, vector<int>& inorder, int& previ, int inbegin, int inend) {
		if (inbegin > inend) {
			return nullptr;
		}
		TreeNode* root = new TreeNode(preorder[previ]);
		// 分割出左右区间
		int rooti = inbegin;
		while (rooti <= inend) {
			if (inorder[rooti] == preorder[previ]) {
				break;
			}
			else {
				rooti++;
			}
		}
		++previ;
		// [inbegin, rooti - 1], rooti, [rooti + 1, inend]
		root->left = _buildTree(preorder, inorder, previ, inbegin, rooti - 1);
		root->right = _buildTree(preorder, inorder, previ, rooti + 1, inend);
		return root;
	}
	TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
		int i = 0;
		return _buildTree(preorder, inorder, i, 0, inorder.size() - 1);
	}
};

7. 二叉树的前序遍历(非递归)

【数据结构】二叉树经典题目

class Solution {
public:
	vector<int> preorderTraversal(TreeNode* root) {
		stack<TreeNode*> st;
		TreeNode* cur = root;
		vector<int> v;
		while (cur || !st.empty()) {
			// 1. 开始访问一棵树
			// 2. 左路节点
			// 3. 左路节点的右子树
			while (cur) {
				v.push_back(cur->val);
				st.push(cur);
				cur = cur->left;
			}
			// 访问右子树
			TreeNode* top = st.top();
			st.pop();
			// 子问题访问右子树
			cur = top->right;// 这个地方非常重要
		}
		return v;
	}
};

8. 二叉树的中序遍历(非递归)

class Solution {
public:
	vector<int> inorderTraversal(TreeNode* root) {
		stack<TreeNode*> st;
		TreeNode* cur = root;
		vector<int> v;
		while (cur || !st.empty()) {
			while (cur) {
				st.push(cur);
				cur = cur->left;
			}
			// 栈里面取到左路节点,左路节点的左子树访问完了
			TreeNode* top = st.top();
			st.pop();
			v.push_back(top->val);

			cur = top->right;
		}
		return v;
	}
};

8. 二叉树的后序遍历(非递归)

class Solution {
public:
	vector<int> postorderTraversal(TreeNode* root) {
		stack<TreeNode*> st;
		TreeNode* cur = root;
		vector<int> v;
		TreeNode* prve = nullptr;
		while (cur || !st.empty()) {
			while (cur) {
				st.push(cur);
				cur = cur->left;
			}
			// 栈里面取到左路节点,左路节点的左子树访问完了
			TreeNode* top = st.top();
			// 右为空或者右已经访问过了,可以访问根节点
			if (top->right == nullptr || top->right == prve) {
				v.push_back(top->val);
				st.pop();
				prve = top;
			}
			else {
				cur = top->right;
			}
		}
		return v;
	}
};

这里对非递归的三种代码进行对比:

【数据结构】二叉树经典题目文章来源地址https://www.toymoban.com/news/detail-499083.html

到了这里,关于【数据结构】二叉树经典题目的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【数据结构】二叉树的相关操作以及OJ题目

    当一个树不是满二叉树或完全二叉树时,它是不适合使用数组存储的,它应该使用链式结构来存储。 再看二叉树基本操作前,再回顾下二叉树的概念,二叉树是: 空树 非空:根节点,根节点的左子树、根节点的右子树组成的。 从概念中可以看出,二叉树定义是递归式的,因

    2024年03月19日
    浏览(15)
  • 数据结构:二叉树经典例题(单选题)-->你真的掌握二叉树了吗?(第一弹)

    朋友们、伙计们,我们又见面了,本期来给大家解读一下有关二叉树的经典例题,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成! C 语 言 专 栏: C语言:从入门到精通 数据结构专栏: 数据结构 个  人  主  页 : stackY、 目录 前言: 一、 二、

    2024年02月10日
    浏览(14)
  • 数据结构:二叉树经典例题(单选题)-->你真的掌握二叉树了吗?(第二弹)

     朋友们、伙计们,我们又见面了,本期来给大家解读一下有关二叉树的经典例题,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成! C 语 言 专 栏: C语言:从入门到精通 数据结构专栏: 数据结构 个  人  主  页 : stackY、 ​ 目录   前言: 一、

    2024年02月10日
    浏览(30)
  • 【数据结构入门指南】二叉树顺序结构: 堆及实现(全程配图,非常经典)

    普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。 而完全二叉树更适合使用顺序结构存储。   现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储 ,需要注意的是这里的堆和操作系统虚拟进程地址空间中的堆是两回事,一个是数据结构,一

    2024年02月12日
    浏览(14)
  • 【数据结构入门指南】二叉树链式结构的实现(保姆级代码思路解读,非常经典)

    其他数据结构不同,二叉树的增删查改接口实现的意义不大(后续搜索树的增删查改才有意义)。普通初阶二叉树更重要的是学习控制结构,为后续的AVL树、红黑树等高级数据结构打下基础。同时大部分OJ题也出在此处。 所谓二叉树遍历(Traversal)是按照某种特定的规则,依次

    2024年02月11日
    浏览(14)
  • 数据结构——二叉树的创建与遍历(链式存储结构)

    二叉树(binary tree)是指树中节点的度不大于2的有序树,它是一种最简单且最重要的树。二叉树的递归定义为:二叉树是一棵空树,或者是一棵由一个根节点和两棵互不相交的,分别称作根的左子树和右子树组成的非空树;左子树和右子树又同样都是二叉树。以下是对链式存

    2024年02月05日
    浏览(21)
  • 【数据结构】二叉树的创建和遍历(先序、中序、后序)

    最近一段时间学习了数据结构中二叉树的基本操作,包括二叉树的结构、二叉树的创建、递归先序中序后序遍历、非递归遍历等,想着把二叉树的相关知识和自己的见解放到网上来让网友看看是否正确,想和网友一起共同交流。 先了解一下二叉树的三个基本性质: 性质1:在

    2024年02月04日
    浏览(17)
  • 【数据结构】二叉树的创建和四种遍历(附带详细注释)

    《数据结构系列首页》是数据结构系列文章的首页,其中会 逐步更新 各种数据结构的实现,有兴趣的选手可以一看。 首页中不仅有各种数据结构的实现,还有学习数据结构 必备的基础知识 ,如果有选手觉得自己的基础不太牢固,可以先将搞定基础知识,之后再攻克数据结

    2024年02月05日
    浏览(22)
  • 14-数据结构-二叉树的创建以及前中后遍历,以及结点和叶子节点的计算(C语言)

    概述:         二叉树,这里采用孩子链表存储法,即一个数据域和两个左右孩子指针域。随后递归进行遍历即可。在创建二叉树的时候,先创建各个二叉树结点(这里的结点采用动态分配,因此结点为指针变量),随后,再根据逻辑结构图,手动通过左右指针域,链接到对

    2024年02月11日
    浏览(15)
  • 二叉树经典算法题目

    省略 输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度。 例如: 给定二叉树 [3,9,20,null,null,15,7] , 返回它的最大深度 3 。 思路:递归,当前数的深度等于左子数和右子树其中最大深

    2024年02月09日
    浏览(22)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包