实现排序二叉树

时间:2022-02-08 15:13:51

概念

二叉树:如图。

  • 某个节点最多有两个子节点的树。常用于排序。效率较高。
  • 节点中的值:键。key。
  • 兄弟节点:拥有同一个父节点的节点。
  • 根节点:没有父节点
  • 外部节点:叶子节点,没有子节点。
  • 内部节点:中间节点。有子节点。
  • 高:节点都有深度,最大的节点深度即为这棵树的高。
  • 排序二叉树:节点左孩子的值小于它,右孩子的值大于它。显然,左子树的节点值都比当前节点小,右子树的逗比当前节点大。

实现排序二叉树

代码实现

需要创建对象实现其基本结构、封装相应属性和方法。创建对象或者继承对象的方法可见《JavaScript高级程序设计》第六章。这次实现则采取了构造函数进行封装的方法。

结构

  • 完整的排序二叉树,包括对节点(特别地,根节点)结构的描述、以及必要的方法。
  • 节点的一般结构:
    var Node = function(key){
    this.key = key;
    this.left = null;
    this.right = null;
    };

    var root = null;
  • 实际上是个也是个节点的构造函数,将在之后的insert()方法中对其进行调用。

方法

  • 有了基本的节点结构,就可以在此基础上使用必要的方法来创建、遍历、查询、删除排序二叉树了。
  • 创建一棵排序二叉树:insert(key)方法
    1. 基本描述:显然需要一个一个的插入相应的节点值,最后循环得到完整的排序二叉树。
    2. 分析:需要通过递归依次将待插入的节点与排序二叉树的部分节点进行大小比较。从根节点开始,遵循左子节点小于当前节点,右子节点大于当前节点的规则。就是说,需要考虑两种情况:插入根节点、插入一般节点。
    3. 借助:insertNode(key)函数。
    4. 递归:如图(借助中序遍历进行说明)。递归函数有个进栈和退栈的过程。当本次递归中所有语句执行完毕(这是一般情况,函数执行完毕都会默认return)或者遇到return语句的时候,会返回上一个调用这次递归的位置。并从该位置开始继续执行接下来的语句。
      实现排序二叉树
  • 遍历二叉树:
    • 同样涉及递归。
    • 操作的对象是整棵树
    • 显然x序遍历的“x”是前/中/后取决于当前节点的位置,而左一直在右前面
    • 中序遍历:
      1. 遍历顺序:左子节点(树)->当前节点->右子节点(树);
      2. 适合进行升序打印。
      3. 方法:inOrderTraverse(callback);//从根节点开始,callback()就是处理遍历到的节点的方法,较灵活。借助inOrderTraverseNode(node,callback)函数
    • 前序遍历:
      1. 遍历顺序:当前节点->左子节点(树)->右子节点(树);
      2. 适合进行排序二叉树的复制,效率比创建一棵同样的二叉树高;
      3. 方法:preOrderTraverse(callback);//从根节点开始,callback()就是处理遍历到的节点的方法,较灵活。借助preOrderTraverseNode(node,callback)函数
    • 后序遍历:
      1. 遍历顺序左子节点(树)->右子节点(树)->当前节点;
      2. 适合进行文件系统的遍历。
      3. 方法:postOrderTraverse(callback);//从根节点开始,callback()就是处理遍历到的节点的方法,较灵活。借助postOrderTraverseNode(node,callback)方法。
  • 查找二叉树
    • 查找是否有符合条件的节点。
    • 同样涉及遍历。
    • 查找整棵二叉树的最小值:从根节点开始,不断查找左子节点,直到某一个左子节点是叶节点,即为最小值对应的节点。
    • 查找整棵二叉树的最大值:从根节点开始,不断向右子节点查找,直到某一个右子节点是叶节点,即为最大值对应的节点
    • 查找任意值输入值:
      1. 与当前节点比较大小:若相同返回这个值;若小于当前节点,则进入左子树;若大于当前节点,则进入右子树。。。
      2. 直至找到相同值 or 无法继续查找(没有左节点或者右节点了),前者表示二叉树中存在相应节点(可以返回true或其他操作);后者表示不存在相应节点(可以返回false或进行其他操作)
      3. search(key)方法,借助search(node,key)函数。一般从根节点开始查找。
  • 删除节点(比较重要)
    • 同样涉及遍历
    • 有以下对应情况需要进行处理:
      1. 若只有一个子节点(只有左节点or右节点):删除该节点,将其父节点与其子节点连接起来。
      2. 若没有子节点(叶子节点):删除该节点,且删除其父节点指向他的连接(=null)
      3. 若有两个子节点:从右子树中找到值最小的那个,用其代替删除的节点。当然需要注意处理一些细节问题。比如几处指针的指向。
    • remove(key)方法。借助removeNode(node,key)函数。同样一般从根节点开始。
    • 其实涉及到节点的查找。

其他链接