二叉树相关面试题目总结

前言:
一、为什么要树结构? 不像数组、链表是线性的数据结构,树是一种分层的非线性数据结构 (1)使用树的一个原因是:我们需要存储有分层关系的信息(比如说文件系统) (2)另外一个是(BST):当把树建成有一定的形式的树可以方便数据的查找(对于平衡的树,查找时间复杂度为O(logn))。 (3)同理对于这样一个树(AVL/红黑树):他们的插入和删除的时间复杂度是(O(logn)) (4)相对于数组来说,树使用指针操作,可以动态的扩展节点。
二、二叉树的BFS和DFS
1、一个树典型的以两种方式进行遍历:

  • 广度优先遍历(或者层序遍历)
  • 深度优先遍历
  1. 中序遍历
  2. 前序遍历
  3. 后序遍历

2、四种遍历方式的比较 (1)时间复杂度上,上面四种遍历方式都需要O(n)的时间,因为他们都遍历了每一个node (2)空间复杂度上,

  • 对于BFS来说空间复杂度为O(w)其中w是二叉树的最大宽度,在层序遍历的时候,使用队列依次存储不同层次的nodes
  • 对于DFS来说空间复杂度是O(h)其中h是二叉树的最大高度,在深度遍历的时候,使用stack来存储他们的祖先nodes

3、如何选择一种遍历方式? 平衡二叉树的高度为O(logn),最坏的情况下出现倾斜树的时候成为O(n)

  • 额外的空间是一个选择的标准
  • DFS一般使用的是递归的方法,递归方法的函数调用的开销也是一个因素
  • 最重要的是:BFS总是从根节点开始,而DFS更倾向于从叶子节点开始,所以如果我们的问题是寻找查找离根节点很近的话我们要用BFS,反之使用DFS。

三、二叉树的一些特性 (1)第i层上的节点个数是2^(i-1),也就是i层上的节点个数是i-1层上的2倍 (2)第i层之前的所有节点个数是2^i-1;(1+2+4+7+2^(i-1)) (3)如果二叉树也有N个节点,最小可能的高度或者最小的层数是(log2(N+1)) (4)一个二叉树有L个叶子节点那么至少有log2L+1层
《二叉树相关面试题目总结》

(5)二叉树中度为0的节点要比度为2的节点多一个 完全二叉树:
《二叉树相关面试题目总结》

满二叉树(节点只有度为0和度为2,
这里和我之前理解不同!!)
《二叉树相关面试题目总结》

完美二叉树
《二叉树相关面试题目总结》

四、一些习题和代码
注解 1、求二叉树中的节点个数(222)     2、求二叉树的深度(104)             求二叉树的最小深度(111)    
3、前中后序遍历(94/144/145)    
4、分层遍历二叉树(102/107)    
   之字形遍历(103)        
5、将二叉查找树变为有序的双向链表(114)
6、求二叉树第k层节点个数    
7、求二叉树中叶子节点的个数    
8、判断两个二叉树的结构是否相同(100)    
9、判断二叉树是否为平衡二叉树(110)        
10、求二叉树的镜像(226)                
    判断二叉树是否对称(101)            

<span style="line-height: 1.5; font-family: 'Courier New'; background-color: inherit;">11、求二叉树两个节点的最低公共祖先节点(236)</span>

12、求二叉树中节点的最大距离
13、由前序遍历和中序遍历重建二叉树(105)
    由中序和后序遍历重建二叉树(106)
14、判断二叉树是否为完全二叉树() 15、将一个有序数组转化为二叉查找树(108)

#include <iostream>
#include <queue>
#include <vector>
#include <stack>
#include <algorithm>
using namespace std;
struct TreeNode{
	int val;
	TreeNode* left;
	TreeNode* right;
	TreeNode(int n) :val(n), left(nullptr), right(nullptr){}
};

