二叉树作为树的一种,是一种重要的数据结构,也是面试官经常考的东西。最近也一直在看这些,所以就记录下来方便以后的学习 和 分享给一起学习的朋友。
二叉树的常见面试题:二叉树的前序、中序后序遍历 , 二叉树的线索化和线索二叉树的遍历(其中后序最难) , 求二叉树的高度 , 二叉树的叶子节点的个数 , 查询某个元素是否在二叉树中 , 判断某个节点是否在二叉树中 , 找两个节点的最近的祖先节点,二叉树的镜像 , 判断二叉树是不是完全二叉树 等等。
首先,前面对二叉树的遍历和二叉树的线索化及遍历做了详细的解读 ,本篇就不在多说 。
节点的构造
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、判断二叉树是不是完全二叉树
我测了感觉没有什么问题,大家看的时候多测测,或许能找出漏洞。
思路 :设置标志位,当像第一次遇到只存在单个子树的时候,就标记一下,如果下一次还能再遇到,那么它就不是完全二叉树
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.