二叉树的五道面试题

本文涵盖了五道经典的二叉树面试题目,包括判断是否为完全二叉树、求最远结点距离、从前序和中序遍历重建二叉树、寻找最近公共祖先以及将二叉搜索树转化为有序双向链表。对于每道题目,文章详细阐述了解题思路和方法。



1、判断一棵树是否是完全二叉树;

2、求二叉树中最远两个结点的距离;

3、由前序和中序遍历序列重建二叉树 (前序序列:1 2 3 4 5 6 - 中序序列:3 2 4 1 6 5);

4、求二叉树两个结点的最近公共祖先;

5、将二叉搜索树转化成有序的双向链表;



判断一棵树是否是完全二叉树


要想判断一颗树是否是完全二叉树,你得先知道什么是完全二叉树。

完全二叉树:
①若树的高度为h,则除第h层,上面的h-1层都是达到最大个数。
②第h层的结点都集中在最左边。

当你知道了完全二叉树的性质,这道题就好做了。有很多种解法。这里我给出一种使用 队列的解法。

我们先看一下完全二叉树与非完全二叉树的区别:



我们可以看到, 将完全的二叉树的所有结点push到队列里之后,有连续的非NULL结点。中间没有NULL打断。而非完全二叉树非空结点之间右NULL打断。我们可以根据这一区别来判断一棵树是否是完全二叉树。


代码:
//队列法
//队列法
bool IsCompleteTree()
{
	if (_root == NULL)
	{
		return true;
	}
	Node* root = _root;
	queue<Node*> q;//建立队列
	q.push(root);//先将根节点入队列

	//层序遍历,将结点依次入队列
	while (1)
	{
		q.push(root->_left);
		q.push(root->_right);
		q.pop();
		if (q.front() != NULL)
		{
			root = q.front();
		}
		else
		{
			break;//遇到空结点就退出循环
		}

	}
	//遇到空结点,判断后面是否还有空结点
	while (!q.empty())
	{
		Node* ret = q.front();
		if (ret != NULL)
		{
			return false;
		}
		q.pop();
	}
	return true;
}

还有一种时间空间复杂度较为复杂的解法,使用了递归。我将代码放到这里,感兴趣的可以研究下。
递归法:
//递归法
bool IsCompleteTree()
{
	if (_root == NULL)
	{
		return true;
	}
	return __IsCompleteTree(_root);
}
//递归判断
bool __IsCompleteTree(Node* root)
{
	if (root == NULL)
	{
		return true;
	}
	if (root->_left == NULL && root->_right != NULL)
	{
		return false;
	}
	//递归,求每一个节点的左右高度
	int left = __GetHigh(root->_left) + 1;
	int right = __GetHigh(root->_right) + 1;
	if (left - right > 1)//当其中某个节点的左右高度差大于1的时候,就不满足完全二叉树
	{
		return false;
	}
	return __IsCompleteTree(root->_left) && __IsCompleteTree(root->_right);
}


求二叉树中最远两个结点的距离

看到这个题,一般大家会有一个思想误区:最远的两个结点是左子树最深结点和右子树最深结点。不是!千万不要这样想!

最远结点,即为相距路径最长的两个结点,例如下面两种情况:



最优解法:利用递归( 后序递归),划分子问题。
子问题模型:传一个全局变量Max(最远距离),初值设为0,传参类型为传引用。求取当前结点cur左右子树的深度并进行比较,返回较深的子树的深度的值。在返回前,将左右子树的深度相加求的和,与Max进行比较,若和大于Max,将和的值赋给Max。

例如:


我们在写代码的时候不要递归到一个结点就对其左右子树求高度。这样会大大增加工作量,降低了程序的效率。采用后序递归,先递归左子树,再递归右子树。将子树高度层层返回,会是最优的解法。令时间复杂度达到O(N)。

代码:


 
(1)非递归定义 树(tree)是由n(n≥0)个结点组成的有限集合。n=0的树称为空树;n>0的树T: ① 有且仅有一个结点n0,它没有前驱结点,只有后继结点。n0称作树的根(root)结点。 ② 除结点外n0 , 其余的每一个结点都有且仅有一个直接前驱结点;有零个或多个直接后继结点。 (2)递归定义 一颗大树分成几个大的分枝,每个大分枝再分成几个小分枝,小分枝再分成更小的分枝,… ,每个分枝也都是一颗树,由此我们可以给出树的递归定义。 树(tree)是由n(n≥0)个结点组成的有限集合。n=0的树称为空树;n>0的树T: ① 有且仅有一个结点n0,它没有前驱结点,只有后继结点。n0称作树的根(root)结点。 ② 除根结点之外的其他结点分为m(m≥0)个互不相交的集合T0,T1,…,Tm-1,其中每个集合Ti(0≤i<m)本身又是一棵树,称为根的子树(subtree)。 2、掌握树的各种术语: (1) 父母、孩子与兄弟结点 (2) 度 (3) 结点层次、树的高度 (4) 边、路径 (5) 无树、有树 (6) 森林 3、二叉树的定义 二叉树(binary tree)是由n(n≥0)个结点组成的有限集合,此集合或者为空,或者由一个根结点加上两棵分别称为左、右子树的,互不相交的二叉树组成。 二叉树可以为空集,因此根可以有空的左子树或者右子树,亦或者左、右子树皆为空。 4、掌握二叉树的五个性质 5、二叉树的二叉链表存储。
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值