您的位置:首页 > 职场人生

二叉树经典面试题4~判断一棵树是否是完全二叉树

2017-07-27 19:03 381 查看

转载:点击打开链接

二叉树经典面试题4~判断一棵树是否是完全二叉树

 一.问题描述

 
有一棵树判断该树是否是完全二叉树?

二.问题分析

1.完全二叉树的定义?

  判断一棵树是否是完全二叉树,首先要知道什仫是完全二叉树?完全二叉树就是除最后一层外,每一层上的结点数均达到最大值;在最后一层上只缺少右边的若干结点。

若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。  
  
完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。  
  
一棵二叉树至多只有最下面的两层上的结点的度数可以小于2,并且最下层上的结点都集中在该层最左边的若干位置上,则此二叉树成为完全二叉树。  

   


 2.如何判断一棵树是完全二叉树?

    在了解了完全二叉树的概念之后,相信读者应该都会判定一颗树是否是完全二叉树了,根据完全二叉树的定义,我们知道完全二叉树的前h-1是满二叉树,而最后一层又是从左到右没有间隔的,如果对这棵树进行层序遍历会发生什仫情况呢?详细介绍见下。在这里我提到两种判断完全二叉树的方法:

    1).标记法

     


    设置标记flag=false,如上图所示,从根结点开始层序遍历入队列,如果队列不为空,一直循环。遇到第一个没有左孩子或者右孩子的结点,设置标记位flag=true,如果继续入队列再次遇到存在孩子的结点一定不是完全二叉树。

//设置标志位的方法  
bool IsCompleteBinaryTree1()  
{  
    bool flag=false;  
    queue<Node *>q;  
    q.push(_root);  
    Node *cur=q.front();  
    while (cur)  
    {  
        //有右孩子无左孩子  
        if(cur->_left == NULL && cur->_right != NULL)  
            return false;  
        //标志位为true并且当前结点存在孩子  
        if(flag == true && (cur->_left || cur->_right))  
            return false;  
        //如果当前结点少一个孩子  
        if(cur->_left == NULL || cur->_right == NULL)  
            flag=true;  
        if(cur->_left)  
            q.push(cur->_left);  
        if(cur->_right)  
            q.push(cur->_right);  
        q.pop();  
        if(!q.empty())  
            cur=q.front();  
        else  
            cur=NULL;  
    }  
    return true;  
}  

     2).剩余队列判空法

     突然发现使用上述标记法要考虑的情况很多,不太方便,于是又提出了另一种方法,就是剩余队列判空法

     这个方法同样的用到了队列这种辅助结构,那仫如何只通过队列这个结构来判断一棵树是否是完全二叉树呢?试想一下,如果我们把一棵树的所有结点,包括叶子结点的左右空孩子都通过层序遍历入队列会发生什仫情况?详细的分析见下图:

      


      


[cpp]
view plain
copy

print?

//利用辅助队列的办法  
bool IsCompleteBinaryTree2()  
{  
    queue<Node *>q;  
    q.push(_root);  
    Node *cur=q.front();  
    //按照层序遍历的办法入队列直到遇到第一个NULL停止  
    while (cur)  
    {  
        q.push(cur->_left);  
        q.push(cur->_right);  
        q.pop();  
        cur=q.front();  
    }  
    //如果队列中全为NULL则是完全二叉树,否则不是  
    while(!q.empty())  
    {  
        if(q.front())  
            return false;  
        q.pop();  
    }  
    return true;  
}  

 三.完整的代码实现

[cpp]
view plain
copy

print?

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(const T*a,size_t size,const T& invalid)  
    {  
        size_t index=0;  
        _root=_CreatTree(a,size,index,invalid);  
    }  
    //设置标志位的方法  
    bool IsCompleteBinaryTree1()  
    {  
        bool flag=false;  
        queue<Node *>q;  
        q.push(_root);  
        Node *cur=q.front();  
        while (cur)  
        {  
            //有右孩子无左孩子  
            if(cur->_left == NULL && cur->_right != NULL)  
                return false;  
            //标志位为true并且当前结点存在孩子  
            if(flag == true && (cur->_left || cur->_right))  
                return false;  
            //如果当前结点少一个孩子  
            if(cur->_left == NULL || cur->_right == NULL)  
                flag=true;  
            if(cur->_left)  
                q.push(cur->_left);  
            if(cur->_right)  
                q.push(cur->_right);  
            q.pop();  
            if(!q.empty())  
                cur=q.front();  
            else  
                cur=NULL;  
        }  
        return true;  
    }  
    //利用辅助队列的办法  
    bool IsCompleteBinaryTree2()  
    {  
        queue<Node *>q;  
        q.push(_root);  
        Node *cur=q.front();  
        //按照层序遍历的办法入队列直到遇到第一个NULL停止  
        while (cur)  
        {  
            q.push(cur->_left);  
            q.push(cur->_right);  
            q.pop();  
            cur=q.front();  
        }  
        //如果队列中全为NULL则是完全二叉树,否则不是  
        while(!q.empty())  
        {  
            if(q.front())  
                return false;  
            q.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;  
};  
void testIsCompleteTree()  
{  
    //int array[]={0,1,3,'#','#','#',2,4,'#','#',5};    //false  
    //int array[]={0,1,3,'#','#',4,'#','#',2,5,'#','#','#'}; //true  
    //int array[]={0,1,3,'#','#',4,'#','#',2};  //true  
    int array[]={0,1,3,'#','#','#',2};  
    size_t size=sizeof(array)/sizeof(array[0]);  
    BinaryTree<int> bt(array,size,'#');  
    bool ret=bt.IsCompleteBinaryTree2();  
    if(ret == true)  
        cout<<"是完全二叉树"<<endl;  
    else  
        cout<<"不是完全二叉树"<<endl;  
}  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: