求二叉树的高度
判断一棵树是否为平衡二叉树
求二叉树叶子节点的个数
求二叉树第k层节点的个数
判断某个节点是否存在于二叉树中
求二叉树的镜像
求二叉树中最远的两个节点之间的距离
由前序遍历和中序遍历重建二叉树
二叉树的高度
题目:输入一棵二叉树的根结点,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
思路: 1、如果树为空,返回0
2、若果二叉树只有一个节点,返回1
3、如果二叉树中有左子树,返回左子树的高度+1
4、如果二叉树中有右子树,返回右子树的高度+1
5、如果左右子树都存在,则返回高度较大的子树值+1
代码实现如下(递归思想):
树的节点结构:
struct BTNode
{
BTNode(const T& data=T())//定义结构体 并初始化
:_data(data)
, _left(NULL)
, _right(NULL)
{}
BTNode* _left;
BTNode* _right;
T _data;
};
size_t _Depth(Node* _root)// 左右子树高的+1依次递归
{
if (_root == NULL)
{
return 0;
}
if (_root)
{
//int left=_Depth(_root->_left)
//int right=_Depth(_root->_right)
//return left>right?left+1:right+1
return (_Depth(_root->_left) > _Depth(_root->_right)
? _Depth(_root->_left) : _Depth(_root->_right)) + 1;
}
}
判断一棵树是否为平衡二叉树
题目: 输入一棵二叉树的根结点,判断该树是不是平衡二叉树。如果某二叉树中任意结点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。例如,下图中的二叉树就是一棵平衡二叉树。
思路:
1、由于在上一个题中已经可以得到了树的高度,所以只需要求得左右子树的高度差就可以了
2、两颗子树也要平衡
bool Isbalance(Node* _root)
{
if (_root == NULL)
return NULL;
int left_height = _Depth(_root->_left);
int right_height = _Depth(_root->_right);
int sub_height = abs(left_height - right_height);
if (sub_height > 1)
return false;
//判断两颗子树是否平衡
return Isbalance(_root->_left) && Isbalance(_root->_right);
}
但是,上面的“先序遍历”判断二叉树平衡的方法,时间复杂度比较大。因为,二叉树中的很多结点遍历了多次。
比如,求解根的的高度时,需要先求解根的左子树高度和右子树高度,这就遍历了整棵左子树中的结点和右子树中的结点。而求解以根的左孩子为根的子树的高度时,又需要遍历它(根的左孩子)的左子树和右子树。这样,相当于很多结点的高度重复计算了。
根本原因是采用了“先序遍历”,求根的高度,需要先知道根的左右孩子的高度。
如果采用后序遍历,先知道某结点左右子树的高度,如果左右子树的高度都不满足平衡二叉树(二者高度相减大于1),那么都不需要再去求解该结点的高度了。
因为,平衡二叉树要求二叉树中任意结点的左右子树高度相差不超过1
代码实现如下:
bool isBalance(TreeNode *root, int &height)
{
if (root == NULL)
{
height = 0;
return true;
}
int leftHeight = 0, rightHeight = 0;
bool leftRet = isBalance3(root->left, leftHeight);
bool rightRet = isBalance3(root->right, rightHeight);
height = max(leftHeight, rightHeight) + 1;
if (abs(leftHeight - rightHeight) > 1)
return false;
return leftRet && rightRet;
}
};
二叉树叶子节点的个数
题目:输入一棵二叉树的根结点,求该树的叶子节点的个数。
思路: 1、当树为空时,返回0;
2、当树只有根节点时,返回1
3、当树的左右子树都为空时,树的叶子节点为左右子树的叶子节点之和
代码实现如下:
size_t _LeafSize( const Node* _root)//返回二叉树中叶子节点的个数 三种情况都要分别考虑到
{
if (_root == NULL)
{
return 0;
}
if ((_root->_left == NULL) && (_root->_right==NULL))
{
return 1;
}
if (_root)
{
return _LeafSize(_root->_left) + _LeafSize(_root->_right);
}
}
第K层节点的个数
题目:给定一个二叉树的根节点,求二叉树第K层节点的个数
思路: 1、如果树为空或者K<0,返回0
2、如果树不为空,并且求的是树的第一层的节点个数,返回1
3、树的左右子树都不为空,返回第k-1层左右子树节点的个数之和
递归方法
size_t _GetKLevel_NodeSzie( Node* _root,int k)//返回第k层节点的个数
{
if (_root == NULL||K<=0)
{
return 0;
}
if (_root!=NULL&&k==1)
{
return 1;
}
return _GetKLevel_NodeSzie(_root->_left, k - 1)
+ _GetKLevel_NodeSzie(_root->_right, k - 1);
}
判断一个节点是否在一颗二叉树中
题目: 给一个二叉树的根节点,和另外一个节点,判断此节点是否在二叉树中
思路:
1、如果树为空或者所给节点为空,返回false
2、如果所给节点的值,与树中某一个节点的值相等,返回true
3、如果树不为空,所给节点也不为空,依次遍历树的左子树和右子树
代码实现如下:
//判断一个二叉树的节点是否在二叉树中
bool IsNodeIntree(Node* _root, Node *node)
{
if (_root == NULL || node == NULL)
return false;
if (_root->_data == node->_data)
return true;
if (IsNodeIntree(_root->_left, node) || IsNodeIntree(_root->_right, node))
return true;
return false;
}
求二叉树的镜像
题目: 输入一颗二叉树,输出它的镜像
思路:
树的镜像就是将树的所有左右节点全部进行交换
1、当树为空时,直接返回
2、当树只有一个节点时,直接返回
3、当树的左右节点都不为空时,依次交换树的左右节点
方法1:递归法
void Mirrorcursively(Node *_root)
{
if (_root == NULL || (_root->_left == NULL&&_root->_right == NULL))
return;
Node *ptmp = _root->_left;
_root->_left = _root->_right;
_root->_right = ptmp;
if (_root->_left)
Mirrorcursively(_root->_left);
if (_root->_right)
Mirrorcursively(_root->_right);
}
方法二:非递归法
用非递归方法实现,借助栈来完成
void Iteratively(Node *_root)
{
if (_root == NULL)
return;
stack<Node*> s;
s.push(_root);
while (!s.empty())
{
Node *top = s.top();
s.pop();
Node *ptmp = top->_left;
top->_left = top->_right;
top->_right = ptmp;
if (top->_left)
s.push(top->_left);
if (top->_right)
s.push(top->_right)
}
}
求二叉树中最远的两个节点之间的距离
题目:如果我们把二叉树看做图,父子节点之间的连线看成是双向的,我们姑且定义“距离”为两个节点之间边的个数。写一个程序求一棵二叉树中相距最远的两个节点之间的距离。
思路:
1、如果最远距离的两个节点都经过了根节点,则最远距离就是左边最深的深度到根节点的距离+右边最深的深度到根节点的距离
如下图所示,树中相距最远的两个节点为A,B,最大距离为6。
2、如果具有最远距离的两个节点不经过根节点,那么最远距离就是根节点上某个子树上面的两个节点
如下图所示,树中相距最远的两个节点为A,B,最大距离为5。
代码实现如下:
int GetFarDistance()
{
int distance = -1;
_Height(_root,distance);
return distance;
}
protected:
int _Height(Node* root, int& distance)
{
if (root == NULL)
{
return 0;
}
int leftH = _Height(root->_left);
int rightH = _Height(root->_right);
if (leftH+rightH > distance)
{
distance = leftH + rightH;
}
return leftH > rightH ? leftH+1 : rightH+1;
}
由前序遍历和中序遍历重建二叉树
题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
思路:
1、在二叉树的前序遍历序列中,第一个数字总是树的根结点的值。但在中序遍历序列中,根结点的值在序列的中间,左子树的结点的值位于根结点的值的左边,而右子树的结点的值位于根结点的值的右边。因此我们需要扫描中序遍历序列,才能找到根结点的值。
2、如下图所示,前序遍历序列的第一个数字1就是根结点的值。扫描中序遍历序列,就能确定根结点的值的位置。根据中序遍历特点,在根结点的值1前面的3个数字都是左子树结点的值,位于1后面的数字都是右子树结点的值。
3、同样,在前序遍历的序列中,根结点后面的3个数字就是3个左子树结点的值,再后面的所有数字都是右子树结点的值。这样我们就在前序遍历和中序遍历两个序列中,分别找到了左右子树对应的子序列。
4、既然我们已经分别找到了左、右子树的前序遍历序列和中序遍历序列,我们可以用同样的方法分别去构建左右子树。也就是说,接下来的事情可以用递归的方法去完成。
代码实现如下:
#include <iostream>
#include <vector>
using namespace std;
// Definition for binary tree
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
/* 先序遍历第一个位置肯定是根节点node,
中序遍历的根节点位置在中间p,在p左边的肯定是node的左子树的中序数组,p右边的肯定是node的右子树的中序数组
另一方面,先序遍历的第二个位置到p,也是node左子树的先序子数组,剩下p右边的就是node的右子树的先序子数组
把四个数组找出来,分左右递归调用即可
*/
class Solution {
public:
struct TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> in) {
int in_size = in.size();//获得序列的长度
2 if (in_size == 0)
return NULL;
//分别存储先序序列的左子树,先序序列的右子树,中序序列的左子树,中序序列的右子树
vector<int> pre_left, pre_right, in_left, in_right;
int val = pre[0];//先序遍历第一个位置肯定是根节点node,取其值
//新建一个树结点,并传入结点值
TreeNode* node = new TreeNode(val);//root node is the first element in pre
//p用于存储中序序列中根结点的位置
int p = 0;
for (p; p < in_size; ++p){
if (in[p] == val) //Find the root position in in
break; //找到即跳出for循环
}
for (int i = 0; i < in_size; ++i){
if (i < p){
//建立中序序列的左子树和前序序列的左子树
in_left.push_back(in[i]);//Construct the left pre and in
pre_left.push_back(pre[i + 1]);//前序第一个为根节点,+1从下一个开始记录
}
else if (i > p){
//建立中序序列的右子树和前序序列的左子树
in_right.push_back(in[i]);//Construct the right pre and in
pre_right.push_back(pre[i]);
}
}
//取出前序和中序遍历根节点左边和右边的子树
//递归,再对其进行上述所有步骤,即再区分子树的左、右子子数,直到叶节点
node->left = reConstructBinaryTree(pre_left, in_left);
node->right = reConstructBinaryTree(pre_right, in_right);
return node;
}
};
作者:wyn126
来源:CSDN
原文:https://blog.csdn.net/wyn126/article/details/81450285
版权声明:本文为博主原创文章,转载请附上博文链接!