使用javascript实现排序二叉树(2)

上一篇文章我们构造了基本的一个排序二叉树的数据结构,但是仅仅是定义了一个insert方法去创建二叉排序树,今天我们来给我们的数据结构添加一些遍历的功能。

二叉树的三种遍历方式(以根节点为准来定义前、中、后)的介绍及其应用场景:

  1. 前序遍历

    • 顺序:根节点 => 左子树 => 右子树
    • 应用:可以用来构建文件的目录结构,输出所有目录并分层
  2. 中序遍历

    • 顺序:左子树 => 根节点 => 右子树
    • 应用:可以进行排序,输出的结果是一个递增的序列
  3. 后续遍历

    • 顺序:左子树 => 右子树 => 根节点
    • 应用:后续遍历是先遍历子树,最后到根节点,可以实现统计节点数、计算文件夹大小的功能

思考

  1. 遍历的方法是给谁用的,是否需要暴露出去
  2. 如果暴露出去,怎样设计才能让调用者能够获取到每一个节点并且进行对应的操作

结论

  1. 肯定是要暴露出去给别人调用的
  2. 给别人调用,具体的逻辑是不确定的,所以应该是调用者传入一个函数,我们在遍历的时候把每一次的节点都传给这个函数,并且去调用这个函数,这样我们不用管具体函数的逻辑,反正已经把它想要的 节点 给他了,具体怎样操作我们不用管。

分析完毕之后,依然是上次的代码,我们给他添加前序中序和后续遍历的方法:


function BinaryTree(){
  var root = null; //根节点默认为null
  //节点类型的构造函数
  function Node(key){
    this.key = key;
    this.left = null;
    this.right = null;
  }
  //插入方法
  this.insert = function(key){     
    var newNode = new Node(key);
    if(root === null){
       root = newNode;
    }else{
       insertNode(root,newNode)
    }
  }
  var insertNode = function(node,newNode){
    if(newNode.key < node.key){
      if(node.left === null){
         node.left = newNode;
      }else{
         insertNode(node.left,newNode)
      }
    }else{
      if(newNode.key > node.key){
        if(node.right === null){
          node.right = newNode;
        }else{
          insertNode(node.right,newNode)
        }
      }
    }
  }
  
  /*--------------------------------------------------------*/
  /*
      前序遍历: 根节点 => 左子树 => 右子树
  */
  this.preTravel = function(callback){
    //和上面插入操作类似,都用一个内部的函数来实现具体的逻辑,因为需要使用root
     preTravelNode(root,callback); 
  }   
  /* 
      逻辑:
          1. 判断传入的节点是否为null,如果为null就直接return
          2. 如果不为null,则继续对该节点下的left和right进行递归调用
          3. 具体的调用顺序根据为 根节点 => 左子树 => 右子树
  */
  function preTravelNode(node,callback){
    if(node !== null){ 
       callback(node.key); 
       preTravelNode(node.left,callback);
       preTravelNode(node.right,callback);
    }
  }
  
  //中序遍历
  this.middleTravel = function(callback){
    middleTravelNode(root,callback);
  }
  function middleTravelNode(node,callback){
    if(node !== null){
       middleTravelNode(node.left,callback);
       callback(node.key);
       middleTravelNode(node.right,callback);
    }
  }
  
  //后续遍历
  this.nextTravel = function(callback){
    nextTravelNode(root,callback);
  }
  function nextTravelNode(node,callback){
    if(node !== null){
       nextTravelNode(node.left,callback);
       nextTravelNode(node.right,callback);
       callback(node.key);
    }
  }
}

var nodes = [8,7,3,4,6,5,2,9,12]
var binaryTree = new BinaryTree();
nodes.forEach((item)=>{
    binaryTree.insert(item)
})
//测试前序遍历
binaryTree.beforeTravel((key)=>{
  console.log(key) // 8,7,3,2,4,6,5,9,10
})
console.log('--------------------')
//中序遍历
binaryTree.middleTravel((key)=>{
  console.log(key) // 2,3,4,5,6,7,8,9,10
})
console.log('--------------------')
//后续遍历
binaryTree.nextTravel((key)=>{
  console.log(key) // 2,5,6,4,3,7,10,9,8
})

具体的逻辑

  1. 判断传入的节点是否为null,如果为null就直接return
  2. 如果不为null,则继续对该节点下的left和right进行递归调用
  3. 具体的调用顺序根据前序、中序、后序、的访问节点顺序去修改调用的顺序

还是放上这个二叉树的图,根据图去对比测试的遍历结果更直观:

二叉树图

重点

  1. 怎样设计遍历方法,调用者传什么东西进来,我们要暴露什么东西出去,这个地方得想明白

下期内容

  1. 实现二叉树的节点查找功能
  2. 实现二叉树中节点的删除功能
  3. 实现一个二叉树的一个小游戏

上期内容

  1. 使用javascript定义一个排序二叉树

JinsongChai
182 声望1 粉丝

每天进步一点点。。。