树结构的遍历

172 阅读1分钟
二叉树的前序、中序、后序遍历

定义一个二叉树的节点结构

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 树
  1. 深度优先遍历
/**
 * 访问节点
 * @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) // 递归
        })
    }
}
  1. 深度优先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))
         }
     }
 }
  1. 广度优先
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))
        }
    }
}
二叉树最大深度
  1. 递归方式
function maxDepth(root: TreeNode | null): number {
    if(root === null) return 0
    return 1 + Math.max(maxDepth(root.left), maxDepth(root.right))
}
  1. 根据扩优先 思路:用队例,动态收集节点,先收集父节点,释放父节点,后加入这一层父节点的子节点, 一层一层往下,遍历一层计一次数
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
};