什么是遍历二叉树,JavaScript实现二叉树的遍历(递归,非递归)

2,259 阅读3分钟

遍历二叉树:

遍历的定义指顺着一条搜索路径巡防二叉树的结点,使得每个结点均被访问一次,而且仅被访问一次(又称周游)

遍历方法:

依次遍历二叉树中的三个组成部分,便是遍历了整个二叉树

L:遍历左子树
D: 访问根结点
R: 遍历右子树 若规定先左后右,则遍历二叉树就有三种情况
DLR ———— 先(根)序遍历
LDR ———— 中(根)序遍历
LRD ———— 后(根)序遍历

遍历二叉树的算法描述:

先序遍历二叉树:若二叉树为空,则空操作,否则(1)访问根结点;(2)先序遍历左子树;(3)先序遍历右子树
中序遍历二叉树:若二叉树为空,则空操作,否则(1)中序遍历左子树;(2)访问根结点;(3)中序遍历右子树
后序遍历二叉树:若二叉树为空,则空操作,否则(1)后序遍历左子树;(2)后序遍历右子树;(3)访问根结点

由二叉树的递归定义可知,遍历左子树和遍历右子树可如同遍历二叉树一样“递归”进行。

下面我们用JavaScript实现一下二叉树的遍历

给定一个二叉树对象

var root = {  
   id: 1,  
   
    left: {
        id: 2,
        left: {
            id: 4,
        },
        right:{
            id:5
        }
    },
    right: {
        id: 3,
        left: {
            id: 6
        },
        right: {
            id: 7
        }
    }
}

递归先序遍历

var res = []  

function DLR(root) {  

  if(root != null) {
      res.push(root.id)
      if(root.left) {
          DLR(root.left)
      }
      if(root.right) {
          DLR(root.right)
      }
  }
  return res
}  

console.log('递归先序遍历', DLR(root))  

递归中序遍历

var res = []  

function LDR(root) {  

    if(root != null) {
        if(root.left) {
            LDR(root.left)
        }
        res.push(root.id)
        if(root.right) {
            LDR(root.right)
        }
    }
    return res
}  

console.log('递归中序遍历', DLR(root))  

递归后序遍历

var res = []  

function LRD(root) {  

    if(root != null) {
        if(root.left) {
            LRD(root.left)
        }
        if(root.right) {
            LRD(root.right)
        }
        res.push(root.id)
    }
    return res
}  

console.log('递归后序遍历', LRD(root))  

看完上面的递归遍历,下面对比一下非递归的二叉树遍历。

非递归先序遍历

就是把递归的遍历改成循环模式,将需要遍历的树放入数组arr中,在利用数组的pop()方法,返回这个大树,取出树的根,将树的右子树放入arr中,  
再将树的左子树放入arr中(这样的话pop出来的就是先左后右),然后循环上面操作,pop arr数组,取出根,然后右子树push arr中, 左子树  
push arr中。。。循环
function DLR(root) {  

    var res = [] , arr =[]
    if (root != null){
        arr.push(root)
    }
    while (arr.length > 0) {
        var temp = arr.pop()
        res.push(temp.id)
        if(temp.right){ // 先放右子树再放左子树  取出来的时候才是先左后右
            arr.push(temp.right)
        }
        if(temp.left){
            arr.push(temp.left)
        }
    }
    return res
}  

console.log('非递归先序遍历', DLR(root))

非递归中序遍历

先把左边的,全部放进arr再输出
function LDR(root) {  

    var res = [] , arr =[]
    while (true){
        while (root != null){
            arr.push(root)
            root = root.left
        }
        //终止条件:最后树遍历完了自然就结束
        if(arr.length===0) {
            break;
        }
        let temp = arr.pop()
        res.push(temp.id)
        root = temp.right
    }
    return res
}  

console.log('非递归中序遍历', LDR(root))

非递归后序遍历

其实就是先根右左(和先序方法一样) 然后在反过来
function LRD(root) {  

    var res = [] , arr =[]
    if (root != null){
        arr.push(root)
    }
    while (arr.length > 0) {
        var temp = arr.pop()
        res.push(temp.id)
        if(temp.left){
            arr.push(temp.left)
        }
        if(temp.right){
            arr.push(temp.right)
        }
    }
    return res.reverse()
}  

console.log('非递归后序遍历', LRD(root))