一、二叉树基础
1)满二叉树:如果一颗二叉树只有度为0结点和度为2的结点,并且度为0的结点在同一层
2)完全二叉树:除了最底层结点可能没填满之外,其余每层结点都达到最大值;并且最下面节点都集中在左边的位置
优先级队列是一棵完全二叉树
3)二叉搜索树:有数值的有序树;若左子树节点不空,则左子树上所有节点的值均小于它的根节点的值;若右子树节点不空,则右子树节点的值均大于它的根节点的值
4)平衡二叉树:一颗空树,或它的左右子树高度差的绝对值不超过1
二叉树的储存方式:链式储存或顺序储存
链式储存:用指针串联在一起;
顺序储存:用数组来储存。
二、二叉树的遍历方式:深度优先遍历和广度优先遍历;
深度优先遍历:先遍历到深层次的子节点,再往回找节点,分为前序遍历,中序遍历和后序遍历;
广度优先遍历:按每层进行遍历
三、二叉树节点代码定义的代码实现方式:
function TreeNode(val, left, right) {
this.val = val === undefined ? 0 : val;
this.left = left === undefined ? null : left;
this.right = right === undefined ? null : right;
}
四、二叉树的递归遍历
递归遍历有三要素 1)确认入参和返回值 2)确认终止条件 3)确认单层递归的逻辑
这里实现深度优先遍历:前中后序遍历,其实是中间元素在中左右这三个元素递归中的顺序;
// 前序遍历
var preorderTraversal = function(root) {
let res = []
function dfs (cur) {
if(cur === null) return
res.push(cur.val)
dfs(cur.left)
dfs(cur.right)
}
dfs(root)
return res
};
//后序遍历
var postorderTraversal = function(root) {
let res = []
function dfs(cur) {
if( cur === null) return //终止条件
dfs(cur.left)
dfs(cur.right)
res.push(cur.val)
}
dfs(root)
return res // 入参和返回值
};
//中序遍历
var inorderTraversal = function(root) {
let res = []
function dfs(cur) {
if(cur === null) return
dfs(cur.left)
res.push(cur.val)
dfs(cur.right)
}
dfs(root)
return res
};
五、二叉树的迭代遍历
二叉树的迭代遍历是用栈来实现的,将元素不断压入栈中,根据先入后出的原则来遍历数组;
前序遍历:按右左的顺序来入栈,那么出债的顺序就是中左右;后序遍历在前序遍历的基础上修改;即通过中右左的顺序来输出再反转; 中序遍历: 将左节点全部弹出栈,再将左节点以此取出,查看是否有右节点,如果有的话,将右节点下的左节点全部弹入栈;
// 前序遍历
var preorderTraversal = function(root) {
let stack = [root]
let result = []
if(root === null) return result
while(stack.length) {
let cur = stack.pop()
result.push(cur.val)
cur.right && stack.push(cur.right)
cur.left && stack.push(cur.left)
}
return result
};
// 后序遍历
var postorderTraversal = function(root) {
if(root === null) return []
let stack = [root]
let result = []
while(stack.length) {
let cur = stack.pop()
result.push(cur.val)
cur.left && stack.push(cur.left)
cur.right && stack.push(cur.right)
}
return result.reverse()
};
// 中序遍历
var inorderTraversal = function(root) {
if(root === null) return []
let result = [], stack = []
while(root) {
stack.push(root)
root = root.left
}
while(stack.length) {
let cur = stack.pop()
result.push(cur.val)
if(cur.right) {
let node = cur.right
while(node) {
stack.push(node)
node = node.left
}
}
}
return result
};
可以将上述右节点的逻辑放入栈中;也可以在一个条件中同时判断:中序遍历的实现代码:
var inorderTraversal = function (root) {
if (root === null) return []
let result = [], stack = [];
let cur = root
while (stack.length || cur) {
if (cur) {
stack.push(cur)
cur = cur.left
} else {
cur = stack.pop()
result.push(cur.val)
cur = cur.right
}
}
return result
};
六、二叉树的统一迭代
统一迭代的核心是对处理过的节点后 push(null)入栈进行标记,如果 pop 出的是 null 节点,那么就要将前一个节点 pop 出并加入 result
实现中序遍历的过程,其他同理;
var inorderTraversal = function (root) {
// 中序遍历输出顺序左中右,入栈顺序应该是右中左
let result = [], stack = []
if(root === null) return result;
stack.push(root)
while(stack.length) {
let node = stack.pop()
if(!node) {
result.push(stack.pop().val)
continue;
}
node.right && stack.push(node.right)
stack.push(node)
stack.push(null)
node.left && stack.push(node.left)
}
return result
};