本篇为复习过程当中遇到过的总结,同时也给准备面试的同窗一份参考。另外,因为篇幅有限,本篇的重点在于二叉树的常见算法以及实现。
以前写过相关的文章,是关于如何建立及遍历二叉树的,这里再也不赘述。提供连接给各位感兴趣的小伙伴,点此跳转javascript
对于一棵二叉树,翻转它的左右子树,以下图所示: 前端
下面来分析具体的实现思路:java
这种状况须要排除,由于null不是一个对象,不可能存在左右子树而且能够翻转的状况面试
emmm,这种状况也能够翻转,由于此时根结点左右子树为null,交换左右子树其实也就是在交换两个null,理论上是翻转了,但实际上咱们看到的和没有翻转以前的结果是同样的算法
能够看出,不管是只有左子树仍是只有右子树均可以进行翻转。这句话等价于,为空的子树能够和不为空的子树进行交换,也就是不对为空的子树进行特殊处理微信
其实这样咱们仍是不知道二叉树是如何翻转的,咱们能够用第一张图的二叉树为例子,看一下翻转的具体过程。数据结构
根据上面的推理过程咱们能够得出以下的代码:post
function reverseTree(root){ if( root !== null){ [root.left, root.right] = [root.right, root.left] reverseTree(root.left) reverseTree(root.right) } }
虽然推理过程比较复杂(也多是写的比较啰嗦。。),可是仔细观察代码,这和遍历的代码彷佛也没多大差异,只是把输出结点变为了交换结点。spa
一棵左右彻底对称的二叉树是这样的:
那到底如何判断呢?3d
按照咱们正常的思惟,看对称与否,首先看左边,而后看右边,最后比较左右是否相等。同时咱们注意到,在二叉树深度比较大的时候,咱们光是比较左右是不够的。能够观察到,咱们比较完左右之后还须要比较左的左和右的右,比较左的右和右的左
这么看是比较绕,接下来咱们来看图分析:
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) }
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:
根据上图,咱们如何算出二叉树的宽度呢?其实有个很简单的思路:
根据分析过程,咱们能够利用队列这种数据结构来实现这个算法,代码以下:
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
其中有个很明显的特征,根结点的值为前序遍历序列的第一个值,并且咱们在中序遍历序列中很容易看出,根结点左右两边的结点分别为构成左子树和右子树的结点,因此咱们能够获得一种解决问题的思路:
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老师的前端补习班」关注个人微信公众号,那么就能够第一时间收到个人最新文章。