二叉树的常见面试题(1)

二叉树作为树的一种,是一种重要的数据结构,也是面试官经常考的东西。最近也一直在看这些,所以就记录下来方便以后的学习 和 分享给一起学习的朋友。

二叉树的常见面试题:二叉树的前序、中序后序遍历  , 二叉树的线索化和线索二叉树的遍历(其中后序最难) , 求二叉树的高度 , 二叉树的叶子节点的个数  , 查询某个元素是否在二叉树中 , 判断某个节点是否在二叉树中 , 找两个节点的最近的祖先节点,二叉树的镜像 , 判断二叉树是不是完全二叉树   等等。

首先,前面对二叉树的遍历和二叉树的线索化及遍历做了详细的解读 ,本篇就不在多说 。 


节点的构造

template<class T>
struct BinaryTreeNode
{
	typedef BinaryTreeNode<T>*  Treepoint ;
	BinaryTreeNode(const T& data)
		:_data(data)
		, pLeft(NULL)
		, pRight(NULL)
	{}
	T _data;
	Treepoint pLeft;
	Treepoint pRight;
};


下面看讲述的都声明在这个类里面

template<class T>
class BinaryTree

{

private:
BinaryTreeNode<T>* _pRoot;

    //下面的代码程序

}


开始

 1、求二叉树的高按照 根节点的高度是 1