//1、求二叉树中的节点个数
//暴力递归法用于普通的二叉树
int countNodes(TreeNode* root)
{
	if (root == NULL)
		return 0;
	return countNodes(root->left) + countNodes(root->right) + 1;
}
//对于完全二叉树可以使用公式2^h-1
int getleft(TreeNode* root)
{
	int count = 0;
	while (root->left != NULL)
	{
		root = root->left;
		count++;
	}
	return count;
}
int getright(TreeNode* root)
{
	int count = 0;
	while (root->right != NULL)
	{
		root = root->right;
		count++;
	}
	return count;
}
int countNodes2(TreeNode* root)
{
	if (root == NULL)
		return 0;
	int leftcount = getleft(root)+1;
	int rightcount = getright(root)+1;
	if (leftcount == rightcount)
		return (2 << (leftcount-1)) - 1;//这里
	else
		return countNodes2(root->left) + countNodes2(root->right) + 1;
}
//2、求二叉树的深度
//2.1求二叉树的最大深度
int maxDepth(TreeNode* root)
{
	if (root == NULL)
		return 0;
	int maxLeft = maxDepth(root->left);
	int maxRight = maxDepth(root->right);
	return maxLeft > maxRight ? (maxLeft + 1) : (maxRight + 1);
}
//2.2求二叉树的最小深度
int minDepth(TreeNode* root)
{
	if (root == NULL)
		return 0;
	if (root->left == NULL&&root->right == NULL)
		return 1;
	int left = minDepth(root->left);
	int right = minDepth(root->right);
	if (root->left == NULL)
		return right + 1;
	if (root->right == NULL)
		return left + 1;
	return left > right ? (right + 1) : (left + 1);
}
int minDepth2(TreeNode* root)
{
	queue<pair<TreeNode*, int> >q;
	if (root == NULL)
		return 0;
	q.push(make_pair(root, 1));
	while (!q.empty())
	{
		pair<TreeNode*, int> cur = q.front();
		q.pop();
		if (cur.first->left == NULL&&cur.first->right == NULL)//遇到第一个叶子节点的时候返回
			return cur.second;
		if (cur.first->left)
			q.push(make_pair(cur.first->left,cur.second+1));
		if (cur.first->right)
			q.push(make_pair(cur.first->right, cur.second + 1));

	}
}
//3、前中后序遍历
//3.1 递归遍历
vector<int> vec;
vector<int> inorderTraversal(TreeNode* root) {
	
	if (root == NULL)
		return vec;
	inorderTraversal(root->left);
	vec.push_back(root->val);
	inorderTraversal(root->right);
	return vec;
}
vector<int> preorderTraversal(TreeNode* root) {
	if (root == NULL)
		return vec;
	vec.push_back(root->val);
	preorderTraversal(root->left);
	preorderTraversal(root->right);
	return vec;
}
vector<int> postorderTraversal(TreeNode* root) {
	if (root == NULL)
		return vec;
	postorderTraversal(root->left);
	postorderTraversal(root->right);
	vec.push_back(root->val);
	return vec;
}

//3.2非递归版本
vector<int> inorderTraversal(TreeNode* root) {

	stack<TreeNode*> s;
	TreeNode* temp = root;
	while (temp != NULL|| !s.empty())
	{
		while (temp != NULL)
		{
			s.push(temp);
			temp = temp->left;
		}
		if (!s.empty())
		{	
			temp = s.top();
			s.pop();
			vec.push_back(temp->val);
			temp = temp->right;
		}
	}
	return vec;
}
vector<int> preorderTraversal(TreeNode* root) {
	
	stack<TreeNode*> s;
	TreeNode* temp = root;
	while (temp || !s.empty())
	{
		while (temp != NULL)
		{
			vec.push_back(temp->val);
			s.push(temp);
			temp = temp->left;
		}
		if (!s.empty())
		{
			temp = s.top();
			temp = temp->right;
			s.pop();
		}
	}
	return vec;
}
vector<int> postorderTraversal(TreeNode* root) {
	if (root == NULL)
		return vec;
	
	return vec;
}
//4、分层遍历二叉树
//4.1
vector<vector<int>> levelOrder(TreeNode* root) {
	vector<TreeNode*> q;
	vector<vector<int> >res;
	
	if (root != NULL)
	{
		q.push_back(root);
		int cur = 0;
		int last = 1;
		while (cur < q.size())
		{
			last = q.size();
			vector<int> vec;
			while (cur < last)
			{
				vec.push_back(q[cur]->val);
				if (q[cur]->left)
					q.push_back(q[cur]->left);
				if (q[cur]->right)
					q.push_back(q[cur]->right);
				cur++;
			}
			res.push_back(vec);
		}
	}
	return res;
}
//4.2之字形打印二叉树
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
	vector<TreeNode*> q;
	vector<vector<int> >res;

	if (root != NULL)
	{
		q.push_back(root);
		int cur = 0;
		int last = 1;
		int row = 1;
		while (cur < q.size())
		{
			last = q.size();
			vector<int> vec;
			while (cur < last)
			{
				vec.push_back(q[cur]->val);
				if (q[cur]->left)
					q.push_back(q[cur]->left);
				if (q[cur]->right)
					q.push_back(q[cur]->right);
				cur++;
			}
			if (row % 2 == 0)
			{
				reverse(vec.begin(), vec.end());
			}
			row++;
			res.push_back(vec);
		}
	}
	return res;
}
//5、将二叉查找树变为有序的双向链表

