数据结构之二叉搜索树

1. 相关术语

  1. 第一个节点叫做根节点
  2. 包含至少一个子节点的节点叫做内部节点
  3. 树最后表示结束不包含任何数据的用null表示的节点叫做叶节点

2. 二叉搜索树

左侧的子节点小于父节点,右侧的子节点大于父节点。
在这里插入图片描述

  1. insert(key) 插入一个元素
  2. search(key) 查找树中是否包含key元素,是返回true, 否返回false
  3. inOrderTraverse() 中序遍历,以从小到大的顺序遍历所有节点。
  4. preOrderTraverse() 先序遍历,先遍历父节点,在遍历子节点。打印一个结构化的文档。
  5. postOrderTraverse() 后序遍历,先遍历子节点在遍历父节点。计算一个目录以及其子目录中所有文件占用的空间大小。
  6. min() 查找最小值
  7. max() 查找最大值
  8. remove(key) 移除某个元素

2.1 节点对象

class Node {
  constructor(key) {
    this.key = key;
    this.left = null;
    this.right = null
  }
}

2.2 比较函数

const COMPARE = {
  LESS_THAN: 'LESS_THAN',
  EQUALITY: 'EQUALITY',
  BIGGER_THAN: 'BIGGER_THAN'
}

// 2. 比较函数
function defaultCompareFn(a, b) {
  if (a < b) {
    return COMPARE.BIGGER_THAN;
  }
  else if (a > b) {
    return COMPARE.LESS_THAN;
  }
  else {
    return COMPARE.EQUALITY;
  }
}

2.3 树对象

class BinarySearchTree {
  constructor(compareFn = defaultCompareFn) {
    this.root = null;
    this.compareFn = compareFn;
  }

  insert(key) {
    if (this.root === null) {
      this.root = new Node(key);
    }
    else {
      this.insertNode(this.root, key);
    }
  }

  insertNode(node, key) {
    if (this.compareFn(node.key, key) === COMPARE.LESS_THAN) {
      if (node.left === null) {
        node.left = new Node(key);
      }
      else {
        this.insertNode(node.left, key);
      }
    }
    else {
      if (node.right === null) {
        node.right = new Node(key);
      }
      else {
        this.insertNode(node.right, key);
      }
    }
  }
  // 查找特定节点
  search(key) {
    return this.searchNode(this.root, key);
  }

  searchNode(node, key) {
    if (node === null) return false;
    const compareResult = this.compareFn(node.key, key);
    if (compareResult === COMPARE.LESS_THAN) {
      return this.searchNode(node.left, key);
    }
    else if (compareResult === COMPARE.BIGGER_THAN) {
      return this.searchNode(node.right, key);
    }
    else {
      return true;
    }
  }

  // 查找最小值
  min() {
    return this.minNode(this.root);
  }

  minNode(node) {
    let currentNode = node;
    while (currentNode !== null && currentNode.left !== null) {
      currentNode = currentNode.left;
    }
    return currentNode;
  }

  // 查找最大值
  max() {
    return this.maxNode(this.root);
  }

  maxNode(node) {
    let currentNode = node;
    while (currentNode !== null && currentNode.right !== null) {
      currentNode = currentNode.right;
    }
    return currentNode;
  }

  // 中序遍历
  inOrderTraverse(callback) {
    this.inOrderTraverseNode(this.root, callback);
  }

  inOrderTraverseNode(node, callback) {
    if (node !== null) {
      this.inOrderTraverseNode(node.left, callback);
      callback(node);
      this.inOrderTraverseNode(node.right, callback);
    }
  }

  preOrderTraverse(callback) {
    this.preOrderTraverseNode(this.root, callback);
  }
  preOrderTraverseNode(node, callback) {
    if (node !== null) {
      callback(node);
      this.preOrderTraverseNode(node.left, callback);
      this.preOrderTraverseNode(node.right, callback);
    }
  }

  // 后序遍历
  postOrderTraverse(callback) {
    this.postOrderTraverseNode(this.root, callback);
  }

  postOrderTraverseNode(node, callback) {
    if (node !== null) {
      this.preOrderTraverseNode(node.left, callback);
      this.preOrderTraverseNode(node.right, callback);
      callback(node);
    }
  }

  remove(key) {
    this.root = this.removeNode(this.root, key);
  }

  removeNode(node, key) {
    if (node === null) return null;
    const compareResult = this.compareFn(node.key, key);
    if (compareResult === COMPARE.LESS_THAN) {
      node.left = this.removeNode(node.left, key);
      return node;
    }
    else if (compareResult === COMPARE.BIGGER_THAN) {
      node.right = this.removeNode(node.right, key);
      return node;
    }

    if (node.left === null && node.right === null) {
      node = null;
      return node;
    }
    if (node.left === null) {
      node = node.right;
      return node;
    }
    else if (node.right === null) {
      node = node.left;
      return node;
    }

    let aux = this.minNode(node.right);
    node.key = aux.key;
    node.right = this.removeNode(node.right, aux.key);
    return node;
  }

}

let bst = new BinarySearchTree()
bst.insert(10);
bst.insert(1);
bst.insert(2);
bst.insert(5);
bst.insert(9);
console.log('bst:', bst.root);
console.log('min', bst.min().key);
console.log('max', bst.max().key);
bst.inOrderTraverse(function(node) {
  console.log('key:', node.key);
})

3. AVL树

任何一个节点,他的左子树和右子树高度最多相差1。
本质上还是一种二叉搜索树,可以继承BinarySearchTree类,只需要重新插入和删除等可能会影响平衡的方法即可。

