二叉树节点定义如下:
struct BinaryTreeNode
{
int Value;
BinaryTreeNode* Left;
BinaryTreeNode* Right;
};
相关链接:
轻松搞定面试中的链表题目
题目列表:
1. 求二叉树中的节点个数
2. 求二叉树的深度
3. 前序遍历,中序遍历,后序遍历
4.分层遍历二叉树(按层次从上往下,从左往右)
5. 将二叉查找树变为有序的双向链表
6. 求二叉树第K层的节点个数
7. 求二叉树中叶子节点的个数
8. 判断两棵二叉树是否结构相同
9. 判断二叉树是不是平衡二叉树
10. 求二叉树的镜像
11. 求二叉树中两个节点的最低/近公共祖先节点
12. 求二叉树中节点的最大距离
13. 由前序遍历序列和中序遍历序列重建二叉树
14.判断二叉树是不是完全二叉树
15、交换左右儿子
16、判断一个节点是否在一棵树中
17、判断一棵树是不是二叉查找树(BST)
18、给出有序数组,求出高度最小的二叉查找树
19、由前序中序求出后序
详细解答
1. 求二叉树中的节点个数
递归解法:
(1)如果二叉树为空,节点个数为0
(2)如果二叉树不为空,二叉树节点个数 = 左子树节点个数 + 右子树节点个数 + 1
参考代码如下:
递归解法:
(1)如果二叉树为空,二叉树的深度为0
(2)如果二叉树不为空,二叉树的深度 = max(左子树深度, 右子树深度) + 1
参考代码如下:
3. 前序遍历,中序遍历,后序遍历
前序遍历递归解法:
(1)如果二叉树为空,空操作
(2)如果二叉树不为空,访问根节点,前序遍历左子树,前序遍历右子树
参考代码如下:
中序遍历递归解法
(1)如果二叉树为空,空操作。
(2)如果二叉树不为空,中序遍历左子树,访问根节点,中序遍历右子树
参考代码如下:
后序遍历递归解法
(1)如果二叉树为空,空操作
(2)如果二叉树不为空,后序遍历左子树,后序遍历右子树,访问根节点
参考代码如下:
递归:
- int PrintNodeAtLevel(BiTree root, int level) //遍历指定的某层
- {
- if(root==NULL || level < 0)
- return 0;
- else if(level == 0)
- {
- cout << root->data << endl;
- return 1;
- }
- else
- return PrintNodeAtLevel(root->left, level - 1) + PrintNodeAtLevel(root->right, level - 1);
- }
相当于广度优先搜索,使用队列实现。队列初始化,将根节点压入队列。当队列不为空,进行如下操作:弹出一个节点,访问,若左子节点或右子节点不为空,将其压入队列。
要求不能创建新节点,只调整指针。
递归解法:
(1)如果二叉树查找树为空,不需要转换,对应双向链表的第一个节点是NULL,最后一个节点是NULL
(2)如果二叉查找树不为空:
如果左子树为空,对应双向有序链表的第一个节点是根节点,左边不需要其他操作;
如果左子树不为空,转换左子树,二叉查找树对应双向有序链表的第一个节点就是左子树转换后双向有序链表的第一个节点,同时将根节点和左子树转换后的双向有序链 表的最后一个节点连接;
如果右子树为空,对应双向有序链表的最后一个节点是根节点,右边不需要其他操作;
如果右子树不为空,对应双向有序链表的最后一个节点就是右子树转换后双向有序链表的最后一个节点,同时将根节点和右子树转换后的双向有序链表的第一个节点连 接。参考代码如下:
6. 求二叉树第K层的节点个数
递归解法:
(1)如果二叉树为空或者k<1返回0
(2)如果二叉树不为空并且k==1,返回1
(3)如果二叉树不为空且k>1,返回左子树中k-1层的节点个数与右子树k-1层节点个数之和
参考代码如下:
7. 求二叉树中叶子节点的个数
递归解法:
(1)如果二叉树为空,返回0
(2)如果二叉树不为空且左右子树为空,返回1
(3)如果二叉树不为空,且左右子树不同时为空,返回左子树中叶子节点个数加上右子树中叶子节点个数
参考代码如下:
8. 判断两棵二叉树是否结构相同
不考虑数据内容。结构相同意味着对应的左子树和对应的右子树都结构相同。
递归解法:
(1)如果两棵二叉树都为空,返回真
(2)如果两棵二叉树一棵为空,另一棵不为空,返回假
(3)如果两棵二叉树都不为空,如果对应的左子树和右子树都同构返回真,其他返回假
参考代码如下:
9. 判断二叉树是不是平衡二叉树
递归解法:
(1)如果二叉树为空,返回真
(2)如果二叉树不为空,如果左子树和右子树都是AVL树并且左子树和右子树高度相差不大于1,返回真,其他返回假
参考代码:
解法一:
- bool IsBalanced(BinaryTreeNode* Root)
- {
- if(Root== NULL)
- return true;
- int LeftDepth = GetDepth(pRoot->Left); //取深度
- int RightDepth = GetDepth(pRoot->Right);
- int diff = RightDepth-LeftDepth;
- if (diff>1 || diff<-1)
- return false;
- return IsBalanced(Root->Left) && IsBalanced(Root->Right);
- }
10. 求二叉树的镜像
递归解法:
(1)如果二叉树为空,返回空
(2)如果二叉树不为空,求左子树和右子树的镜像,然后交换左子树和右子树
参考代码如下:
void getImage(BinaryTreeNode *root)
{
if(root != NULL && root->Left != NULL && root->Right != NULL)
{
BinaryTreeNode *temp = root->Left; //交换左右子树
root->Left = root->Right;
root->Right = temp;
getImage(root->Left); //递归求解
getImage(root->Right);
}
}
11. 求二叉树中两个节点的最低公共祖先节点
递归解法:
(1)如果两个节点分别在根节点的左子树和右子树,则返回根节点
(2)如果两个节点都在左子树,则递归处理左子树;如果两个节点都在右子树,则递归处理右子树
参考代码如下:
- BTreeNode *GetCommon( BTreeNode *Root, BTreeNode *Node1, BTreeNode *Node2){
- if( Root == NULL ) //说明是空树,不用查找了,也就找不到对应节点,则返回NULL
- return NULL;
- if( Root == Node1 || Root == Node2 )//说明在当前子树的根节点上找到两个节点之一
- return pRoot;
- BTreeNode *Left = GetCommon( Root->Left, Node1, Node2); //左子树中的查找两个节点并返回查找结果
- BTreeNode *Right = GetCommon( Root->Right, Node1, Node2);//右子树中查找两个节点并返回查找结果
- if( Left == NULL )//如果在左子树中没有找到,则断定两个节点都在右子树中,可以返回右子树中查询结果;
- return Right; 否则,需要结合左右子树查询结果共同断定
- if ( Right == NULL )//如果在右子树中没有找到,则断定两个节点都在左子树中,可以返回左子树中查询结果; return Left; 否则,需要结合左右子树查询结果共同断定
- return Root; //如果在左右子树中都找两个节点之一,则pRoot就是最低公共祖先节点,返回即可。
- }
递归解法效率很低,有很多重复的遍历,下面看一下非递归解法。
非递归解法:先求从根节点到两个节点的路径,然后再比较对应路径的节点就行,最后一个相同的节点也就是他们在二叉树中的最低公共祖先节点
参考代码如下:
在上述算法的基础上稍加变化即可求二叉树中任意两个节点的距离了。
12. 求二叉树中节点的最大距离
最大距离的两个点有可能出现在三种情况下
- 左子树
- 右子树
- 过节点x
经分析得出以下特点
- 以上三种情况最终必定一叶子结束
- 在第三种情况下必然是左子树高度 与 右子树高度 之和(只有这样,才可能取得最大值)
经过以上分析即可得出递推式
Dis(x) = max(Dis(x->left), Dis(x->right), height(x->left)+height(x->right))
参考代码
int treeDistance(BiTree root) { if(root == NULL) return 0; else if(root->left == NULL && root->right == NULL) return 0;
int maxDis = 0; int dis = max(height(root->left) + height(root->right),
treeDistance(root->left),
treeDistance(root->right)); if(maxDis < dis) maxDis = dis; return dis; }
这里用了一个技巧:maxDis是个全局变量,递归一次根节点会遍历到每个节点,在这期间于maxDis比较,从而得出了最大值,而不需要额外的空间。
13. 由前序遍历序列和中序遍历序列重建二叉树
二叉树前序遍历序列中,第一个元素总是树的根节点的值。中序遍历序列中,左子树的节点的值位于根节点的值的左边,右子树的节点的值位
于根节点的值的右边。
递归解法:
(1)如果前序遍历为空或中序遍历为空或节点个数小于等于0,返回NULL。
(2)创建根节点。前序遍历的第一个数据就是根节点的数据,在中序遍历中找到根节点的位置,可分别得知左子树和右子树的前序和中序遍
历序列,重建左右子树。
同样,有中序遍历序列和后序遍历序列,类似的方法可重建二叉树,但前序遍历序列和后序遍历序列不同恢复一棵二叉树,证明略。
14.判断二叉树是不是完全二叉树
算法思想:采用层次遍历的算法,将所有节点都加入队列(包括空节点)。当遇到空节点时,查看其后是否有非空节点,若有,则不是完全二叉树。
- bool is_complete(tree *root)
- {
- queue Q;
- tree *p;
- // 进行广度优先遍历(层次遍历),并把NULL节点也放入队列
- Q.push(root);
- while ((p = Q.pop()) != NULL)
- {
- Q.push(p->left);
- Q.push(p->right);
- }
- // 判断是否还有未被访问到的节点
- while (!Q.is_empty())
- {
- p = Q.pop();
- // 有未访问到的的非NULL节点,则树存在空洞,为非完全二叉树
- if (p != NULL)
- {
- return false;
- }
- }
- return true;
- }
15 交换二叉树的左右儿子(即镜像)
交换二叉树的左右儿子,可以先交换根节点的左右儿子节点,然后递归以左右儿子节点为根节点继续进行交换。树中的操作有先天的递归性。。
1 //交换二叉树的左右儿子 2 void BinTree::swap(BinTreeNode *root) 3 { 4 if(root == NULL) 5 { 6 return; 7 } 8 BinTreeNode *temp = root->left;
9 root->left = root->right;
10 root->right = temp;
11 swap(root->left);
12 swap(root->right);
13 }
16 判断一个节点是否在一颗子树中
可以和当前根节点相等,也可以在左子树或者右子树中。
1 //判断一个节点t是否在以r为根的子树中 2 bool BinTree::isContain(BinTreeNode *root,BinTreeNode *node)const 3 { 4 if(root== NULL) 5 { 6 return false; 7 } 8 else if(root == node) 9 { 10 return true; 11 } 12 else 13 { 14 bool has = false; 15 if(root->left != NULL) 16 { 17 has = isContain(root->left, node); 18 } 19 if(!has && root->right != NULL) 20 { 21 has = isContain(root->right, node); 22 } 23 return has; 24 } 25 }
17、判断是否为二叉查找树
思路: 1 将数组中间位置的元素插入树中;
2 将数组左半边元素插入左子树中;
3 同理,右;
4 递归处理
TreeNode createMinimalBST(int arr[], int start, int end)
{if (end < start)
{
return null;
}
int mid = start + (end - start) / 2;
TreeNode root =new TreeNode(arr[mid]);
root.left=createMinimalBST(arr,start,mid-1);
root.right=createMinimalBST(arr,mid+1,end);
return root;
}
TreeNode createMinimalBST(int array[])
{
return createMinimalBST(array,0,array.length-1);
}
19、已知二叉树的前序遍历和中序遍历,输出后序遍历的代码
- void BinaryTreeFromOrderings(char* inorder, char* preorder, int length)
- {
- if(length == 0)
- {
- return;
- }
- char node_value = *preorder;
-
- int rootIndex = 0;
-
- for(;rootIndex < length; rootIndex++)
-
- {
- if(inorder[rootIndex] == *preorder)
- break;
- }
- BinaryTreeFromOrderings(inorder, preorder +1, rootIndex); //Left and Right
- BinaryTreeFromOrderings(inorder + rootIndex + 1, preorder + rootIndex + 1, length - (rootIndex + 1));
- cout<<node_value<<endl;
- return;
- }
- //来自: http://blog.csdn.net/feliciafay/article/details/6816871
===============
创建二叉树:
void CreateBinaryTree(BinaryTreeNode * &root)
{
char ch;
cin>>ch;
if(ch=='#') //当遇到#时,令树的根节点为NULL,从而结束该分支的递归
root = NULL;
else
{
root=new BinaryTreeNode;
root->data=ch;
CreateBinaryTree(root->left);
CreateBinaryTree(root->right);
}
}
Status CreateBiTree(Binary_Tree &Root)
{
char ch;
if(!Root)Root
=(Binary_Tree)malloc(sizeof(BiTree));
exit(OVERFLOW);
cin>>ch;
if(ch=='0')
Root=NULL;
else
{
Root->data=ch;
CreateBiTree(Root->Lchild);
CreateBiTree(Root->Rchild);
}
return OK;
}