如何确定二叉树是否完整?

时间:2009-09-18 04:59:54

标签: algorithm binary-tree

完整的二叉树被定义为二叉树,其中除了可能是最深的之外,每个级别都被完全填充。在最深层次上,所有节点必须尽可能远离。

我认为一个简单的递归算法能够判断给定的二叉树是否完整,但我似乎无法弄明白。

16 个答案:

答案 0 :(得分:5)

类似于:

height(t) = if (t==NULL) then 0 else 1+max(height(t.left),height(t.right))

你有:

perfect(t) = if (t==NULL) then 0 else { 
                  let h=perfect(t.left)
                  if (h != -1 && h==perfect(t.right)) then 1+h else -1
             }

如果叶子不是全部在同一深度,或者任何节点只有一个孩子,则perfect(t)返回-1;否则,它返回高度。

编辑:这是为了“完整”=“一个完美的二叉树是一个完整的二叉树,其中所有叶子处于相同的深度或相同的水平。1(这被模糊地称为完整的二叉树。)“(Wikipedia)。

这是一个递归检查:“一个完整的二叉树是一个二叉树,其中除了可能是最后一个级别之外,每个级别都被完全填满,所有节点都尽可能地离开。”如果树不完整则返回(-1,false),否则(高度,满)如果是,则为full == true如果它是完美的。

complete(t) = if (t==NULL) then (0,true) else { 
                  let (hl,fl)=complete(t.left)
                  let (hr,fr)=complete(t.right)                      
                  if (fl && hl==hr) then (1+h,fr)
                  else if (fr && hl==hr+1) then (1+h,false)
                  else (-1,false)
              }

答案 1 :(得分:3)

最简单的程序是:

  1. 查找树的深度(简单算法)。
  2. 计算树中节点的数量(通过在访问任何节点时遍历和增加计数器)。
  3. 对于级别为 d 的完整二叉树,节点数等于 pow(2,d + 1)-1
  4. 如果条件满足树,则是完整的二叉树,否则不是。

    这是一个简单的算法,如果你的编码器足够好,那么把它变成一个工作代码应该不是问题。

答案 2 :(得分:2)

//Helper function

int depth (struct tree * n)
{
   int ld,rd;

   if (n == NULL) return 0;

   ld=depth(n->left);
   ld=depth(n->right);

   if (ld>rd)
      return (1+ld);
   else
      return (1+rd);

}


//Core function

int isComplete (struct tree * n)
{
   int ld,rd;

   if (n == NULL) return TRUE;

   ld=depth(n->left);
   rd=depth(n->right);

   return(ld==rd && isComplete(n->left) && isComplete(n->right));

}

答案 3 :(得分:1)

要使一棵树完整

  

高度(左)==高度(右)   要么   高度(左)== 1+高度(右)

    bool isComplete (struct Node* root){
    if(root==NULL)
    return true;                  // Recur for left and right subtree 
    bool flag=false;
    int option1=height(root->left);
    int option2=height(root->right);
    if(option1==option2||option1==option2+1)
    flag=true;
    return flag&&isComplete(root->left)&&isComplete(root->right);
    }

答案 4 :(得分:0)

您可以组合子树中的三条信息:

  • 子树是否完整

  • 最大高度

  • 最小高度(等于最大高度或最大高度 - 1)

答案 5 :(得分:0)

我认为可能有一种可能的算法可以解决这个问题。考虑树:

Level 0:    a  
Level 1:  b   c  
Level 2: d e f g  
  • 我们采用广度优先遍历。

  • 对于队列中每个排队的元素,我们必须按顺序进行三次检查:

    1. 如果有一个孩子或没有孩子终止;否则,请检查2.
    2. 如果两个孩子都存在,则设置全局标志= true。
      1. 将队列中每个节点的标志设置为true:flag [b] = flag [c] = true。
      2. 检查每个条目是否已离开n右子n然后设置标志或将其重置为false。
      3. (Dequeue)if(queue_empty())
                  比较所有节点标志[] ...如果全部为true global_flag = true,则为global_flag = false。
      4. 如果global_flag = true,请继续使用广度中的下一级别进行首次遍历,否则终止

