二叉树的前序、中序、后序遍历
定义一个二叉树的节点结构
interface ITreeNode {
value: number;
left: ITreeNode | null;
right: ITreeNode | null;
}
前序遍历:root -> left -> right 中序遍历:left -> root -> right 后序遍历:left -> right -> root
前序
function preOrderTraverse(node: ITreeNode | null) {
if (node == null) return
console.log(node.value)
preOrderTraverse(node.left)
preOrderTraverse(node.right)
}
中序
function inOrderTraverse(node: ITreeNode | null) {
if (node == null) return
inOrderTraverse(node.left)
console.log(node.value)
inOrderTraverse(node.right)
}
后序
function postOrderTraverse(node: ITreeNode | null) {
if (node == null) return
postOrderTraverse(node.left)
postOrderTraverse(node.right)
console.log(node.value)
}
录找二叉搜索树的第 k 小值
用中序遍历,数组收集,k 是数组的索引
const arr: number[] = []
function inOrderTraverse(node: ITreeNode | null) {
if (node == null) return
inOrderTraverse(node.left)
arr.push(node.value)
inOrderTraverse(node.right)
}
function getKthValue(node: ITreeNode, k: number): number | null {
inOrderTraverse(node)
return arr[k - 1] || null
}
遍历 DOM 树
- 深度优先遍历
/**
* 访问节点
* @param n node
*/
function visitNode(n: Node) {
if (n instanceof Comment) {
// 注释
console.info('Comment node ---', n.textContent)
}
if (n instanceof Text) {
// 文本
const t = n.textContent?.trim()
if (t) {
console.info('Text node ---', t)
}
}
if (n instanceof HTMLElement) {
// element
console.info('Element node ---', `<${n.tagName.toLowerCase()}>`)
}
}
/**
* 深度优先遍历
* @param root dom node
*/
function depthFirstTraverse1(root: Node) {
visitNode(root)
const childNodes = root.childNodes // .childNodes 和 .children 不一样
if (childNodes.length) {
childNodes.forEach(child => {
depthFirstTraverse1(child) // 递归
})
}
}
- 深度优先2
function depthFirstTraverse2(root: Node) {
const stack: Node[] = []
// 根节点压栈
stack.push(root)
while (stack.length > 0) {
const curNode = stack.pop() // 出栈
if (curNode == null) break
visitNode(curNode)
// 子节点压栈
const childNodes = curNode.childNodes
if (childNodes.length > 0) {
// reverse 反顺序压栈
Array.from(childNodes).reverse().forEach(child => stack.push(child))
}
}
}
- 广度优先
function breadthFirstTraverse(root: Node) {
const queue: Node[] = []
// 根节点入队列
queue.unshift(root)
while (queue.length > 0) {
const curNode = queue.pop()
if (curNode == null) break
visitNode(curNode)
// 子节点入队
const childNodes = curNode.childNodes
if (childNodes.length) {
childNodes.forEach(child => queue.unshift(child))
}
}
}
二叉树最大深度
- 递归方式
function maxDepth(root: TreeNode | null): number {
if(root === null) return 0
return 1 + Math.max(maxDepth(root.left), maxDepth(root.right))
}
- 根据扩优先 思路:用队例,动态收集节点,先收集父节点,释放父节点,后加入这一层父节点的子节点, 一层一层往下,遍历一层计一次数
function maxDepth(root: TreeNode | null): number {
let count = 0
if(!root) return count
const queue = []
queue.push(root)
while(queue.length){
let size = queue.length
while(size--){
const node = queue.shift()
if(node.left)queue.push(node.left)
if(node.right)queue.push(node.right)
}
count++
}
return count
};