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

本文介绍了完全二叉树的特点及通过广度优先遍历来判断一个二叉树是否为完全二叉树的方法,并针对特殊情况进行代码优化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.完全二叉树的特点(来自专业定义)


看到上面完全二叉树的特点,我可以将其特点按照自己的理解归纳为以下几点:

(1):若二叉树最下面一层有节点出现,那么这个节点一定是是从左到右依次排列,若只有一个孩子,那么这个孩子一定是左孩子而不是右孩子(特殊情况,空树和只有根节点的树都是完全二叉树)。

(2)要么最后一层全为叶子节点,否则以它为根节点的孩子一定是从左依次排列的)。

2.解决这个问题的办法(全部采用广度优先遍历的方法进行遍历,并使用队列这个结构操作数据):

只要当前节点有一个孩子不为空,那么就将它的左右孩子都压入队列,出队列第一次到NULL节点时,做一个标记,直到队列为空后面都再无非空节点出现,那么它就一定是完全二叉树;反之若第一次出现NULL节点后再出现非空节点,那么它一定就不满足完全二叉树的定义。

3.代码实现

bool _IsCompleteTree(Node* root)
	{
		if (root == NULL)
		{
			return true;
		}
		if (root->_left == NULL&&root->_right == NULL)
		{
		return true;
		}
		queue<Node*> q;
		bool flag = false;
		q.push(root);
		while (!q.empty())
		{
			Node* Front = q.front();
			q.pop();
			if (Front != NULL && (Front->_left || Front->_right))
			{
				q.push(Front->_left);
				q.push(Front->_right);
			}
			if (Front == NULL)
			{
				flag = true;
			}
			else
			{
				flag = false;
			}
		}
		if (flag == false)
		{
			return false;
		}
		else
		{
			return true;
		}
	}


(在这会出现bug,具体的问题出现紧跟着提出)

<strong style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"><span style="font-size:18px;">这样写,会有一种情况出现误判,解释如下:</span></strong>


第一次出现NULL节点后,将flag置为true,后面遇到一个非空节点再将flag置为false,此时队列不为空,继续出队列,遇到NULL节点将flag置为true,此时队列为空,出循环,很明显,这个时候得到的结果就是错误的。

所以为了解决这种情况的误判,我们必须做以标记,在第一次出现NULL节点时并且后面紧跟着有非空节点出现时,直接返回,没有再进行判断的必要了。修改后代码如下:

bool _IsCompleteTree(Node* root)
	{
		if (root == NULL)
		{
			return true;
		}
		if (root->_left == NULL&&root->_right == NULL)
		{
			return true;
		}
		queue<Node*> q;
		bool flag = false;
		int count = 0;
		q.push(root);
		while (!q.empty())
		{
			Node* Front = q.front();
			q.pop();
			if (Front != NULL && (Front->_left||Front->_right))
			{
                           q.push(Front->_left);
			   q.push(Front->_right);
			}
			if (Front== NULL)
			{
				flag = true;
				count++;
			}
			else
			{
				if (count == 1)
				{
					flag = false;
					return flag;
				}
				else
				{
					flag = false;
				}
				
			}
		}
		if (flag == false)
		{
			return false;
		}
		else
		{
			return true;
		}
	}


<strong style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"><span style="font-size:18px;">测试用例可以多给以下几组:</span></strong>

int array[] = { 1, 2, 3, '#', '#', 4, '#','#',5,6,'#','#',7,'#',8 };//无左孩子,有右孩子
int array[] = { 1, 2, 3, 8, '#', '#', '#', 4, '#', '#', 5, 6, '#', '#', 7 };//最下面一层有一个孩子,且是左孩子
array[] = { 1, 2, 3, '#', 9, 4, '#', '#', 5, 6, '#', '#', 7, '#', '#' };//最下面一层有一个孩子,且是右孩子
int array[] = { 1, 2, 3, '#', '#', 4, '#', '#', 5, 6, '#', '#', 7, '#', '#' };//最下面一层全部是叶子节点
int array[] = { 1, 2, 3, 8, '#', '#','#', 4,9, '#', '#','#', 5, 6, '#', '#', 7 };//上迎面解释的这种情况
int array[] = { 1 };//只有一个根节点

int array[] = { NULL};//空树


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值