二叉树遍历(前序,后序,中序,层次)递归与迭代实现JavaScript
liusaint opened this issue · 0 comments
liusaint commented
最近做leetcode题目。总结一下二叉树遍历的一般方法。
数据结构
function Node(val){
this.left = this.right = null;
this.val = val;
}
先定义一棵树。node1是根节点。
var node4 = {left: null, right: null, val: 4 };
var node5 = {left: null, right: null, val: 5 };
var node6 = {left: null, right: null, val: 6 };
var node7 = {left: null, right: null, val: 7 };
var node3 = {left: node6, right: node7, val: 3 };
var node2 = {left: node4, right: node5, val: 2 };
var node1 = {left: node2, right: node3, val: 1 };
- 结构如图:
// 1
// /\
// 2 3
// /\ /\
// 4 5 6 7
什么是前中后序遍历?
以一个根节点带两个叶子节点举例。 根据访问的顺序,根节点在前面就是前序(根左右),在中间就是中序(左根右),在后面就是后续(左右根)。
1.前序遍历
- 前序遍历递归实现:
function preorderTraversal(root) {
if (!root) {
return;
}
console.log(root.val);
var left = root.left;
var right = root.right;
left && preorderTraversal(left);
right && preorderTraversal(right);
}
preorderTraversal(node1); //1 2 4 5 3 6 7
- 前序遍历迭代实现:
function preorderTraversal1(root) {
if (!root) {
return;
}
var stack = [root];
while (stack.length > 0) {
//取第一个。
var item = stack.shift();
console.log(item.val);
if (item.right) {
stack.unshift(item.right);
}
if (item.left) {
stack.unshift(item.left);
}
}
}
preorderTraversal1(node1); //1 2 4 5 3 6 7
2.中序遍历
- 中序遍历递归实现:
function inorderTraversal(root) {
if (!root) {
return;
}
var left = root.left;
var right = root.right;
left && inorderTraversal(left);
console.log(root.val);
right && inorderTraversal(right);
}
console.log(inorderTraversal(node1)); //4 2 5 1 6 3 7
- 中序遍历迭代实现:
//中序遍历迭代方式。
function inorderTraversal1(root) {
if (!root) {
return;
}
var stack = [root];
while (stack.length > 0) {
var item = stack[stack.length - 1];
if (!item.left || (item.left && item.left.isOk)) {
stack.pop();
item.isOk = true;
console.log(item.val);
item.right && stack.push(item.right);
} else if (item.left && !item.left.isOk) {
stack.push(item.left);
}
}
}
inorderTraversal1(node1); //4 2 5 1 6 3 7
3.后序遍历
- 后序遍历递归实现:
function postorderTraversal(root) {
if (!root) {
return;
}
var left = root.left;
var right = root.right;
left && postorderTraversal(left);
right && postorderTraversal(right);
console.log(root.val);
}
postorderTraversal(node1);//4 5 2 6 7 3 1
- 后序遍历迭代实现:
function postorderTraversal1(root) {
if (!root) {
return;
}
var stack = [root];
while (stack.length > 0) {
var item = stack[stack.length - 1];
//满足这些就可以直接输出它了。它是叶子节点。或它的子节点都ok了。
if ((item.left == null && item.right == null) || (item.left && item.left.isOk && item.right && item.right.isOk) || (item.left && item.left.isOk && item.right == null) || (item.left == null && item.right && item.right.isOk)) {
item.isOk = true;
console.log(item.val);
stack.pop();
} else if (item.left && !item.left.isOk) {
//如果左边的没ok,就把左边的入栈
stack.push(item.left);
} else if (item.right && !item.right.isOk) {
//如果右边的没ok就把右边的入栈。
stack.push(item.right);
}
}
}
postorderTraversal1(node1);//4 5 2 6 7 3 1
4.层次遍历。
从上往下,从左往右,一层一层的遍历。
var levelOrder = function(root) {
if(!root){
return;
}
var checkArr = [root];
while (checkArr.length > 0) {
var newCheckArr = [];
for (var i = 0; i < checkArr.length; i++) {
var item = checkArr[i];
console.log(item.val);
item.left && newCheckArr.push(item.left);
item.right && newCheckArr.push(item.right);
}
checkArr = newCheckArr;
}
};
levelOrder(node1);//1 2 3 4 5 6 7
深度优先与广度优先
- 二叉树的深度优先遍历的非递归的通用做法是采用栈,广度优先遍历的非递归的通用做法是采用队列。
- 深度优先对每一个可能的分支路径深入到不能再深入为止,先序遍历、中序遍历、后序遍历属于深度优先。
- 广度优先又叫层次遍历,从上往下,从左往右(也可以从右往左)访问结点,访问完一层就进入下一层,直到没有结点可以访问为止。
leetcode
- 附上刷leetcode的github项目。项目内容从https://leetcode-cn.com通过node爬虫抓取。
- 项目地址:https://github.com/liusaint/leetcode