优点:可能无法遍历整棵树 开销:维护标志条目

答案 6 :(得分:0)

您可以通过比较每个节点的子节点的高度来递归地执行此操作。最多可能有一个节点,其中左边的孩子的高度恰好比正确的孩子高一个;所有其他节点必须完美平衡。

答案 7 :(得分:0)

以下代码仅处理每种可能的情况。沿途获得树高以避免另一次递归。

enum CompleteType
{
    kNotComplete = 0,
    kComplete = 1, // Complete but not full
    kFull = 2,
    kEmpty = 3
};

CompleteType isTreeComplete(Node* node, int* height)
{
    if (node == NULL)
    {
        *height = 0;
        return kEmpty;
    }

    int leftHeight, rightHeight;

    CompleteType leftCompleteType = isTreeComplete(node->left, &leftHeight);
    CompleteType rightCompleteType = isTreeComplete(node->right, &rightHeight);

    *height = max(leftHeight, rightHeight) + 1;

    // Straight forwardly treat all possible cases
    if (leftCompleteType == kComplete && 
        rightCompleteType == kEmpty &&
        leftHeight == rightHeight + 1)
        return kComplete;

    if (leftCompleteType == Full)
    {
        if (rightCompleteType == kEmpty && leftHeight == rightHeight + 1)
            return kComplete;
        if (leftHeight == rightHeight)
        {
            if (rightCompleteType == kComplete)
                return kComplete;
            if (rightCompleteType == kFull)
                return kFull;
        }
    }

    if (leftCompleteType == kEmpty && rightCompleteType == kEmpty)
        return kFull;

    return kNotComplete;
}

bool isTreeComplete(Node* node)
{
    int height;
    return (isTreeComplete(node, &height) != kNotComplete);
}

答案 8 :(得分:0)

您还可以使用级别顺序遍历来解决此问题。程序如下:

  1. 存储向量中遇到的节点的数据元素
  2. 如果节点为NULL,则存储特殊号码(INT_MIN)
  3. 跟踪最后访问的非空节点 - lastentry
  4. 现在遍历矢量直到lastentry。如果您遇到INT_MIN,则表示树未完成。否则它是一个完整的二叉树。
  5. 这是一个c ++代码:

    我的树节点是:

    struct node{
        int data;
        node *left, *right;
    };
    
    void checkcomplete(){//checks whether a tree is complete or not by performing level order traversal
        node *curr = root;
        queue<node *> Q;
        vector<int> arr;
        int lastentry = 0;
        Q.push(curr);
        int currlevel = 1, nextlevel = 0;
        while( currlevel){
            node *temp = Q.front();
            Q.pop();
            currlevel--;
            if(temp){
                arr.push_back(temp->data);
                lastentry = arr.size();
                Q.push(temp->left);
                Q.push(temp->right);
                nextlevel += 2;
            }else
                arr.push_back(INT_MIN);
            if(!currlevel){
                currlevel = nextlevel;
                nextlevel = 0;
            }
        }
        int flag = 0;
        for( int i = 0; i<lastentry && !flag; i++){
            if( arr[i] == INT_MIN){
                cout<<"Not a complete binary tree"<<endl;
                flag = 1;
            }
        }
        if( !flag )
            cout<<"Complete binary tree\n";
    }
    

答案 9 :(得分:0)

private static boolean isCompleteBinaryTree(TreeNode root) {

if (root == null) {
    return false;
} else {
    boolean completeFlag = false;
    List<TreeNode> list = new ArrayList<TreeNode>();
    list.add(root);
    while (!list.isEmpty()) {
        TreeNode element = list.remove(0);
        if (element.left != null) {
            if (completeFlag) {
                return false;
            }
        list.add(element.left);
        } else {
            completeFlag = true;
        }
        if (element.right != null) {
            if (completeFlag) {
                return false;
            }
        list.add(element.right);
        } else {
            completeFlag = true;
        }
    }
        return true;
    }
}