树的高度就是左子树高度和右子树高度的最大值  , 基于这个思想,我们先分别求得左子树高度 和右子树高度,然后比较两者,返回两者的最大值即可(注意:得加上根节点的高度

size_t _Height(BinaryTreeNode<T>* Root)//高度    
	{
		if (Root == NULL  )
		{
			return 0 ;
		}
		if (Root->pLeft == NULL && Root->pRight == NULL)
		{
			return 1;
		}
		size_t LeftHeight = _Height(Root->pLeft); //左子树的高度
		size_t RightHeight = _Height(Root->pRight);  <span style="font-family: Arial, Helvetica, sans-serif;">//右子树的高度</span>
		return LeftHeight > RightHeight ? LeftHeight + 1 : RightHeight + 1; 
	}

 2、求叶节点的个数

叶节点:树中度为0的节点 。当树只存在一个节点的时候,叶节点的的个数就是1(即 叶节点就是根节点),像上面的面试题一样,我们这就相当于找到了一个最终的结束条件(不管是循环还是递归) , 其实对于 二叉树的遍历 ,我们就很容易把这个结束条件往 递归上面靠 。

size_t _LeefCount(BinaryTreeNode<T>* Root)//叶节点个数
	{
		if (NULL == Root)
		{
			return 0;
		}
		if (NULL == Root->pLeft && NULL == Root->pRight)
		{
			return 1;
		}
		size_t Left_number = _LeefCount(Root->pLeft);//左边的叶节点
		size_t Right_number = _LeefCount(Root->pRight);//右边的叶节点
		return  Left_number + Right_number;
	}
3、 查询某个元素是否在二叉树中
可定要遍历二叉树直到找到该元素,然返回该元素的位置即可。

BinaryTreeNode<T>* _Find_data(BinaryTreeNode<T>* Root,const T& data) //找数
	{
		if (Root == NULL || Root->_data == data)
		{
			return Root;
		}
		
		BinaryTreeNode<T>* Ret = NULL;
		if ((Ret = _Find_data(Root->pLeft, data)) != NULL)   //在左边找
		{
			return Ret;
		}
		if ((Ret = _Find_data(Root->pRight, data)) != NULL)  //在右边找
		{
			return Ret ;
		}
		return NULL;
	}

4、  判断某个节点是否在二叉树中 

那我们也是和找元素的方法类似

bool _Finde_Node(BinaryTreeNode<T>* Root, BinaryTreeNode<T>* Node)
	{
		assert(Node != NULL);
		if (Root == NULL )
		{
			return false ;
		}
		if (Root == Node)
		{
			return true;
		}
		bool Ret = false;
		if ( Ret = _Finde_Node(Root->pLeft, Node) )//左边找
		{
			return Ret;
		}
		if ( Ret = _Finde_Node(Root->pRight , Node) ) //右边找
		{
			return Ret;
		}
		return false;
	}

5、  找两个节点的最近的祖先节点 

首先得知道这两个节点是不是在一个树中 , (Yes) 然后把找寻节点的路径保存在栈中,然后依次出栈比较,直到找到该位置,然后返回(栈为空 就找不到 , 返回NULL就可以了)

<span style="font-size:18px;">BinaryTreeNode<T>*  <span style="color:#ff0000;">GetAncestorNode</span>(BinaryTreeNode<T>* pNode1 , BinaryTreeNode<T>* pNode2) 
	{
		vector<BinaryTreeNode<T>* > v1;
		vector<BinaryTreeNode<T>* > v2;

		if (_GetPath(this->_pRoot, pNode1, v1)
			&& _GetPath(this->_pRoot, pNode2, v2))   
		{
			while (!v1.empty() && !v2.empty()) 
			{
				if (v1.back() == v2.back())
				{
					return v1.back();
				}
				if (v1.size() > v2.size())
				{
					v1.pop_back();
				}
				else if (v1.size() < v2.size())
				{
					v2.pop_back();
				}
				else
				{
					v1.pop_back();
					v2.pop_back();
				}
			}
		}
		return NULL;
	}
bool<span style="color:#ff0000;"> _GetPath</span>(BinaryTreeNode<T>* Root, BinaryTreeNode<T>* pNode, vector<BinaryTreeNode<T>* >& v)//找路径
	{
		if (Root == NULL || pNode == NULL)
		{
			return false;
		}
		v.push_back(Root);
		if (Root == pNode)
		{
			return true;
		}
		if ((Root->pLeft !=NULL) && _GetPath(Root->pLeft, pNode, v)) //左边
		{
			return true ;
		}
		if (Root->pLeft != NULL)
		{
			v.pop_back();
		}

		if ((Root->pRight != NULL) && _GetPath(Root->pRight, pNode, v)) //右边
		{
			return true;
		}

		if (Root->pLeft != NULL)
		{
			v.pop_back();
		}
		return false; 
	}</span>

6、  二叉树的镜像

就像照镜子一样 ,二叉树也是同样如此。左右互换即可

BinaryTreeNode<T>*  _BiTree_Mirror(BinaryTreeNode<T>* Root)
{
	if ( Root == NULL || (Root->pLeft == NULL && Root->pRight == NULL))
	{
		return Root;
	}
	std::swap(Root->pLeft, Root->pRight);
	_BiTree_Mirror(Root->pLeft);
	_BiTree_Mirror(Root->pRight);
	return Root;
}

又想出了一个非递归的做法,大家看看

void _BiTree_Mirror_Nor(BinaryTreeNode<T>* Root)
	{
		if (Root == NULL || (Root->pLeft == NULL && Root->pRight == NULL))
		{
			return ;
		}
		queue<BinaryTreeNode<T>* > q;
		q.push(Root);

		while (!q.empty())
		{
			BinaryTreeNode<T>* pCur = q.front();
			std::swap(pCur->pLeft, pCur->pRight);
			q.pop();
			if (pCur->pLeft != NULL)
			{
				q.push(pCur->pLeft);
			}
			if (pCur->pRight != NULL)
			{
				q.push(pCur->pRight);
			}
		}
	}

7、判断二叉树是不是完全二叉树

完全二叉树:具有n个结点的二叉树按层序编号,如果编号为i(1≤i≤n)的结点与同样深度的满二叉树中的编号为i的结点在二叉树中的位置完全相同。 定义这样难免不好理解,我们可以用这棵树和的它的满二叉树形式对比就可以知道是不是完全二叉树了。

我测了感觉没有什么问题,大家看的时候多测测,或许能找出漏洞

  思路 :设置标志位,当像第一次遇到只存在单个子树的时候,就标记一下,如果下一次还能再遇到,那么它就不是完全二叉树

bool _IsComplete_BiTree_First(BinaryTreeNode<T >* Root)
	{
		if (Root == NULL)
		{
			return false ;
		}
		bool flag = false; 
		queue<BinaryTreeNode<T>* > q;
		q.push(Root);
		while (!q.empty())
		{
			BinaryTreeNode<T>* pCur = q.front();
			q.pop();
			if (flag)//找到第二个  只有单个子树的节点 
			{
				if (pCur->pLeft != NULL || pCur->pRight != NULL)
				{
					return false;
				}
			}
			//两个子树都存在
			if (pCur->pLeft != NULL && pCur->pRight != NULL)
			{
				q.push(pCur->pLeft);
				q.push(pCur->pRight);
			}
			//只有左子树
			else if (pCur->pLeft != NULL)
			{
				q.push(pCur->pLeft) ;
				flag = true;
			}
			//只有右子树
			else if (pCur->pRight != NULL)
			{
				q.push(pCur->pRight) ;
				flag = true; 
			}
			else   //没有子树
			{
				flag = false;
			}
		}
		return true;
	}

                Thx.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python二叉树面试题有很多种,以下是其中几个常见面试题: 1. 二叉树的最大深度:这个问题要求计算给定二叉树的最大深度。可以使用递归的方法来解决,递归函数的定义是返回当前节点的深度,递归终止条件是节点为空时返回0,递归过程中比较左右子树的深度并返回较大值加1。时间复杂度为O(n),空间复杂度为O(n)。 2. 二叉树的前序遍历:这个问题要求按照前序遍历的顺序输出二叉树的节点值。可以使用递归或迭代的方法来解决。递归方法的思路是先输出当前节点的值,然后递归遍历左子树,最后递归遍历右子树。迭代方法可以使用栈来辅助实现,把根节点压入栈中,然后循环弹出栈顶节点,输出其值,并将其右子节点和左子节点依次压入栈中。时间复杂度为O(n),空间复杂度为O(n)。 3. 二叉树的层序遍历:这个问题要求按照层序遍历的顺序输出二叉树的节点值。可以使用队列来辅助实现。首先将根节点入队,然后循环直到队列为空,每次从队列中取出一个节点,输出其值,并将其左右子节点依次入队。时间复杂度为O(n),空间复杂度为O(n)。 以上是几个常见的Python二叉树面试题的解法,根据具体的问题要求和输入条件选择合适的解法即可。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [【编程之路】面试必刷TOP101:二叉树系列(23-30,Python实现)](https://blog.csdn.net/be_racle/article/details/125531755)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [【面试题8】二叉树的下一个节点](https://download.csdn.net/download/weixin_38589168/14035034)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值