二叉树的面试常见问题包括:
参考文章:
- 二叉树中的节点个数
- 二叉树的深度
- 前序遍历,中序遍历,后序遍历,层序遍历
- 将二叉查找树变为有序的双向链表
- 二叉树第K层的节点个数
- 二叉树中叶子节点的个数
- 判断二叉树是不是平衡二叉树
- 二叉树的镜像
- 二叉树中两个节点的最低公共祖先节点
- 二叉树中节点的最大距离
- 判断二叉树是不是完全二叉树
下面是完整二叉树及这些常见问题的代码实现:
头文件BTree.h
#ifndef BTREE_H
#define BTREE_H
struct BTreeNode
{
int data;
BTreeNode *lChild,*rChild;
};
class BTree
{
public:
void setRoot(BTreeNode* r){ root=r;}
BTreeNode* getRoot(){ return root;}
BTreeNode* createBTree();
BTree():root(createBTree()){}
//中序遍历(递归)
void inOrder();
//中序遍历(非递归)
void NotReInOrder();
//前序遍历(递归)
void preOrder();
//前序遍历(非递归)
void NotRePreOrder();
//后序遍历(递归)
void postOrder();
//后序遍历(非递归)
void NotRePostOrder();
//层序遍历BFS
void LevelOrder(BTreeNode*);
//求结点个数
int BTreeSize();
//求叶子结点个数
int BTreeLeaves();
//求树高
int BTreeHeight();
//将二叉查找树变为有序的双向链表
void convert_tree_list(BTreeNode * pRoot, BTreeNode * & pFirstNode, BTreeNode * & pLastNode);
//二叉树第k层节点个数
int GetNodeNumKthLevel(BTreeNode * pRoot, int k);
//判断二叉树是否是平衡的
bool IsAVL(BTreeNode * pRoot,int & height);
//求二叉树的镜像
BTreeNode * Mirror(BTreeNode * pRoot);
//判断一个节点是否存在
bool FindNode(BTreeNode * pRoot, BTreeNode * pNode);
// 求二叉树两个节点的公共祖先
BTreeNode * GetLastCommonParent(BTreeNode * pRoot,
BTreeNode * pNode1,
BTreeNode * pNode2);
//求二叉树节点的最大距离
int GetMaxDistance(BTreeNode * pRoot, int & maxLeft, int & maxRight);
//判断一颗树是不是完全二叉树
bool IsCompleteBinaryTree(BTreeNode * pRoot);
protected:
//中序遍历
void inOrder(BTreeNode*);
//前序遍历
void preOrder(BTreeNode*);
//后序遍历
void postOrder(BTreeNode*);
//结点个数
int BTreeSize(BTreeNode*);
//叶子结点
int BTreeLeaves(BTreeNode*);
//树高
int BTreeHeight(BTreeNode*);
private:
BTreeNode* root;
};
#endif
源文件BTree.cpp
#include <iostream>
#include <stack>
#include <queue>
#include <algorithm>
#include "BTree.h"
using namespace std;
//建立二叉树的算法
BTreeNode* BTree::createBTree()
{
BTreeNode* current=0;
int val=0;
cin>>val;
//-1的个数比数值的个数多1
if(val==-1)
return NULL;
else
{
current=new BTreeNode;
current->data=val;
current->lChild=createBTree();
current->rChild=createBTree();
return current;
}
}
//利用重载的方法
void BTree::inOrder()
{
inOrder(root);
cout<<endl;
}
//中序访问二叉树(递归)
void BTree::inOrder(BTreeNode* r)
{
if(r!=0) //是if,而不是while
{
inOrder(r->lChild); //递归访问
cout<<r->data<<" ";
inOrder(r->rChild); //递归访问
}
}
//中序遍历(非递归)
//往左放,放完访问,回溯到右
void BTree::NotReInOrder()
{
stack<BTreeNode*> s;
BTreeNode* r=getRoot();
while(!s.empty()||r!=0)
{
while(r!=0)
{
s.push(r);
r=r->lChild;
}
if(!s.empty())
{
r=s.top();
s.pop();
cout<<r->data<<" ";
r=r->rChild;
}
}
}
//重载形式
void BTree::preOrder()
{
preOrder(root);
cout<<endl;
}
//前序递归访问二叉树(递归)
void BTree::preOrder(BTreeNode* r)
{
if(r!=0) //是if,而不是while
{
cout<<r->data<<" ";
preOrder(r->lChild); //递归访问
preOrder(r->rChild); //递归访问
}
}
//前序遍历(非递归)
//过程可以理解为:放入一个元素,访问它,弹出,
//放入她的右孩子以便返回,放入左孩子用于下次访问
void BTree::NotRePreOrder()
{
stack<BTreeNode*> s;
BTreeNode* r=getRoot();
s.push(r);
while(!s.empty())
{
r=s.top();
s.pop();
cout<<r->data<<" ";
if(r->rChild!=0)
s.push(r->rChild);
if(r->lChild!=0)
s.push(r->lChild);
}
}
//重载形式
void BTree::postOrder()
{
postOrder(root);
cout<<endl;
}
//后序遍历(递归)
void BTree::postOrder(BTreeNode* r)
{
if(r!=0) //是if,而不是while
{
postOrder(r->lChild); //递归访问
postOrder(r->rChild); //递归访问
cout<<r->data<<" ";
}
}
//后序非递归访问要定义新的结构体类型
struct Node
{
BTreeNode* tp;
bool flag;
};
//后序遍历(非递归)
void BTree::NotRePostOrder()
{
Node node; //定义Node结构体的一个结点
stack<Node> s;
BTreeNode* r=getRoot();
while(!s.empty()||r!=0)
{
while(r!=0)
{
node.tp=r;
node.flag=0;
s.push(node);
r=r->lChild;
}
if(!s.empty())
{
node=s.top();
s.pop();
r=node.tp; //将栈顶的BTreeNode*部分赋给r
if(node.flag==1)
{
cout<<r->data<<" ";
r=0; //表示已经访问了该结点
}
else
{
node.flag=1;
s.push(node);
r=r->rChild;
}
}
}
}
//层序遍历,即广度优先搜索,用到queue
void BTree::LevelOrder(BTreeNode* pRoot)
{
if(pRoot == NULL)
return;
queue<BTreeNode *> q;
q.push(pRoot);
while(!q.empty())
{
BTreeNode * pNode = q.front();
q.pop();
cout<<pNode->data; // 访问节点
if(pNode->lChild != NULL)
q.push(pNode->lChild);
if(pNode->rChild != NULL)
q.push(pNode->rChild);
}
}
//重载形式
int BTree::BTreeSize()
{
return BTreeSize(root);
}
//求二叉树结点个数的函数
int BTree::BTreeSize(BTreeNode* r)
{
//二叉树的结点个数为左右子树的高度之和再+1
if(r==0) return 0;
else return 1+BTreeSize(r->lChild)+BTreeSize(r->rChild);
}
//重载形式
int BTree::BTreeLeaves()
{
return BTreeLeaves(root);
}
//求二叉树叶子结点个数的函数
int BTree::BTreeLeaves(BTreeNode* r)
{
//当为空时,返回0;当找到叶子时返回1
if(r==0) return 0;
else if(r->lChild==0&&r->rChild==0) return 1;
else return BTreeLeaves(r->lChild)+BTreeLeaves(r->rChild);
}
//重载形式
int BTree::BTreeHeight()
{
return BTreeHeight(root);
}
//求二叉树高度的函数
int BTree::BTreeHeight(BTreeNode* r)
{
if(r==0) return 0;
//二叉树的高度为左右子树的最大者+1
else return max(BTreeHeight(r->lChild),BTreeHeight(r->rChild))+1;
}
void BTree::convert_tree_list(BTreeNode * pRoot, BTreeNode * & pFirstNode, BTreeNode * & pLastNode)
{
BTreeNode *pLastLeft, * pFirstRight;
if(pRoot == NULL)
{
pFirstNode = NULL;
pLastNode = NULL;
return;
}
if(pRoot->lChild == NULL)
{
// 如果左子树为空,对应双向有序链表的第一个节点是根节点
pFirstNode = pRoot;
}
else
{
convert_tree_list(pRoot->lChild, pFirstNode, pLastLeft);
// 将根节点和左子树转换后的双向有序链表的最后一个节点连接
pRoot->lChild = pLastLeft;
pLastLeft->rChild = pRoot;
}
if(pRoot->rChild == NULL)
{
// 对应双向有序链表的最后一个节点是根节点
pLastNode = pRoot;
}
else
{
convert_tree_list(pRoot->rChild, pFirstRight, pLastNode);
// 将根节点和右子树转换后的双向有序链表的第一个节点连接
pRoot->rChild = pFirstRight;
pFirstRight->lChild = pRoot;
}
}
//二叉树第k层节点个数
int BTree::GetNodeNumKthLevel(BTreeNode * pRoot, int k)
{
if(pRoot == NULL || k < 1) return 0;
else if(k == 1) return 1;
else return (GetNodeNumKthLevel(pRoot->lChild, k-1) + GetNodeNumKthLevel(pRoot->rChild, k-1));
}
//判断二叉树是否是平衡的
bool BTree::IsAVL(BTreeNode * pRoot,int & height)
{
if(pRoot == NULL) // 空树,返回真
{
height = 0;
return true;
}
int heightLeft;
bool resultLeft = IsAVL(pRoot->lChild, heightLeft);
int heightRight;
bool resultRight = IsAVL(pRoot->rChild, heightRight);
if(resultLeft && resultRight && abs(heightLeft - heightRight) <= 1) // 左子树和右子树都是AVL,并且高度相差不大于1,返回真
{
height = max(heightLeft, heightRight) + 1;
return true;
}
else
{
height = max(heightLeft, heightRight) + 1;
return false;
}
}
//求二叉树的镜像
BTreeNode * BTree::Mirror(BTreeNode * pRoot)
{
if(pRoot == NULL) return NULL;
// 交换左子树和右子树
pRoot->lChild = Mirror(pRoot->rChild);
pRoot->rChild = Mirror(pRoot->lChild);
return pRoot;
}
//判断一个节点是否存在
bool BTree::FindNode(BTreeNode * pRoot, BTreeNode * pNode)
{
if(pRoot == NULL || pNode == NULL) return false;
else if(pRoot == pNode) return true;
else return FindNode(pRoot->lChild, pNode)||FindNode(pRoot->rChild, pNode);
}
// 求二叉树两个节点的公共祖先
BTreeNode * BTree::GetLastCommonParent(BTreeNode * pRoot,
BTreeNode * pNode1,
BTreeNode * pNode2)
{
bool lf1=FindNode(pRoot->lChild,pNode1);
bool lf2=FindNode(pRoot->lChild,pNode2);
bool rf1=FindNode(pRoot->rChild,pNode1);
bool rf2=FindNode(pRoot->rChild,pNode2);
if(lf1&&lf2) return GetLastCommonParent(pRoot->lChild,pNode1,pNode2);
else if(rf1&&rf2) return GetLastCommonParent(pRoot->rChild,pNode1,pNode2);
else return pRoot;
}
//求二叉树节点的最大距离
//用到分治策略
int BTree::GetMaxDistance(BTreeNode * pRoot, int & maxLeft, int & maxRight)
{
// maxLeft, 左子树中的节点距离根节点的最远距离
// maxRight, 右子树中的节点距离根节点的最远距离
if(pRoot == NULL)
{
maxLeft = 0;
maxRight = 0;
return 0;
}
int maxLL, maxLR, maxRL, maxRR;
int maxDistLeft, maxDistRight;
if(pRoot->lChild != NULL)
{
maxDistLeft = GetMaxDistance(pRoot->lChild, maxLL, maxLR);
maxLeft = max(maxLL, maxLR) + 1;
}
else
{
maxDistLeft = 0;
maxLeft = 0;
}
if(pRoot->rChild != NULL)
{
maxDistRight = GetMaxDistance(pRoot->rChild, maxRL, maxRR);
maxRight = max(maxRL, maxRR) + 1;
}
else
{
maxDistRight = 0;
maxRight = 0;
}
return max(max(maxDistLeft, maxDistRight), maxLeft+maxRight);
}
//判断一颗树是不是完全二叉树
// 按层序遍历,当遇到一个节点的左子树为空时,则该节点右子树必须为空且后面节点的左右子树都为空
// 当遇到右子树为空,则后面节点左右子树都为空
bool BTree::IsCompleteBinaryTree(BTreeNode * pRoot)
{
if(pRoot == NULL)
return false;
queue<BTreeNode *> q;
q.push(pRoot);
bool mustHaveNoChild = false;
bool result = true;
while(!q.empty())
{
BTreeNode * pNode = q.front();
q.pop();
if(mustHaveNoChild) // 已经出现了有空子树的节点了,后面出现的必须为叶节点(左右子树都为空)
{
if(pNode->lChild != NULL || pNode->rChild != NULL)
{
result = false;
break;
}
}
else
{
if(pNode->lChild != NULL && pNode->rChild != NULL)
{
q.push(pNode->lChild);
q.push(pNode->rChild);
}
else if(pNode->lChild != NULL && pNode->rChild == NULL)
{
mustHaveNoChild = true;
q.push(pNode->rChild);
}
else if(pNode->lChild == NULL && pNode->rChild != NULL)
{
result = false;
break;
}
else
{
mustHaveNoChild = true;
}
}
}
return result;
}
参考文章:
http://blog.csdn.net/luckyxiaoqiang/article/details/7518888/
http://blog.csdn.net/iqrocket/article/details/8266365#cpp