坐下,这些都是二叉树的基本操做!

春招来了,辞了职在家里准备再找份实习工做。相信你们,尤为是大3、大四的同窗都常常在招聘要求上看到这样一条要求:熟悉常见的数据结构与算法。常见的数据结构一般有:链表二叉树,若是要求再高点,可能会让你实现红黑树AVL树这种高级的数据结构。因而可知,数据结构与算法仍是比较重要的,最近也是在复习这方面的知识。本篇为复习过程当中遇到过的总结,同时也给各位跟我同样准备面试的同窗一份参考。另外,因为篇幅有限,本篇的重点在于二叉树的常见算法以及实现。javascript

常见的二叉树实现代码

以前写过相关的文章,是关于如何建立及遍历二叉树的,这里再也不赘述。提供连接给各位感兴趣的小伙伴,点此跳转前端

翻转二叉树

对于一棵二叉树,翻转它的左右子树,以下图所示:java

下面来分析具体的实现思路:

  • 对于根结点为空的状况
    这种状况须要排除,由于null不是一个对象,不可能存在左右子树而且能够翻转的状况
  • 对于一棵只有一个根结点的二叉树
    emmm,这种状况也能够翻转,由于此时根结点左右子树为null,交换左右子树其实也就是在交换两个null,理论上是翻转了,但实际上咱们看到的和没有翻转以前的结果是同样的
  • 对于一棵具备两个或两个以上结点的二叉树,此时二叉树能够表示为以下的图像:


能够看出,不管是只有左子树仍是只有右子树均可以进行翻转。这句话等价于,为空的子树能够和不为空的子树进行交换,也就是 不对为空的子树进行特殊处理

分析过程

其实这样咱们仍是不知道二叉树是如何翻转的,咱们能够用第一张图的二叉树为例子,看一下翻转的具体过程。面试

  1. 首先咱们须要对根结点进行判空处理,在根结点不为空的状况下存在左右子树(即便左右子树为空),而后交换左右子树;

2. 把根结点的左子树当成左子树的根结点,对当前根结点进行判空处理,不为空时交换左右子树;

3. 把根结的右子树当成右子树的根结点,对当前根结点进行判空处理,不为空时交换左右子树;

4. 重复步骤 23,最后二叉树变为原来的镜像结构,结果能够参考文章第一张示意图。

示例代码

根据上面的推理过程咱们能够得出以下的代码:算法

function reverseTree(root){
    if( root !== null){
        [root.left, root.right] = [root.right, root.left]
        reverseTree(root.left)
        reverseTree(root.right)
    }
}
复制代码

虽然推理过程比较复杂(也多是写的比较啰嗦。。),可是仔细观察代码,这和遍历的代码彷佛也没多大差异,只是把输出结点变为了交换结点。微信

判断二叉树是否彻底对称

一棵左右彻底对称的二叉树是这样的: 数据结构

那到底如何判断呢?

  • 根结点为空时,此时为一棵空二叉树,知足对称条件(-_-||)
  • 只有一个根结点时,左右子树都为null,知足左右对称条件
  • 只有两个结点时,此时左右子树一定有一个为空,不可能存在对称的状况
  • 结点数在三个及三个以上时,二叉树有对称的可能。

按照咱们正常的思惟,看对称与否,首先看左边,而后看右边,最后比较左右是否相等。同时咱们注意到,在二叉树深度比较大的时候,咱们光是比较左右是不够的。能够观察到,咱们比较完左右之后还须要比较左的左右的右,比较左的右右的左post

分析过程

这么看是比较绕,接下来咱们来看图分析:spa

  1. 先比较根结点左右孩子
  2. 左子树根结点的左孩子右子树根结点的右孩子进行比较
  3. 左子树根结点的右孩子右子树根结点的左孩子进行比较
  4. 重复以上过程...

示例代码

function isSymmetrical(pRoot) {
    // write code here
    if(!pRoot){
        return true
    }
    return funC(pRoot.left, pRoot.right)
}
 
