javascript实现二叉树递归遍历和非递归遍历

首先我们实现二叉树的构造

(function () {

  /**
   * 首先我们定义一个Node的构造函数
   */
  function Node(data) {
    this.left = null;
    this.right = null;
    this.data = data;
  }

  /**
   * 二叉树的创建
   * 我们规定用数字0表示为空节点
   */
  function createTree (data) {
    let dat = data.shift();
    let p = null;

    if (dat != 0) {
      p = new Node(dat);
      p.left = createTree(data);
      p.right = createTree(data);
    }

    return p;
  }

// 构造一棵二叉树
let arr = [1,2,4,0,0,5,0,0,3,6,0,0,7,0,0],
    root = createTree(arr);

})();

递归遍历

// 前序遍历
function prevTraverse (node) {
  if (node === null) return;

  prevTraverse(node.left);
  console.log(node.data);
  prevTraverse(node.right);
}

// 中序遍历
function middleTraverse (node) {
  if (node === null) return;

  console.log(node.data);
  middleTraverse(node.left);
  middleTraverse(node.right);
}

// 后序遍历
function lastTraverse (node) {
  if (node === null) return;

  lastTraverse(node.left);
  lastTraverse(node.right);
  console.log(node.data);
}

非递归遍历

非递归前序遍历

  • 我们用栈arr来保存遍历过程中的节点
  • 首先将根节点保存到栈中,循环遍历栈直到栈为空
  • 因为是前序遍历,因此第一步打印根节点
  • 打印完毕后,查询当前节点是否有右孩子,右孩子要先入栈
  • 查询当前节点是否有左孩子,左孩子后入栈
  • 右孩子比左孩子先入栈的原因是,在下一个循环中左孩子要先出栈,右孩子后出栈
  • 右孩子出栈后又相当于一个根节点,先打印根节点,然后再继续向下执行上述类似查找步骤
function prevTraverseUnRecursion (root) {
  let arr = [],
      node = null;

  arr.unshift(root);

  while (arr.length !== 0) {
    node = arr.shift();
    console.log(node.data);

    if (node.right !== null) {
      arr.unshift(node.right);
    }

    if (node.left !== null) {
      arr.unshift(node.left);
    }
  }
}

非递归中序遍历

  • 非递归中序遍历首先要访问左孩子,然后在访问根节点,最后在访问右孩子
  • 因此,在执行过程中,需要有一次跨域根节点的过程,此时栈已经空了,而这个时候是需要访问右孩子的
  • 所以,当栈为空,且节点为空时表明整个访问过程结束
  • 否则,如果当前节点为空,表明已经到达最底部;如果当前节点不为空,继续向下查找
function middleTraverseUnRecursion (root) {
  let arr = [],
      node = root;

  while (arr.length !== 0 || node !== null) {
    if (node === null) {
      node = arr.shift();
      console.log(node.data);
      node = node.right;
    } else {
      arr.unshift(node);
      node = node.left;
    }
  }

}

非递归后序遍历

  • 我们采用栈来保存之前经过的节点,首先将根节点保存到栈中,并用parentNode记录下栈顶的节点
  • 我们要使用parentNode来判断是否要继续向下搜寻,直到parentNode的左孩子和右孩子都为空。
  • 我们需要使用一个循环来遍历栈arr,直到arr为空
  • 第一种情况就是不断向下搜寻的过程,最近一次打印的节点traverseNode既不是parentNode的左孩子,也不是parentNode的右孩子
  • 第二种情况也是不断的搜寻过程,只不过此时刚打印完parentNode的左孩子traverseNode,转到了parentNode的右孩子
  • 第三种情况就是parentNode的左孩子和右孩子都不存在,说明此时已经到了最底端,需要从弹出栈顶的元素并进行打印,同时更新最近打印过的节点traverseNode
function lastTraverseUnRecursion (root) {
  let arr = [],
      parentNode = null,
      traverseNode = null;

  if (root !== null) {
    arr.unshift(root);

    while (arr.length !==0) {
      parentNode = arr[0];
      if (parentNode.left !== null && traverseNode !== parentNode.left &&traverseNode !== parentNode.right) {
        arr.unshift(parentNode.left);
      } else if (parentNode.right !== null && traverseNode !== parentNode.right) {
        arr.unshift(parentNode.right);
      } else {
        traverseNode = arr.shift();
        console.log(traverseNode.data);
      }
    }
  }
}

你可能感兴趣的:(JavaScript,数据结构)