树是一种分层数据的抽象模型。由一个或多个父子关系的节点组成。
相关术语

- 根节点 :位于树的顶部的节点叫根节点
- 内部节点 :至少有一个子节点的节点称为内部节点,如上图的 7,5,9,15,13,20
- 外部节点 :一个节点都没有的节点称为外部节点,也叫
叶节点,如上图的 3,6,8,10,12,14,18,25 - 子树 :由节点和他的后代节点组成,如上图的 13,12,14 构成了一个子树
- 节点深度 :节点的深度取决于节点的祖先节点的数量,如上图的节点3,它的祖先节点有 5,7,11, 所以它的节点深度为3
- 树的高度 :树的高度是所有节点的深度的最大值,如上图树的高度最大的节点深度为3,其树的高度也就是3。也可以通过分层,根节点在第0层,子节点在第1层,依此类推,可得到树的高度。
二叉树
二叉树就是只有两个节点的树,一个左节点和一个右节点。
二叉搜索树
二叉搜索树(BST),是二叉树的一种,他的特点是左侧节点比父节点小,右侧节点比父节点大。
class Node {constructor(key) {this.key = key;this.left = null;this.right = null;}}class BinarySearchTree {constructor() {this.root = null;}insert(key) {if (this.root) {this.insertNode(this.root, key);} else {this.root = new Node(key);}}insertNode(node, key) {if (key < node.key) {if (node.left) {this.insertNode(node.left, key);} else {node.left = new Node(key);}} else {if (node.right) {this.insertNode(node.right, key);} else {node.right = new Node(key);}}}/*** 中序遍历* 从小到大访问节点* @param {*} callback*/inOrderTraverse(callback) {this.inOrderTraverseNode(this.root, callback);}inOrderTraverseNode(node, callback) {if (node) {this.inOrderTraverseNode(node.left, callback);callback(node.key);this.inOrderTraverseNode(node.right, callback);}}/*** 先序遍历* 从上往下,先左后右访问节点* @param {*} callback*/preOrderTraverse(callback) {this.preOrderTraverseNode(this.root, callback);}preOrderTraverseNode(node, callback) {if (node) {callback(node.key);node.left && this.preOrderTraverseNode(node.left, callback);node.right && this.preOrderTraverseNode(node.right, callback);}}/*** 后序遍历* 从下往下,先左后右访问节点* @param {*} callback*/postOrderTraverse(callback) {this.postOrderTraverseNode(this.root, callback);}postOrderTraverseNode(node, callback) {if (node) {node.left && this.postOrderTraverseNode(node.left, callback);node.right && this.postOrderTraverseNode(node.right, callback);callback(node.key);}}min() {return this.minNode(this.root);}minNode(node) {let current = node;while (current && current.left) {current = current.left;}return current;}max() {let current = this.root;while (current && current.right) {current = current.right;}return current;}search(key) {return this.searchNode(this.root, key);}searchNode(node, key) {if (!node) return false;if (key < node.key) {return this.searchNode(node.left, key);} else if (key > node.key) {return this.searchNode(node.right, key);} else {return true;}}remove(key) {return this.removeNode(this.root, key);}removeNode(node, key) {if (!node) return null;if (key < node.key) {node.left = this.removeNode(node.left, key);return node;} else if (key > node.key) {node.right = this.removeNode(node.right, key);} else {if (!node.left && !node.right) {node = null;} else if (node.left && !node.right) {node = node.left;} else if (!node.left && node.right) {node = node.right;} else {let minNode = this.minNode(node.right);node.key = minNode.key;node.right = this.removeNode(node.right, minNode.key);}return node;}}toString() {return JSON.stringify(this.root, null, 2);}}const tree = new BinarySearchTree();tree.insert(11);tree.insert(7);tree.insert(15);tree.insert(5);tree.insert(3);tree.insert(9);tree.insert(8);tree.insert(10);tree.insert(13);tree.insert(12);tree.insert(14);tree.insert(20);tree.insert(18);tree.insert(25);tree.insert(6);tree.remove(5)console.log(tree.toString());
