二叉树类型笔试面试题大总结(含代码)
一、二叉树的遍历-前序、中序、后序以及层次遍历(递归与非递归)
参考另外一篇笔记《二叉树的遍历-递归与非递归 -海子 - 博客园》。
二、重建二叉树,依据前序遍历结果和中序遍历结果
《剑指Offer》面试题6.
思想:递归
代码:
// 《剑指Offer——名企面试官精讲典型编程题》代码
// 著作权所有者:何海涛
struct BinaryTreeNode
{
int m_nValue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;
};
BinaryTreeNode* ConstructCore(int* startPreorder,int* endPreorder,int* startInorder,int* endInorder);
BinaryTreeNode* Construct(int* preorder,int* inorder,int length)
{
if(preorder== NULL|| inorder == NULL|| length<=0)
return NULL;
returnConstructCore(preorder, preorder+ length-1,
inorder,inorder +length-1);
}
BinaryTreeNode* ConstructCore(int* startPreorder,int* endPreorder,int* startInorder,int* endInorder)
{
// 前序遍历序列的第一个数字是根结点的值
int rootValue= startPreorder[0];
BinaryTreeNode* root=new BinaryTreeNode();
root->m_nValue= rootValue;
root->m_pLeft= root->m_pRight= NULL;
if(startPreorder== endPreorder)
{
if(startInorder== endInorder&&*startPreorder==*startInorder)
return root;
else
throw std::exception("Invalid input.");
}
// 在中序遍历中找到根结点的值
int* rootInorder= startInorder;
while(rootInorder<= endInorder&&*rootInorder!= rootValue)
++ rootInorder;
if(rootInorder== endInorder&&*rootInorder!= rootValue)
throw std::exception("Invalid input.");
int leftLength= rootInorder- startInorder;
int* leftPreorderEnd= startPreorder+ leftLength;
if(leftLength>0)
{
//构建左子树
root->m_pLeft=ConstructCore(startPreorder+1, leftPreorderEnd,
startInorder,rootInorder -1);
}
if(leftLength< endPreorder- startPreorder)
{
//构建右子树
root->m_pRight=ConstructCore(leftPreorderEnd+1, endPreorder,
rootInorder+1, endInorder);
}
return root;
}
// ====================测试代码====================
void Test(char* testName,int* preorder,int* inorder,int length)
{
if(testName!= NULL)
printf("%s begins:\n",testName);
printf("The preorder sequence is: ");
for(int i=0; i< length; ++ i)
printf("%d ",preorder[i]);
printf("\n");
printf("The inorder sequence is: ");
for(int i=0; i< length; ++ i)
printf("%d ",inorder[i]);
printf("\n");
try
{
BinaryTreeNode* root= Construct(preorder,inorder, length);
PrintTree(root);
DestroyTree(root);
}
catch(std::exception& exception)
{
printf("Invalid Input.\n");
}
}
三、判断二叉搜索树的后序遍历是否合法
思想:通过根节点将序列划分为左子树序列和右子树序列,他们必须满足的条件是:左子树序列中的所有值小于根节点,右子树中所有值大于根节点,然后递归判断左子树序列和右子树序列。
代码:
// BST:BinarySearch Tree,二叉搜索树
bool VerifySquenceOfBST(int sequence[], int length )
{
if (sequence == NULL || length <=0)
return false ;
int root = sequence[ length -1];
//在二叉搜索树中左子树的结点小于根结点
int i =0;
for(; i < length -1;++ i )
{
if ( sequence [ i ]> root )
break ;
}
//在二叉搜索树中右子树的结点大于根结点
int j = i ;
for(; j < length -1;++ j )
{
if ( sequence [ j ]< root )
return false ;
}
//判断左子树是不是二叉搜索树
bool left = true ;
if ( i >0)
left = VerifySquenceOfBST( sequence , i );
//判断右子树是不是二叉搜索树
bool right = true ;
if ( i < length -1)
right = VerifySquenceOfBST( sequence + i , length - i -1);
return (left && right ); }
四、二叉树中和为某一值的路径
《剑指Offer》面试题25
同样是递归思想。
代码:
void find_path(BinaryTreeNode *root,intexpected_sun){
vector<int>path;
intcur_sum =0;
find_path(root,expected_sun,path,cur_sum);
}
void find_path(BinaryTreeNode *root,intexpected_sun,vector<int>&path,int cur_sum){
cur_sum +=root->m_nValue;
path.push_back(root->m_nValue);
// 当前节点是叶子节点而且路径上节点值的和满足条件
if(expected_sun == cur_sum && NULL ==root->m_pLeft &&NULL == root->m_pRight)
{
//输出路径
vector<int>::iterator iter=path.begin();
cout << "Path:";
for(;iter != path.end();++iter)
{
cout<< *iter<< "";
}
cout << endl;
}
if(root->m_pLeft!=NULL)
{
find_path(root->m_pLeft,expected_sun,path,cur_sum);
}
if(root->m_pRight!=NULL)
{
find_path(root->m_pRight,expected_sun,path,cur_sum);
}
path.pop_back();
cur_sum -=root->m_nValue;
}
五、将二叉搜索树转化为双向链表
思路一:当我们到达某一结点准备调整以该结点为根结点的子树时,先调整其左子树将左子树转换成一个排好序的左子链表,再调整其右子树转换右子链表。最近链接左子链表的最右结点(左子树的最大结点)、当前结点和右子链表的最左结点(右子树的最小结点)。从树的根结点开始递归调整所有结点。
代码:
/
//
Covert a sub binary - search- tree into a sorteddouble- linked list
//Input: pNode - the head of the sub tree
//asRight - whether pNode is the right child of its parent
//Output: if asRight is true, return the least node in the sub-tree
//else return the greatest node in the sub-tree
/
//
BSTreeNode * ConvertNode(BSTreeNode* pNode,bool asRight)
{
if (! pNode)
return NULL;
BSTreeNode * pLeft= NULL;
BSTreeNode * pRight= NULL;
// Convert the left sub-tree
if (pNode-> m_pLeft)
pLeft=ConvertNode(pNode-> m_pLeft,false );
//Connectthegreatestnodeintheleftsub-treetothecurrentnode
if (pLeft)
{
pLeft-> m_pRight= pNode;
pNode-> m_pLeft= pLeft;
}
// Convert the right sub-tree
if (pNode-> m_pRight)
pRight=ConvertNode(pNode-> m_pRight,true );
//Connecttheleastnodeintherightsub-treetothe currentnode
if (pRight)
{
pNode-> m_pRight= pRight;
pRight-> m_pLeft= pNode;
}
BSTreeNode * pTemp= pNode;
// If the current node is the right child ofits parent,
//returnthe leastnodeinthetreewhoserootisthecurrent node
if (asRight)
{
while (pTemp-> m_pLeft)
pTemp= pTemp-> m_pLeft;
}
// If the current node is the left child ofits parent,
//returnthegreatestnodeinthetreewhoserootisthecurrentnode
else
{
while (pTemp-> m_pRight)
pTemp= pTemp-> m_pRight;
}
return pTemp;
}
/
//
Covert a binary search tree into a sorted double- linked list
//Input: the head of tree
//Output: the head of sorted double-linked list
/
//
BSTreeNode * Convert(BSTreeNode* pHeadOfTree)
{
// As wewant to return the headof the sorteddouble-linked list,
// we set the second parameter to be true
returnConvertNode(pHeadOfTree,true );
}
思路二:我们可以中序遍历整棵树。按照这个方式遍历树,比较小的结点先访问。如果我们每访问一个结点,假设之前访问过的结点已经调整成一个排序双向链表,我们再把调整当前结点的指针将其链接到链表的末尾。当所有结点都访问过之后,整棵树也就转换成一个排序双向链表了。
代码:
BinaryTreeNode* Convert(BinaryTreeNode* pRootOfTree)
{
BinaryTreeNode *pLastNodeInList = NULL;
ConvertNode(pRootOfTree,&pLastNodeInList);
//pLastNodeInList指向双向链表的尾结点,
//我们需要返回头结点
BinaryTreeNode *pHeadOfList = pLastNodeInList;
while(pHeadOfList!= NULL&& pHeadOfList->m_pLeft!= NULL)
pHeadOfList= pHeadOfList->m_pLeft;
return pHeadOfList;
}
voidConvertNode(BinaryTreeNode* pNode, BinaryTreeNode** pLastNodeInList)
{
if(pNode== NULL)
return;
BinaryTreeNode *pCurrent = pNode;
if (pCurrent->m_pLeft!= NULL)
ConvertNode(pCurrent->m_pLeft,pLastNodeInList);
pCurrent->m_pLeft=*pLastNodeInList;
if(*pLastNodeInList!= NULL)
(*pLastNodeInList)->m_pRight= pCurrent;
*pLastNodeInList= pCurrent;
if (pCurrent->m_pRight!= NULL)
ConvertNode(pCurrent->m_pRight,pLastNodeInList);
}
六、求二叉树的深度
剑指Offer面试题39.
递归:
intTreeDepth(BinaryTreeNode* pRoot)
{
if(pRoot == NULL)
return 0;
int nLeft = TreeDepth(pRoot->m_pLeft);
int nRight = TreeDepth(pRoot->m_pRight);
return (nLeft > nRight) ? (nLeft + 1) :(nRight + 1);
}
七、判断一棵二叉树是否是平衡二叉树
解法一(常规解法):
分别求左右子树的深度,再进行判断。递归。
此方法会遍历一个节点多次,效率不高。
bool IsBalanced_Solution1 (BinaryTreeNode * pRoot )
{
if ( pRoot == NULL )
return true ;
int left = TreeDepth ( pRoot->m_pLeft );
int right = TreeDepth ( pRoot->m_pRight );
int diff = left - right ;
if ( diff >1|| diff <-1 )
return false ;
return IsBalanced_Solution1 ( pRoot - >m_pLeft )
&& IsBalanced_Solution1 ( pRoot - >m_pRight );
}
解法二(更高效的解法):
解决了遍历一个问题多次的问题。用后序遍历的方式遍历二叉树的每一个节点,在遍历到一个节点之前我们就已经遍历了它的左右子树。只要在遍历每个节点的时候记录深度,就可以一边遍历一边判断每个节点是不是平衡的。
bool IsBalanced_Solution2(BinaryTreeNode * pRoot)
{
int depth =0 ;
return IsBalanced(pRoot,& depth);
}
bool IsBalanced(BinaryTreeNode * pRoot, int* pDepth)
{
if (pRoot == NULL)
{
* pDepth=0 ;
return true ;
}
intleft, right;
if (IsBalanced(pRoot-> m_pLeft,& left)
&& IsBalanced(pRoot-> m_pRight,& right))
{
int diff = left - right;
if (diff <=1&& diff>=-1 )
{
* pDepth=1+ (left> right ? left : right);
return true ;
}
}
returnfalse ;
}
八、求二叉树第K层节点个数
递归解法:
(1)如果二叉树为空或者k<1返回0
(2)如果二叉树不为空并且k==1,返回1
(3)如果二叉树不为空且k>1,返回左子树中k-1层的节点个数与右子树k-1层节点个数之和
参考代码如下:
intGetNodeNumKthLevel(BinaryTreeNode* pRoot,int k)
{
if(pRoot== NULL|| k <1)
return0;
if(k==1)
return1;
int numLeft=GetNodeNumKthLevel(pRoot->m_pLeft, k-1); //左子树中k-1层的节点个数
int numRight=GetNodeNumKthLevel(pRoot->m_pRight, k-1); //右子树中k-1层的节点个数
return (numLeft+ numRight);
}
九、求二叉树中两个节点的最低公共祖先节点
参考另外一篇笔记。
十、求二叉树中两个节点的最大距离
即二叉树中相距最远的两个节点之间的距离。
递归解法:
(1)如果二叉树为空,返回0,同时记录左子树和右子树的深度,都为0
(2)如果二叉树不为空,最大距离要么是左子树中的最大距离,要么是右子树中的最大距离,要么是左子树节点中到根节点的最大距离+右子树节点中到根节点的最大距离,同时记录左子树和右子树节点中到根节点的最大距离。
参考代码如下:
intGetMaxDistance(BinaryTreeNode* pRoot,int& maxLeft,int& maxRight)
{
//maxLeft, 左子树中的节点距离根节点的最远距离
//maxRight, 右子树中的节点距离根节点的最远距离
if(pRoot== NULL)
{
maxLeft =0;
maxRight =0;
return0;
}
int maxLL, maxLR, maxRL, maxRR;
int maxDistLeft, maxDistRight;
if(pRoot->m_pLeft!= NULL)
{
maxDistLeft=GetMaxDistance(pRoot->m_pLeft, maxLL, maxLR);
maxLeft = max(maxLL, maxLR)+1;
}
else
{
maxDistLeft=0;
maxLeft =0;
}
if(pRoot->m_pRight!= NULL)
{
maxDistRight=GetMaxDistance(pRoot->m_pRight, maxRL, maxRR);
maxRight = max(maxRL, maxRR)+1;
}
else
{
maxDistRight=0;
maxRight =0;
}
return max(max(maxDistLeft,maxDistRight), maxLeft+maxRight);
}
十一、判断一棵二叉树是否为完全二叉树
若设二叉树的深度为h,除第 h 层外,其它各层(1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。
有如下算法,按层次(从上到下,从左到右)遍历二叉树,当遇到一个节点的左子树为空时,则该节点右子树必须为空,且后面遍历的节点左右子树都必须为空,否则不是完全二叉树。
boolIsCompleteBinaryTree(BinaryTreeNode* pRoot)
{
if(pRoot== NULL)
returnfalse;
queue<BinaryTreeNode*> q;
q.push(pRoot);
bool mustHaveNoChild=false;
bool result=true;
while(!q.empty())
{
BinaryTreeNode* pNode= q.front();
q.pop();
if(mustHaveNoChild) //已经出现了有空子树的节点了,后面出现的必须为叶节点(左右子树都为空)
{
if(pNode->m_pLeft!= NULL || pNode->m_pRight!= NULL)
{
result=false;
break;
}
}
else
{
if(pNode->m_pLeft!= NULL && pNode->m_pRight!= NULL)
{
q.push(pNode->m_pLeft);
q.push(pNode->m_pRight);
}
elseif(pNode->m_pLeft!= NULL && pNode->m_pRight== NULL)
{
mustHaveNoChild=true;
q.push(pNode->m_pLeft);
}
elseif(pNode->m_pLeft== NULL && pNode->m_pRight!= NULL)
{
result=false;
break;
}
else
{
mustHaveNoChild=true;
}
}
}
return result;
}
参考资料:
http://blog.csdn.net/luckyxiaoqiang/article/details/7518888
二叉树类型笔试面试题大总结(含代码)相关推荐
- 嵌入式笔试面试题(不含编程题)
嵌入式考试面试题(部分) 该说不说很多厉害的up发表了很多资料,我也有查阅一些,下面是我所永远的点点资料,目前只有填空部分,大家如果看了下面的并且完成了记得私发一份哈哈 那么正题开始!!! 填空 在L ...
- php大作业含代码_目标检测 | 目标检测技巧大汇总(含代码与解读)
点击上方"AI算法修炼营",选择加星标或"置顶" 标题以下,全是干货 来自 | 知乎作者丨初识CV来源丨https://zhuanlan.zhihu.com/p ...
- DS二叉树——Huffman编码与解码(不含代码框架)
题目描述 1.问题描述 给定n个字符及其对应的权值,构造Huffman树,并进行huffman编码和译(解)码. 构造Huffman树时,要求左子树根的权值小于.等于右子树根的权值. 进行Huffma ...
- 测试工程师---笔试面试题
测试工程师-笔试面试题 文章目录 测试工程师---笔试面试题 前言 一.代码题 二.问答题 前言 目前面试了大大小小很多公司,投的简历也是数不胜数,看的大部分是校招,尽管如此,还是感觉笔试有一些难度, ...
- BAT及各大互联网公司2014前端笔试面试题:HTML/CSS/JAVASCRIPT
BAT及各大互联网公司2014前端笔试面试题:HTML/CSS/JAVASCRIPT Html篇: 1.你做的页面在哪些流览器测试过?这些浏览器的内核分别是什么? IE: trident内核 Fire ...
- 大公司的Java笔试题汇总(含答案)
大公司的Java笔试题汇总(含答案) 1.下列哪一种叙述是正确的(D ) A. abstract修饰符可修饰字段.方法和类 B. 抽象方法的body部分必须用一对大括号{ }包住 C. 声明抽象方法, ...
- 2014九月十月百度,迅雷,华为,阿里巴巴,最新校招笔试面试题
九月十月百度,迅雷,华为,阿里巴巴,最新校招笔试面试六十题 题记 本博客自2010年10月11日开通以来,已经帮助了一大批人找到工作,特别是连续三年在每一年的9.10月份陪伴了至少三届毕业生找工作的旅 ...
- 2013九月十月百度人搜,阿里巴巴,腾讯华为小米搜狗笔试面试题
九月十月百度人搜,阿里巴巴,腾讯华为小米搜狗笔试面试八十题 引言 自发表上一篇文章至今(事实上,上篇文章更新了近3个月之久),blog已经停了3个多月,而在那之前,自开博以来的21个月每月都不曾断过. ...
- java面试笔试题大汇总
java面试笔试题大汇总 JAVA相关基础知识 1.面向对象的特征有哪些方面 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面.抽象并不打算了解全部问题 ...
最新文章
- ActiveMQ学习笔记03 - 消息持久化
- flask_socketio 用法:
- jvm性能调优实战 -52修复堆内存区域内存溢出问题OutOfMemoryError: Java heap space
- 多项式(polynomial)和 单项式(monomial)
- 华为云战略投入政企市场,发布华为云Stack
- opencv+python视频实时质心显示
- 100道练习题,玩转Numpy模块!(上)
- Convirt管理机Socat驻留进程故障处理
- one vs all -- 将01分类器用于多类分类问题
- 深度技术 GHOSTXPSP3 快速装机 2013圣诞节专版
- 8250u运行matlab,第8代CPU i5-8250U 电脑安装核显 WIN7X64位驱动 - 小众知识
- 中国1-4线城市互联网价值分布
- 一键去“码”的AI,还能认出带上口罩的脸
- Baklib分享|知识管理是企业发展的风向标
- Python骚操作—自动刷抖音
- 计算机科学最权威的期刊和会议[转]
- Nginx学习心得总结第一章
- 2023最新大数据毕设选题
- android 识别中文字体,在 Android 上高效准确的进行 OCR 识别,白描帮你实现
- 搜索进阶之迭代加深搜索
热门文章
- OpenCL_Barrier同步
- NativeScaler()与loss_scaler
- [Unity]导入插件出现编译错误的解决办法:在工程关闭时重新添加一次插件
- SQL 拼接语句输出_一文了解Mybatis中动态SQL的实现
- Vue2.0项目安装Mint-UI - cmd篇
- 如何解决IIS配置报错问题:存储空间不足?
- 功能齐全的交易系统导航网源码
- wordpress主题 阿里百秀XIU v7.7版本
- 频域串联滞后校正matlab,自动控制原理实验七基于MATLAB控制系统频域法串联校正设计.doc...
- mysql 用户与数据_MySQL经验9-用户和数据安全