本文主要介绍二叉树遍历的三种方式:
- 前序遍历
- 中序遍历
- 后序遍历
同时分别用递归和非递归的方式实现,给出尽可能间接的代码模版,方便大家在面试的时候可以直接套用。
节点结构
首先定义二叉树每个节点的数据结构。
/**
* 节点数据结构
*/
class TreeNode {
val: number
left: TreeNode | null
right: TreeNode | null
constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
this.val = (val === undefined ? 0 : val)
this.left = (left === undefined ? null : left)
this.right = (right === undefined ? null : right)
}
}
前序遍历
针对每个节点,我们首先访问当前节点,然后访问左节点,最后访问右节点。
递归
/**
* 前序遍历递归实现
* @param root
*/
function preOrderTraversal(root: TreeNode | null) : number[] {
if(root) {
return [root.val, ...preOrderTraversal(root.left), ...preOrderTraversal(root.right)]
}else {
return []
}
}
非递归
/**
* 前序遍历的非递归过程
* @param root
*/
function preOrderTraversalIterate(root: TreeNode | null) : number[] {
if(root === null) return []
const stack: TreeNode[] = []
const ret = []
// stack.push(root)
let node: TreeNode | null = root
while(stack.length || node) {
while(node) {
ret.push(node.val)
stack.push(node)
node = node.left
}
node = stack.pop() as TreeNode
node = node.right
}
return ret
}
中序遍历
针对每个节点,我们首先访问左节点,然后访问当前节点,最后访问右节点。
递归
/**
* 中序遍历递归实现
* @param root
*/
function inOrderTraversal(root: TreeNode | null): number[] {
if(root) {
return [...inOrderTraversal(root.left), root.val, ...inOrderTraversal(root.right)]
}else {
return []
}
}
非递归
/**
* 中序递归迭代实现
* @param root
*/
function inOrderTraversalIterate(root: TreeNode | null): number[] {
if(root === null) return []
const ret = []
const stack: TreeNode[] = []
let node: TreeNode | null = root
while(stack.length || node) {
while(node) {
stack.push(node)
node = node.left
}
node = stack.pop() as TreeNode
ret.push(node.val)
node = node.right
}
return ret
}
后序遍历
针对每个节点,我们首先访问左节点,然后访问右节点,最后访当前节点。
递归
/**
* 后续遍历递归实现
* @param root
*/
function postOrderTraversal(root: TreeNode | null) : number[] {
if(root) {
return [...postOrderTraversal(root.left), ...postOrderTraversal(root.right), root.val]
}else {
return []
}
}
非递归
/**
* 后序遍历的非递归实现
* @param root
*/
function postOrderTraversalIterate(root: TreeNode | null): number[] {
if (root === null) return [];
const ret: number[] = [];
const stack: TreeNode[] = [];
let prev: TreeNode | null = null;
let node: TreeNode | null = root;
while (node || stack.length) {
while (node) {
stack.push(node);
root = node.left;
}
node = stack.pop() as TreeNode;
// 检查右子树是否存在或者是否已经访问过
if (!node.right || node.right === prev) {
ret.push(node.val);
prev = node;
node = null; // 置空root,以便下一次弹出栈顶元素
} else {
// 将当前节点重新入栈,处理右子树
stack.push(node);
node = node.right;
}
}
return ret;
}