class AVLTree extends BinarySearchTree {
  constructor(compareFn = defaultCompareFn) {
    super(compareFn);
    this.root = null
    this.compareFn = compareFn;
  }
}

3.1 节点高度

从节点到最小子节点的距离。

getNodeHeight(node) {
  if (node === null) return -1;

  return Math.max(
    this.getNodeHeight(node.left), 
    this.getNodeHeight(node.right)
  ) + 1;
}

3.2 平衡因子

根据节点高度获取节点的平衡因子,如果平衡因子为 -1、0、+1,表示该节点处于平衡状态,不需要做平衡处理,否则,表示该节点失衡,需要做平衡处理。

平衡因子常量:

const BALANCE_FACTOR = {
  UNBALANCE_RIGHT: -2,
  SLIGHTLY_UNBALANCE_RIGHT: -1,
  BALANCE: 0,
  SLIGHTLY_UNBALANCE_LEFT: 1,
  UNBALANCE_LEFT: 2
}
getBalanceFactor(node) {
  const heightDifference = this.getNodeHeight(node.left) - this.getNodeHeight(node.right);

  switch (heightDifference) {
    case -2:
      return BALANCE_FACTOR.UNBALANCE_RIGHT;
    case -1:
      return BALANCE_FACTOR.SLIGHTLY_UNBALANCE_RIGHT;
    case 1:
      return BALANCE_FACTOR.SLIGHTLY_UNBALANCE_LEFT;
    case 2:
      return BALANCE_FACTOR.UNBALANCE_LEFT;
    default:
      return BALANCE_FACTOR.BALANCE;
  }
}

3.3 平衡方法

3.3.1 LL型

左侧子树高度大于右侧子树高度超过1,节点Node向右旋转,变成左侧子节点的右侧节点,左侧子节点的右侧节点,变成节点Node的左侧节点。
在这里插入图片描述

rotateLL(node) {
  let temp = node.left;
  node.left = temp.right;
  temp.right = node;
  return temp;
}

3.3.2 RR型

右侧子树的高度比左侧子树的高度大于1,节点Node向左旋转,变成右侧节点的左侧节点,右侧节点的左侧节点变成节点Node的右侧节点。
在这里插入图片描述

rotateRR(node) {
  let temp = node.right;
  node.right = temp.left;
  temp.left = node;
  return temp;
}

3.3.3 LR型

左侧子树的高度比右侧子树的高度大于1,并且左侧子节点的右侧子树高度大于左侧子节点的左侧子树高度。节点Node的左侧子节点向左旋转,变成LL型,节点Node再向右旋转。
在这里插入图片描述

rotateLR(node) {
  node.left = this.rotateRR(node.left);
  return this.rotateLL(node);
}

3.3.4 RL型

右侧子树高度比左侧子树高度大于1,并且右侧子节点的左侧子树高度比右侧子树高度大。节点Node的右侧子节点向右旋转,变成RR型,节点Node在向左旋转。
在这里插入图片描述

rotateRL(node) {
  node.right = this.rotateLL(node.right);
  return this.rotateRR(node);
}

3.4 插入元素

insert(key) {
  this.root = this.insertNode(this.root, key);
}

insertNode(node, key) {
  if (node === null) {
    return new Node(key);
  }

  if (this.compareFn(node.key, key) === COMPARE.LESS_THAN) {
    node.left = this.insertNode(node.left, key);
  }
  else if (this.compareFn(node.key, key) === COMPARE.BIGGER_THAN) {
    node.right = this.insertNode(node.right, key);
  }
  else {
    return node;
  }

  // 处理平衡问题
  const factor = this.getBalanceFactor(node);
  // 选择旋转类型
  if (factor === BALANCE_FACTOR.UNBALANCE_LEFT) {
    if (this.compareFn(node.left.key, key) === COMPARE.LESS_THAN) {
      node = this.rotateLL(node);
    }
    else {
      node = this.rotateLR(node);
    }
  }
  else if (factor === BALANCE_FACTOR.UNBALANCE_RIGHT) {
    if (this.compareFn(node.right.key, key) === COMPARE.BIGGER_THAN) {
      node = this.rotateRR(node);
    }
    else {
      node = this.rotateRL(node);
    }
  }

  return node;
}

3.5 删除元素

removeNode(node, key) {
  node = super.removeNode(node, key);
  if (node === null) return node;

  // 处理平衡问题
  const factor = this.getBalanceFactor(node);
  if (factor === BALANCE_FACTOR.UNBALANCE_LEFT) {
    const factorLeft = this.getBalanceFactor(node.left);
    // LL型
    if (
      factorLeft === BALANCE_FACTOR.BALANCE ||
      factorLeft === BALANCE_FACTOR.SLIGHTLY_UNBALANCE_LEFT
    ) {
      return this.rotateLL(node);
    }
    // LR型
    else if (factorLeft === BALANCE_FACTOR.SLIGHTLY_UNBALANCE_RIGHT) {
      return this.rotateLR(node);
    }
  }
  else if (factor === BALANCE_FACTOR.UNBALANCE_RIGHT) {
    const factorRight = this.getBalanceFactor(node.right);
    // RR型
    if (
      factorRight === BALANCE_FACTOR.BALANCE ||
      factorRight === BALANCE_FACTOR.SLIGHTLY_UNBALANCE_RIGHT
    ) {
      return this.rotateRR(node);
    }
    // RL型
    else if (factorRight === BALANCE_FACTOR.SLIGHTLY_UNBALANCE_LEFT) {
      return this.rotateRL(node);
    }
  }
  return node;
}

4. 红黑树

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值