二叉树有多种遍历方法,本文对二叉树的先序、中序、后序的非递归遍历进行分析。代码编写为 javascript。
1 下面为二叉树的数据结构
let root = {
val: 1,
left: {
val: 2,
left: {
val: 3
},
right: {
val: 4
}
},
right: {
val: 5,
}
}
- 先序遍历结果(根左右):1 2 3 4 5 6
- 中序遍历结果(左根右):3 2 1 5 4 6
- 后序遍历结果(左右根):3 2 5 6 4 1
三种遍历方法区别如下
- 先序:遍历到一个节点,即可输出该节点的值,并继续遍历左、右子树
- 中序:遍历到一个节点,将其暂存,遍历完左子树后,再输出该节点的值,再遍历右子树
- 后序:遍历到一个节点,将其暂存,遍历完左右子树后,在输出该节点的值
2 先序遍历
声明两个变量
stack、result
,类型为数组;stack
用来存储遍历到的节点,result
用来存储当前节点的值。总体思路为确定stack
入栈出栈的顺序「出栈压栈的过程」,例如先序遍历对二叉树进行遍历,暂存前,会把当前节点值存入到result
中,在进行左子树遍历,一直遍历到为空再出栈,再以当前节点的右节点为目标执行相同的操作。
思路如下:
- 取跟节点为目标节点,开始遍历
- 1.访问目标节点值
- 2.左子树入栈 -> 直至左子树为空的节点
- 3.节点出栈,以右子树为目标节点,再依次执行1、2、3
function test2(root) {
let stack = [];
let result = [];
while(root || stack.length > 0) {
while(root) {
result.push(root.val);
stack.push(root);
root = root.left;
}
root = stack.pop();
root = root.right;
}
return result;
}
2 中序遍历
思路如下:
- 取跟节点为目标节点,开始遍历
- 1.左子树入栈 -> 直至左子树为空的节点
- 2.节点出栈 -> 访问该节点
- 3.以右子树为目标节点,再依次执行1、2、3
function test(root) {
let result = [];
let stack = [];
while(root || stack.length > 0) {
while(root) {
stack.push(root);
root = root.left;
}
root = stack.pop();
result.push(root.val);
root = root.right;
}
return result;
}
3 后序遍历
后序遍历和前序、中序有一点差别,出现差别的原因是因为遍历完左子树,如果当前遍历最后的一个节点有右子树,还需要遍历右子树。
function test(root) {
const result = [];
const stack = [];
let last = null;
while (root || stack.length > 0) {
while (root) {
stack.push(root);
root = root.left;
}
root = stack[stack.length - 1];
if (!root.right || root.right === last) {
root = stack.pop();
result.push(root.val);
last = root;
root = null;
} else {
root = root.right;
}
}
return result;
}