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

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

定义:

         完全二叉树就是除最后一层外,每一层上的节点数均达到最大值,在最后一层上只缺少右边的若干节点。

         满二叉树是特殊的完全二叉树。

如图:

这些均为完全二叉树:

            
            这个为满二叉树

这些均为不完全二叉树:


解题思路:

1.利用标志位求解

                                     

 

设置标记flag=false,从根节点开始层序遍历入队列,如果队列不为空,则一直循环,遇到第一个没有左孩子或者右孩子的节点,设置标志位为true,则继续向后遍历时遇到有左右孩子的节点时,说明该树不是完全二叉树。

bool IsCompleteBinartTree()
	{
		bool flag = false;     //设置标志位
		queue<Node*> qq;
		qq.push(_root);
		Node* cur = qq.front();
		while (cur)
		{
			if (cur->_left == NULL && cur->_right != NULL)
			{
				return false;
			}
			//当前节点有左右孩子,且之前标志位为true时说明不为完全二叉树
			if (flag == true && ((cur->_left) || (cur->_right)))
			{
				return false;
			}
			//当前节点只要有一个孩子为空,就设置标志位为true
			if (cur->_left == NULL || cur->_right == NULL)
			{
				flag = true;
			}
			if (cur->_left)
			{
				qq.push(cur->_left);    //要依次将队头元素的左右孩子压入队列
			}
			if (cur->_right)
			{
				qq.push(cur->_right);
			}
			qq.pop();    //弹出队头
			if(!qq.empty())
			{
				cur = qq.front();
			}
			else
			{
				cur = NULL;
			}
		}
		return true;
	}
2.优化:辅助队列方法求解,标志位的方法相对要繁琐些

                                                  


代码:

bool IsCompleteBinaryTree()
	{
		queue<Node*> qq;
		qq.push(_root);
		Node* cur = qq.front();
		while (cur)
		{
			qq.push(cur->_left);
			qq.push(cur->_right);
			qq.pop();
			cur = qq.front();     //新的队头
		}
		//出了循环,说明此时队头遇到NULL,如果队列全部为空,即是完全二叉树
		while (!qq.empty())
		{
			if (qq.front())
			{
				return false;
			}
			qq.pop();
		}
		return true;
	}

完整代码:

#include <iostream>
#include <Windows.h>
#include <assert.h>
#include <queue>

using namespace std;

template <class T>
struct BinaryTreeNode
{
	T _data;     //节点数据
	BinaryTreeNode<T>* _left;
	BinaryTreeNode<T>* _right;

	BinaryTreeNode(const T& data)
		:_data(data)
		, _left(NULL)
		, _right(NULL)
	{}
};

template <class T>
class BinaryTree
{
	typedef BinaryTreeNode<T> Node;
public:
	BinaryTree()
		:_root(NULL)
	{}

	~BinaryTree()
	{}

	BinaryTree(const T* a, size_t size, const T& invalid)
	{
		size_t index = 0;    //下标
		_root = _CreatTree(a, size, index, invalid);
	}

	设置标志位方法
	//bool IsCompleteBinaryTree()
	//{
	//	bool flag = false;
	//	queue<Node*> qq;
	//	qq.push(_root);
	//	Node* cur = qq.front();
	//	while (cur)
	//	{
	//		if (cur->_left == NULL && cur->_right != NULL)
	//		{
	//			return false;
	//		}
	//		//当前节点有左右孩子,且之前标志位为true时说明不为完全二叉树
	//		if (flag == true && ((cur->_left) || (cur->_right)))
	//		{
	//			return false;
	//		}
	//		//当前节点只要有一个孩子为空,就设置标志位为true
	//		if (cur->_left == NULL || cur->_right == NULL)
	//		{
	//			flag = true;
	//		}
	//		if (cur->_left)
	//		{
	//			qq.push(cur->_left);    //要依次将队头元素的左右孩子压入队列
	//		}
	//		if (cur->_right)
	//		{
	//			qq.push(cur->_right);
	//		}
	//		qq.pop();    //弹出队头
	//		if(!qq.empty())
	//		{
	//			cur = qq.front();
	//		}
	//		else
	//		{
	//			cur = NULL;
	//		}
	//	}
	//	return true;
	//}


	//利用辅助队列求解
	bool IsCompleteBinaryTree()
	{
		queue<Node*> qq;
		qq.push(_root);
		Node* cur = qq.front();
		while (cur)
		{
			qq.push(cur->_left);
			qq.push(cur->_right);
			qq.pop();
			cur = qq.front();     //新的队头
		}
		//出了循环,说明此时队头遇到NULL,如果队列全部为空,即是完全二叉树
		while (!qq.empty())
		{
			if (qq.front())
			{
				return false;
			}
			qq.pop();
		}
		return true;
	}
protected:
	Node* _CreatTree(const T* a, size_t size, size_t& index, const T& invalid)
	{
		assert(a);
		Node* root = NULL;
		if (index < size && a[index] != invalid)
		{
			root = new Node(a[index]);
			root->_left = _CreatTree(a, size, ++index, invalid);
			root->_right = _CreatTree(a, size, ++index, invalid);
		}
		return root;
	}
protected:
	Node* _root;    //根节点
};

#include "IsCompleteBinaryTree.h"

void TestIsCompleteBinaryTree()
{
	int a[] = { 0, 1, 3, '#', '#', '#', 2 };
	size_t size = sizeof(a) / sizeof(a[0]);
	BinaryTree<int> www(a, size, '#');
	cout <<"是否为完全二叉树:"<< www.IsCompleteBinaryTree() << endl;
}

int main()
{
	TestIsCompleteBinaryTree();
	system("pause");
	return 0;
}


  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值