基础知识
1. 二叉树两种主要的形式:满二叉树和完全二叉树。深度为k,节点数量为2^k - 1的树为满二叉树。
2. 二叉搜索树,是一个有序树,左<根<右。
3. 平衡二叉搜索树,又被称为AVL树:它是一颗空树,或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一颗平衡二叉树。
4. 二叉树的遍历方式,深度优先遍历(前序、中序、后续),广度优先遍历(层次遍历)
function TreeNode(){
this.val = (val === undefined ? 0 : val);
this.left = (left === undefined ? null : left);
this.right = (right === undefined ? null : right);
}
递归三部曲 :
1. 确定递归函数的参数和返回值:确定哪些参数是递归过程中需要处理的,在递归函数里加上这个参数,并且明确每次递归的返回值是什么;
2. 确定终止条件
3. 确定单层递归的逻辑。
递归遍历
以前序遍历为例,
1.确定递归函数的参数和返回值:
function traversal(cur, arr)
2.确定终止条件:在递归过程中,如何算是递归结束了呢?当然是当前遍历的节点是空了,那么本层递归就要结束了
if (cur == null) return;
3.确定单层递归逻辑:前序遍历是中左右的顺序,所以在遍历时,要先取中节点的数值
arr.push(cur.val);
traversal(cur.left, arr);
traversal(cur.right, arr);
完整代码:
var preorderTraversal = function (root) {
let res = [];
const dfs = function (root){
if(root==null) return;
//先序遍历先处理当前节点
res.push(root.val);
//递归左子树
dfs(root.left);
// 递归右子树
dfs(root.right);
}
//只使用一个参数,使用闭包进行存储数据
dfs(root);
return res;
}
中序遍历:
var inorderTraversal = function(root) {
let res=[];
const dfs=function(root){
if(root===null){
return ;
}
dfs(root.left);
res.push(root.val);
dfs(root.right);
}
dfs(root);
return res;
};
后续遍历:
var postorderTraversal = function(root) {
let res=[];
const dfs=function(root){
if(root===null){
return ;
}
dfs(root.left);
dfs(root.right);
res.push(root.val);
}
dfs(root);
return res;
};
迭代遍历
为什么可以用迭代法来实现二叉树的前后中序遍历呢?--递归的实现就是:每一次递归调用都会把函数的局部变量、参数值和返回值等压入调用栈中,然后递归返回的时候,从栈顶弹出上一次递归的各项参数,所以这就是 递归为什么可以返回上一层位置的原因。
前序遍历(迭代法)
function preorderTraversal(root){
let stack = [];
let res = [];
if(root==null) return res;
stack.push(root);
while(stack.length){
let node = stack.pop();
res.push(node.val);
if(node.right) stack.push(node.right); //空节点不入栈
if(node.left) stack.push(node.left);
}
return res;
}
后序遍历(迭代法)
后序: 左右中 将中右左反转即可得到。
function postorderTraversal(root){
let stack = [];
let res = [];
if(root==null) return res;
stack.push(root);
while(stack.length){
let node = stack.pop();
res.push(node.val);
if(node.left) stack.push(node.left);
if(node.right) stack.push(node.right); //空节点不入栈
}
return res.reverse();
}
中序遍历(迭代法,特殊)
中序遍历无法像前序遍历那样实现,因为,中序遍历是 左-中-右,入栈从中开始,左先于右,所以通过先将右压入栈,再压入左的方式,实现左-右的弹出顺序,但是,无法将中节点在左右之间的顺序弹出。
function inorderTraversal(root){
let res = [];
if(root) return res;
let st = [];
let cur = root;
while(cur !==null || st.length!=0){
if(cur!=null){
st.push(cur);
cur = cur.left; // 左
}else{
let top = st.pop();
res.push(top.val); // 中
cur=top.right; // 右
}
}
return res;
}