//6、求二叉树第k层节点个数
int numOfKthLevel(TreeNode* root, int k)
{
	if (root == NULL || k < 1)
		return 0;
	if (k == 1)
		return 1;
	int numleft = numOfKthLevel(root->left, k - 1);
	int numright = numOfKthLevel(root->right, k - 1);
	return numleft + numright;
}
//7、求二叉树中叶子节点的个数
int numOfLeaf(TreeNode* root)
{
	if (root == NULL)
		return 0;
	bool isleaf = root->left == NULL&&root->right == NULL;
	if (isleaf)
		return 1;
	int numleft = numOfLeaf(root->left);
	int numright = numOfLeaf(root->right);
	return numleft + numright;
}
//8、判断两个二叉树的结构是否相同
bool isSameTree(TreeNode* p, TreeNode* q) {
	if (p == NULL&&q == NULL)
		return true;
	if ((p == NULL&&q != NULL) || (p != NULL&&q == NULL))
		return false;
	if (p->val != q->val)
		return false;
	else
	{
		bool l = isSameTree(p->left, q->left);
		bool r = isSameTree(p->right, q->right);
		if (l&&r)
			return true;
		else return false;
	}
	
}
//9、判断二叉树是否为平衡二叉树
bool isBalanced(TreeNode* root) {
	if (root == NULL)
		return true;
	int* depth = 0;
	return isBalanced2(root, depth);
}
bool isBalanced2(TreeNode* root, int *depth)
{
	if (root == NULL)
	{
		depth = 0;
		return true;
	}
	int nleft, nright;
	bool rl = isBalanced2(root->left, &nleft);
	bool rr = isBalanced2(root->right, &nright);
	if (rl&&rr)
	{
		int diff = nleft - nright;
		if (diff >= -1 && diff <= 1)
		{
			*depth = nleft > nright ? (nleft + 1) : (nright + 1);
			return true;
		}
	}
	return false;
}
//10、求二叉树的镜像
TreeNode* invertTree(TreeNode* root) {
	if (root == NULL)
		return NULL;
	TreeNode* temp = root->left;
	root->left = root->right;
	root->right = temp;
	root->left = invertTree(root->left);
	root->right = invertTree(root->right);
	return root;
}
//10.2判断一个树是否对称
bool isSymmetric(TreeNode* root) {
	if (root == NULL)
		return true;

	return isSymmetric2(root->left, root->right);
}
bool isSymmetric2(TreeNode* root1, TreeNode* root2)
{
	if (root1 == NULL&&root2 == NULL)
		return true;
	if ((root1 != NULL&&root2 == NULL) || (root1 == NULL&&root2 != NULL))
		return false;
	if (root1->val != root2->val)
		return false;
	bool l = isSymmetric2(root1->left, root2->right);
	bool r = isSymmetric2(root1->right, root2->left);
	return l&&r;
}
//11、求二叉树两个节点的最低公共祖先节点

//12、求二叉树中节点的最大距离

//13、由前序遍历和中序遍历重建二叉树
typedef vector<int>::iterator Iter;
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
	if (preorder.size() == 0 || inorder.size() == 0||preorder.size()!=inorder.size())
		return NULL;
	return buildTree2(preorder.begin(), preorder.end(), inorder.begin(), inorder.end());
	
}
TreeNode* buildTree2(Iter pbegin, Iter pend, Iter ibegin, Iter iend)
{
	if (pbegin == pend || ibegin == iend)
		return NULL;
	TreeNode* root = new TreeNode(*pbegin);
	
	auto iroot = find(ibegin, iend, *pbegin);
	int leftlength = iroot - ibegin;
	root->left = buildTree2(pbegin+1,pbegin+leftlength+1, ibegin,iroot);
	root->right = buildTree2(pbegin + leftlength + 1,pend, iroot+1,iend);

	return root;
}
//由后序和中序重建二叉树
typedef vector<int>::iterator Iter;
TreeNode* buildTree2(Iter pbegin, Iter pend, Iter ibegin, Iter iend)
{
	if (pbegin == pend || ibegin == iend)
		return NULL;
	TreeNode* root = new TreeNode(*(pend - 1));

	auto iroot = find(ibegin, iend, *(pend - 1));
	int leftlength = iroot - ibegin;
	root->left = buildTree2(pbegin, pbegin + leftlength, ibegin, iroot);
	root->right = buildTree2(pbegin + leftlength, pend - 1, iroot + 1, iend);

	return root;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
	if (postorder.size() == 0 || inorder.size() == 0 || postorder.size() != inorder.size())
		return NULL;
	return buildTree2(postorder.begin(), postorder.end(), inorder.begin(), inorder.end());
}
//14、判断二叉树是否为完全二叉树	


//15、将有序数组组成二叉查找树
TreeNode* sortedArrayToBST(vector<int>& nums) {
	if (nums.empty())
		return NULL;
	TreeNode* root = new TreeNode(nums[nums.size() / 2]);
	vector<int> pre(nums.begin(), nums.begin() + nums.size() / 2);
	vector<int> last(nums.begin() + nums.size() / 2 + 1, nums.end());
	root->left = sortedArrayToBST(pre);
	root->right = sortedArrayToBST(last);

	return root;
}

参考文章:http://blog.csdn.net/luckyxiaoqiang/article/details/7518888#topic2 以及一些leetcode题目的博客

    原文作者:libo982792994
    原文地址: https://blog.csdn.net/libo982792994/article/details/51956299
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