参考: 请查看以下链接以获取详细说明 http://www.geeksforgeeks.org/check-if-a-given-binary-tree-is-complete-tree-or-not/

答案 10 :(得分:0)

感谢@Jonathan Graehl的伪代码。 我用Java实现了它。我已经针对迭代版本进行了测试。它就像一个魅力!

public static boolean isCompleteBinaryTreeRec(TreeNode root){
//      Pair notComplete = new Pair(-1, false);
//      return !isCompleteBinaryTreeSubRec(root).equalsTo(notComplete);
    return isCompleteBinaryTreeSubRec(root).height != -1;
}

public static boolean isPerfectBinaryTreeRec(TreeNode root){
    return isCompleteBinaryTreeSubRec(root).isFull;
}

public static Pair isCompleteBinaryTreeSubRec(TreeNode root){
    if(root == null){
        return new Pair(0, true);
    }

    Pair left = isCompleteBinaryTreeSubRec(root.left);
    Pair right = isCompleteBinaryTreeSubRec(root.right);

    if(left.isFull && left.height==right.height){
        return new Pair(1+left.height, right.isFull);
    }

    if(right.isFull && left.height==right.height+1){
        return new Pair(1+left.height, false);
    }

    return new Pair(-1, false);
}

private static class Pair{
    int height;         
    boolean isFull;     

    public Pair(int height, boolean isFull) {
        this.height = height;
        this.isFull = isFull;
    }

    public boolean equalsTo(Pair obj){
        return this.height==obj.height && this.isFull==obj.isFull;
    }
}

答案 11 :(得分:0)

这是一个用于检查二叉树是否完整的C代码:

struct node
{
    int data;
    struct node * left;
    struct node * right;
};
int flag;
int isComplete(struct node *root, int depth)
{
    int ld, rd;
    if (root==NULL) return depth;
    else
    {
        ld =  isComplete(root->left,depth+1);
        rd = isComplete(root->right, depth+1);
        if (ld==-1 || rd==-1) return -1;
        else if (ld==rd) return ld;
        else if (ld==rd-1 && flag==0)
        {
            flag=1;
            return rd;
        }
        else return -1;
    }
}

它的工作方式是:

  • 如果左子树的深度与右子树的深度相同,则返回雇佣人的深度。

  • 如果左子树的深度比右子树的深度多一个,它会在hirarchy中返回右子树的深度并启用该标志。

  • 如果发现已设置左子树和右子树和标志的深度,则它会在层次结构中返回-1。

  • 最后,如果函数返回-1,则它不是完整的子树,否则返回的值是树的最小深度。

答案 12 :(得分:0)

bool isComplete (struct Node* root){
    if(root==NULL)
    return true;                  // Recur for left and right subtree 
    bool flag=false;
    int option1=height(root->left);
    int option2=height(root->right);
    if(option1==option2||option1==option2+1)
    flag=true;
    return flag&&isComplete(root->left)&&isComplete(root->right);
    }

如果您认为有用,请视为正确答案。

答案 13 :(得分:0)

首先,计算二叉树中的节点数。编写一个递归函数。如果接收到的节点为null,则返回true。如果节点的索引大于或等于节点数,则树不是二进制的。如果这两个都没有发生,请检查左侧和右侧子树。 导入java.util.LinkedList; 导入java.util.Queue;

public class FBCompleteTree {

    /*
    public class TreeNode {

        Integer val;
        TreeNode left;
        TreeNode right;

        TreeNode(Integer x) {
            val = x;
        }

    }
     */

