利用js实现一个二叉查找树

648 阅读3分钟

定义

二叉查找树(Binary Search Tree),(又称:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树:

  1. 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  2. 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
  3. 它的左、右子树也分别为二叉排序树。

image.png

简而言之就是:任意节点的左子树上所有结点永远比该节点的右子树上所有结点的值小,它的任意左、右子树也分别为二叉查找树。

1、定义节点

首先我们声明一个创建节点的方法,它的属性里需要具有左右两个变量属性。

/**
 * 创建节点方法
 * @param  data  节点
 * @param  left  节点左子节点
 * @param  right 节点右子节点
 */
function TreeNode(data = '', left = null, right = null) {
    this.data = data;
    this.left = left;
    this.right = right;
}

2、定义树

/**
 * 创建树
 */
function BinaryTree() {
    // 记录根节点
    this.root = null;
}

3、定义插入方法

插入方法要注意的是,如果插入的节点值比父节点小则插入到左节点上反之则插入到右节点上,重复以上操作,找到一个合适放置插入数据的节点位置。

// 定义插入数据函数
BinaryTree.prototype.insert = function (val) {
  var newNode = new TreeNode(val);
  if (this.root == null) {
      this.root = newNode; // 你就是老大
  } else {
      var current = this.root;
      // 利用 while 循环去给传入的 val 寻找合适的家 
      while(true) {
          if (val < current.data) {
              if (current.left) {
                  current = current.left;
              } else {
                  current.left = newNode;
                  break;
              }
          } else if (val > current.data) {
              if (current.right) {
                  current = current.right;
              } else {
                  current.right = newNode;
                  break;
              }
          }
      }
  }
}

3、定义查询方法

查找功能其实与新增功能差不多,根据二叉树的定义,左子树的节点永远小于右子树的节点,所以在查找的时候就分为两步:

  1. 判断根节点是否已经存在。
  2. 待查找的节点从根节点开始逐级比较,循环查找,直到找到为止。
// 定义查找节点的函数
BinaryTree.prototype.findNode = function (data) {
      var node = this.root;
      while (node != null) {
          if (data < node.data) {
              node = node.left;
          } else if (data > node.data) {
              node = node.right;
          } else {
              return node;
          }
      }
      return null;
}

4、定义获取最大节点和最小节点的方法

// 获取最小值
BinaryTree.prototype.getNodeMin(node) {
      node = node || this.root;
      while (node.left != null) {
          node = node.left;
      }
      return node.data;
}

// 获取最大值
BinaryTree.prototype.getNodeMax(node) {
      node = node || this.root;
      while (node.right != null) {
          node = node.right;
      }
      return node.data;
}

5、定义删除方法

删除就比较麻烦了,想想也知道,情况比较多,具体做法就是定义一个函数,它的入参是一个节点和一个值(用于递归查找),然后进入处理流程:

  1. 先判断传入节点是否存在,不存在不处理。
  2. 比较当前传入要删除的值与节点值的大小,递归循环需要删除的节点,执行删除。
// 定义删除节点的函数
BinaryTree.prototype.removeNode = function (node, data) {
    if (node == null) {
        return null;
    }
    if (data < node.data) {
        node.left = this.removeNode(node.left, data);
        return node;
    } else if (data > node.data) {
        node.right = this.removeNode(node.right, data);
        return node;
    } else {
        if (node.left == null && node.right == null) {
            node = null;
            return node;
        } else if (node.left == null) {
            return node.right;
        } else if (node.right == null) {
            return node.left;
        } else {
            var minNode = this.getNodeMin(node.right);
            node.data = minNode.data;
            node.count = minNode.count;
            node.right = this.removeNode(node.right, minNode.data);
            return node;
        }
    }
}

6、中序遍历


BinaryTree.prototype.centerSort = function (node, arr = []) {
    if (node) {
        this.centerSort(node.left, arr);
        arr.push(node.data);
        this.centerSort(node.right,arr);
    }
    return arr;
}

7、前序遍历


BinaryTree.prototype.prevSort(node, arr= []) {
    if (node) {
          arr.push(node.data);
          this.prevSort(node.left, arr);
          this.prevSort(node.right, arr);
    }
    return arr;
}

8、后续遍历


BinaryTree.prototype.nextSort(node, arr = []) {
    if (node) {
          this.nextSort(node.left, arr);
          this.nextSort(node.right, arr);
          arr.push(node.data);
    }
    return arr;
}