算法-完全二叉树

目录

一、满二叉树

二、完全二叉树

三、判断是不是完全二叉树

总结


前言

二叉树作为常见的数据结构,在面试中也经常出现,所以在此记录一些容易忘掉或者容易混淆的二叉树性质和在刷题中碰到的算法。


一、满二叉树

满二叉树:深度为k拥有2^k - 1个节点的二叉树称为满二叉树,如下图:

算法-完全二叉树_第1张图片

二叉树的深度:就是树中距离根节点最远的节点所处的层次,只有一个根节点的树的深度为1。上图中树的深度为4。

二、完全二叉树

 算法-完全二叉树_第2张图片

完全二叉树的概念:叶子节点只能出现在最下层和次下层,而且最下层的叶子结点集中在树的左部,可以理解为每一层的节点之间不能出现空。上图中如果5号节点有叶子节点,而4号节点只有左节点,那么这样的树就不是完全二叉树了。

三、判断是不是完全二叉树

知道了完全二叉树的性质后,就可以愉快的写代码了,牛客、leetcode上都有类似的题目,给你一个根节点,判断这棵树是不是完全二叉树:

算法-完全二叉树_第3张图片

 这里只以判断是否是完全二叉树作为例子。

算法-完全二叉树_第4张图片

 算法思想:采用树的层序遍历,从左往右依次遍历二叉树的节点,这里需要使用一个队列记录节点。层序遍历就是将队列头部节点的孩子节点放入队列中,然后队列头部节点弹出。

queue := make([]*TreeNode, 0)            // 队列
queue = append(queue, root)              // 往队列中添加头节点
for len(queue) != 0 {
     cur := queue[0]                     // 队列头部节点
     queue = queue[1:]                   // 弹出头节点
     queue = append(queue, cur.Left)     // 往队列尾部加入头节点的左孩子
     queue = append(queue, cur.Right)    // 往队列尾部加入头节点的右孩子
}

上面代码不管队首节点的孩子节点是否为空都加入到队尾,如果是普通的层序遍历打印节点的话,需要判断队首节点的孩子节点是否为空,不为空才添加。

当然判断是否是完全二叉树代码需要做一点修改,代码中再定义一个布尔类型的变量flag用于记录是否遇到了空节点,初始值为false,表示没有遇到孩子节点不双全的节点,例如在遍历到第三层的4号节点时队列中的情况为: 

算法-完全二叉树_第5张图片

可以看到有颜色的节点分别是4号节点的左右孩子,其中左孩子为空,然后4号节点出队,继续遍历。当5、6、7号节点都出队时,队列中的情况:

算法-完全二叉树_第6张图片

当前队首节点为空节点,将flag设为true表示遇到了空节点,根据完全二叉树的性质, 采用层序遍历时,当出现空节点后,该层右边及下一层都不能再出现节点了,而此时队列不为空,说明空节点右边或者下层还有节点,那么这个树就不是完全二叉树了。所以最终代码如下:

func isAll(root *TreeNode) bool {
    if root == nil {
        return true
    }
    flag := false                    // 是否遇到空节点
    queue := make([]*TreeNode, 0)    // 初始化队列
    queue = append(queue, root)      // 将根节点加入队列中
    for len(queue) != 0 {            // 层序遍历的终止条件
        cur := queue[0]              // 队首节点
        queue = queue[1:]            // 出队
        if cur == nil {              // 如果队首节点为空, 上图中“nil”节点出队的情况
            flag = true              // 遇到了空节点
            continue                 // 跳过后面的代码,进入下一次循环
        }                            
        if flag {                    // 如果遇到了空节点,并且此时队列还不为空
            return false             // 这棵树不是完全二叉树,返回false
        }
        queue = append(queue, cur.Left)    // 添加队首节点的左孩子
        queue = append(queue, cur.Right)   // 添加队首节点的右孩子
    }
    return true
}


总结

以上就是今天要讲的内容,本文仅仅简单介绍了完全二叉树和满二叉树的性质以及如何判断二叉树是否是完全二叉树,而二叉树的类型还有搜索二叉树、平衡二叉树等,之后再遇到二叉树性质相关的题目会再次更新本篇文章。

你可能感兴趣的:(算法,golang)