function funC(left, right){
     
    if(!left){
        return right === null
    }
     
    if(!right){
        return false
    }
     
    if(left.val !== right.val){
        return false
    }
     
    return funC(left.right, right.left) && funC(left.left, right.right)
}
复制代码

求二叉树的深度

分析过程

  • 只有一个根结点时,二叉树深度为1
  • 只有左子树时,二叉树深度为左子树深度加1
  • 只有右子树时,二叉树深度为右子树深度加1
  • 同时存在左右子树时,二叉树深度为左右子树中深度最大者加1

示例代码

function deep(root){
    if(!root){
        return 0
    }
    let left = deep(root.left)
    let right = deep(root.right)
    return left > right ? left + 1 : right + 1
}
复制代码

求二叉树的宽度

二叉树的宽度是啥?我把它理解为具备最多结点数的层中包含的结点数,好比下图所示的二叉树,其实它的宽度就是为4: 3d

分析过程

根据上图,咱们如何算出二叉树的宽度呢?其实有个很简单的思路:

  1. 算出第一层的结点数,保存
  2. 算出第二层的结点数,保存一二层中较大的结点数
  3. 重复以上过程

示例代码

根据分析过程,咱们能够利用队列这种数据结构来实现这个算法,代码以下:

function width(root){
    if(!root){
        return 0
    }
    let queue = [root], max = 1, deep = 1
    while(queue.length){
        while(deep--){
            let temp = queue.shift()
            if(temp.left){
                queue.push(temp.left)
            }
            if(temp.right){
                queue.push(temp.right)
            }
        }
        deep = queue.length
        max = max > deep ? max : deep
    }
    return max
}
复制代码

重建二叉树

常见的遍历

  • 前序遍历: 前序遍历首先访问根结点而后遍历左子树,最后遍历右子树

  • 中序遍历: 中序遍历首先访问左子树而后遍历根节点,最后遍历右子树

  • 后序遍历: 后序遍历首先遍历左子树,而后遍历右子树,最后访问根结点

题目描述

根据前序遍历产生的序列和中序遍历产生的序列生成一颗二叉树

思路分析

假若有这么一棵二叉树:

能够看出它 前序遍历序列为: 8 6 5 7 10 9 11中序遍历序列为: 5 6 7 8 9 10 11 其中有个很明显的特征,根结点的值为 前序遍历序列的第一个值,并且咱们在 中序遍历序列中很容易看出,根结点左右两边的结点分别为构成 左子树右子树的结点,因此咱们能够获得一种解决问题的思路:

  1. 获取前序遍历的第一个值,构建根结点
  2. 生成左子树的前序遍历序列和中序遍历序列
  3. 生成右子树的前序遍历序列和中序遍历序列
  4. 重复以上过程...

示例代码

function reConstructBinaryTree(pre, vin) {
    if(!pre || !vin || !pre.length || !vin.length){
        return null
    }
    let root = new TreeNode(pre[0]),
        tIndex = vin.indexOf(pre[0]),
        leftIn = [],leftPre = [],rightIn = [],rightPre = []
    
    for(let i = 0; i < tIndex; i++){
        leftIn.push(vin[i])
        leftPre.push(pre[i+1])
    }
    for(let i = tIndex+1; i < pre.length; i++){
        rightIn.push(vin[i])
        rightPre.push(pre[i])
    }
    //递归
    root.left = reConstructBinaryTree(leftPre, leftIn)
    root.right = reConstructBinaryTree(rightPre, rightIn)
    return root
}
复制代码

以上思路、代码有错漏请在评论区指出!

总结

代码部分来自牛客网--剑指offer,相应的题目也均可以在上面找到。不过在这期间,我也是找到了份实习工做,年后就要去搬砖了。既然找到了,春招就不参与了(春招难度比秋招难太多了)但愿看这篇文章的同窗们也能找到份合适的工做。

扫描下方的二维码或搜索「tony老师的前端补习班」关注个人微信公众号,那么就能够第一时间收到个人最新文章。

相关文章
相关标签/搜索