创建二叉树
let BiTree=function(ele){
this.data=ele
this.left=null
this.right=null
}
遍历二叉树
二叉树有前中后以及层序遍历,最先想到的就是递归的方式来进行求解,那我们先来看看递归的方式如何求解
先序遍历(递归)
function preorderTraversal(root){
const res=[]
if(!root) return null
preorder(root,res)
return res
}
function preorder(node,res){
if(!node) return res
res.push(node.val)
preorder(node.left,res)
preorder(node.right,res)
}
递归其实比较简单,更加考察能力的是非递归,非递归的话我们得借助一个栈来存放暂时的节点
先序遍历(非递归)
function preorderTraversal(root){
const res=[],stack=[]
if(!root) return res
stack.push(root)
while(stack.length){
const node = stack.pop()
res.push(node.val)
if(node.right){stack.push(node.right)}
if(node.left){stack.push(node.left)}
}
return res
}
这个地方为什么先放node.right,因为借助的是一个栈,栈是先进后出,我们先序的顺序是根左右
后序遍历(递归)
function postorderTraversal(root){
const res=[]
if(!root) return res
postorder(root,res)
return res
}
function postorder(node,res){
if(!node) return res
postorder(node.left,res)
postorder(node.right,res)
res.push(node.val)
}
后序遍历(非递归)
先序遍历是根左右,后续遍历时左右根,那么我们可以在先序的基础上改一下,根左右先改成根右左,然后再反转,即得到所需的答案
function postorderTraversal(root){
const res=[],stack=[]
if(!root) return res
stack.push(root)
while(stack.length){
const node = stack.pop()
res.push(node.val)
//接下来是不同于先序的地方,我们要得到根右左,所以得先放左子树进栈
if(node.left){stack.push(node.left)}
if(node.right){stack.push(node.right)}
}
res.reverse()//将根右左翻转 得到左右根
return res
}
中序遍历(递归)
function inorderTraversal(root){
const res=[]
if(!root) return res
inorder(root,res)
return res
}
function inorder(node,res){
if(!node) return res
inorder(node.left,res)
res.push(node.val)
inorder(node.right,res)
}
中序遍历(非递归)
function inorderTraversal(root){
const res=[],stack=[]
if(!root) return res
let cur=root
while(cur||stack.length){
while(cur){
stack.push(cur)
cur=cur.left
}
const node = stack.pop()
res.push(node.val)
cur = node.right
}
return res
}
层序遍历
function levelOrderTraversal(root){
const res=[],queue=[]
if(!root) return res
queue.push(root)
while(queue.length){
let curLevelSize = queue.length
res.push([])
for(let i=0;i<curLevelSize;i++){
let node = queue.shift()
res[res.length-1].push(node.val)
if(node.left){queue.push(node.left)}
if(node.right){queue.push(node.right)}
}
}
return res
}
二叉树相关题目
二叉镜像树
给定一个二叉树根节点root,输出其镜像二叉树
function buildMirrorTree(root){
if(!root) return root
let left=builMirrorTree(root.left)
let right=buildMirrorTree(root.right)
root.left=right
root.right=left
return root
}
对称二叉树
实现一个函数判断一个二叉树是否对称二叉树,如果一棵树二叉树和他的镜像是一样的,那么他是对称二叉树
function isSymmetric(root){
if(!root) return true
return compare(root.left,root.right)
}
function compare(p,q){
if(p==null&&q==null) return true
else if(!p&&q) return false
else if(p&&!q) return false
return q.val==p.val&&compare(p.left,q.right)&&compare(p.right,q.left)
}
平衡二叉树
平衡二叉树首先是二叉搜索树,即左子树的值小于根节点,右子树大于根节点,对其子树也是,而且左子树右子树的深度差不超过1,其子树也是平衡二叉树,为什么要有平衡二叉树,因为二叉搜索树可能退化成链表,降低查找效率,所以需要对其高度进行限制 实现一个函数,输入一个二叉树根节点,判断其是否为平衡二叉树
function isBalanced(root){
if(!root) return true
return Math.abs(Depth(node.left)-Depth(node.right))<2&&isBalanced(root.left)&&isBalanced(root.right)
}
function Depth(node){
if(!node) return 0
return Math.max(Depth(node.left),Depth(node.right))+1
}
二叉搜索树的第K大节点
通过中序遍历可以得到一个从小到大的排列,然后将其反序,即可通过索引得到
function kthLargest(root,k){
const res=[]
inorderTraversal(root,res)
return res[k-1]
}
function inorderTraversal(root,res){
if(!root) return res
const stack=[]
let cur=root
while(cur||stack.length){
while(cur){
stack.push(cur)
cur=cur.left
}
const node = stack.pop()
res.push(node.val)
cur = node.right
}
return res
}
二叉搜索树的最近公共祖先
二叉搜索树,又称二叉排序树,若左子树不为空,则左子树上所有节点均小于他的根节点,右子树不为空的化,右子树的所有节点均大于根节点
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
思路:如果两个节点相等返回任意一个,如果不等, 其中一个大于根节点其中一个小于节点返回根节点 如果都大于根节点,在右子树上找 如果都小于跟节点,在左子树上找
function lowerstCommonAncestor(root,p,q){
if(!root) return null
if(p.val==q.val) return p
while(root){
if(p.val<root.val&&q.val<root.val){root=root.left}
else if(p.val>root.val&&q.val>root.val){root=root.right}
else{
return root
}
}
}
二叉树的公共祖先
这个不同于上一个题,因为上一个是搜索树,有序的,而这个是无序的
function lowestCommonAncestor(root,p,q){
if(root==null||p==root||q==root) return root
let left = lowestCommonAncestor(root.left,p,q)
let right = lowestCommonAncestort(root.right,p,q)
if(left==null) return right
if(right==null) return left
return root
}
重建二叉树
给定先序和中序遍历结果,根据遍历结果重建二叉树
function buildTree(preorder,inorder){
if(!preorder.length||!inorder.length) return null
let rootval = preorder[0]
let rootnode = new TreeNode(rootval)
let index = inorder.indexOf(rootval)
let left = buildTree(preorder.slice(1,index+1),inorder.slice(0,index))
let right = buildTree(preorder.slice(index+1),inorder.slice(index+1))
rootnode.left = left
rootnode.right = right
return rootnode
}
相同的树
function isSameTree(p,q){
if(!q&&!p) return true
if(!q&&p) return false
if(q&&!p) return false
return p.val==q.val&&isSameTree(p.left,q.left)&&isSameTree(p.right,q.right)
}
树的子结构
输入两个二叉树A和B,判断B是不是A的子结构(约定空树不是任意一个树的子结构)
function isSubStructure(A,B){
if(A==null||B==null) return false
return isSameTree(A,B)||isSubStructure(A.left,B)||isSubStructure(A.right,B)
}
function isSameTree(node1,node2){
if(node1==null&&node2==null) return true
if(node1==null&&node2!=null) return false
if(node1!=null&&node2==null) return false
return node1.val==node2.val&&isSameTree(node1.left,node2.left)&&isSameTree(node1.right,node2.right)
}
二叉搜索树与双向链表
输入一棵二叉搜索树,将该二叉搜索树转成一个排序的循环双向链表,要求不能创建任何新节点,只能调整树中的指针的指向 思路:中序遍历
function treeToDoubleList(root){
if(!root) return null
const stack=[]
let pre=null
let head=null
let cur = root
while(cur||stack.length){
while(cur){
stack.push(cur)
cur=cur.left
}
const node = stack.pop()
if(!pre){
head=pre
}
else{
pre.right= node
}
node.left = pre
pre = node
cur= node.right
}
head.left=pre
pre.right=head
return head
}