判断一棵二叉树是否是完全二叉树
定义:
完全二叉树就是除最后一层外,每一层上的节点数均达到最大值,在最后一层上只缺少右边的若干节点。
满二叉树是特殊的完全二叉树。
如图:
这些均为完全二叉树:
这个为满二叉树
这些均为不完全二叉树:
解题思路:
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;
}