    public static void main(String[] args) {
        TreeNode node1 = new TreeNode(1);
        TreeNode node2 = new TreeNode(2);
        TreeNode node3 = new TreeNode(3);
        TreeNode node4 = new TreeNode(4);
        TreeNode node5 = new TreeNode(5);
        TreeNode node6 = new TreeNode(6);
        node1.left = node2;
        node1.right = node3;
        node2.left = node4;
        node2.right = node5;
        node3.left = node6;
        FBCompleteTree completeTree = new FBCompleteTree();
        System.out.println(completeTree.isCompleteTree(node1));
    }

    public boolean isCompleteTree(TreeNode root) {
        int nodeCount = countNodes(root);
        // The index of the root is always zero.
        return isComplete(root, nodeCount, 0);
    }

    /**
     * Tells us if a binary tree is complete or not.
     *
     * @param node      The current node
     * @param nodeCount The node counts of the tree
     * @param index     The index of the node
     * @return If a binary tree is complete or not
     */
    private boolean isComplete(TreeNode node, int nodeCount, int index) {
    // Null is a complete binary tree
    if (node == null)
        return true;
    // In a complete binary tree, index of all the nodes should be less than nodes count.
    if (index >= nodeCount)
        return false;
    /*
    The index of the left child is 2*i+1 and the right child is 2*i+2 in a binary tree.
     */
    return isComplete(node.left, nodeCount, 2 * index + 1)
            &&
            isComplete(node.right, nodeCount, 2 * index + 2);
}

    /**
     * Counts the number of nodes.
     *
     * @param root The root of the tree
     * @return The number of nodes in the tree
     */
    private int countNodes(TreeNode root) {
        if (root == null)
            return 0;
        Queue<TreeNode> q = new LinkedList<>();
        q.add(root);
        int counter = 0;
        while (!q.isEmpty()) {
            TreeNode currentNode = q.poll();
            counter++;
            TreeNode l = currentNode.left;
            if (l != null) {
                q.add(l);
            }
            TreeNode r = currentNode.right;
            if (r != null) {
                q.add(r);
            }
        }
        return counter;
    }

}

我希望这会有所帮助。

答案 14 :(得分:-1)

您可以通过确保具有正确子项的每个节点也具有左子项来判断给定二叉树是否是左完整二叉树 - 更好地称为二进制堆。见下文

bool IsLeftComplete(tree)
{

  if (!tree.Right.IsEmpty && tree.Left.IsEmpty)
    //tree has a right child but no left child, therefore is not a heap
    return false;    

  if (tree.Right.IsEmpty && tree.Left.IsEmpty)  
    //no sub-trees, thus is leaf node. All leaves are complete
    return true;

  //this level is left complete, check levels below
  return IsLeftComplete(tree.Left) && IsLeftComplete(tree.Right);
}

答案 15 :(得分:-1)

int height (node* tree, int *max, int *min) {

  int lh = 0 , rh = 0 ;
  if ( tree == NULL )
    return 0;
  lh = height (tree->left,max,min) ;
  rh = height (tree->right,max,min) ;
  *max = ((lh>rh) ? lh : rh) + 1 ;
  *min = ((lh>rh) ? rh : lh) + 1 ;
  return *max ;
}

void isCompleteUtil (node* tree, int height, int* finish, int *complete) {
  int lh, rh ;
  if ( tree == NULL )
    return ;
  if ( height == 2 ) {
    if ( *finish ) {
      if ( !*complete )
        return;
      if ( tree->left || tree->right )
        *complete = 0 ;
      return ;
    }
    if ( tree->left == NULL && tree->right != NULL ) {
      *complete = 0 ;
      *finish = 1 ;
    }
    else if ( tree->left == NULL && tree->right == NULL )
      *finish = 1 ;
    return ;
  }
  isCompleteUtil ( tree->left, height-1, finish, complete ) ;
  isCompleteUtil ( tree->right, height-1, finish, complete ) ;
}

int isComplete (node* tree) {
  int max, min, finish=0, complete = 1 ;
  height (tree, &max, &min) ;
  if ( (max-min) >= 2 )
    return 0 ;
  isCompleteUtil (tree, max, &finish, &complete) ;
  return complete ;
}