树结构_二叉搜索树
二叉搜索树(BST, Binary Search Tree)
1. 二叉树也是一颗二叉树, 可以为空
2. 如果不为空,则满足以下条件
1. 非空左子树的所有键值小于其根节点的键值
2. 非空右子树的所有键值大于其根节点的键值
3. 左, 右子树本身也是搜索树
3. 二叉搜索树的特点
1. 二叉搜索树中,相对较小的值总包存在左节点上, 嫌贵较大的值总是保存在右节点上
注: 这一特性可以保证二叉搜索树高效的送偶所特性
4. 二叉搜索树的节点的属性
this.item = item
this.left = null
this.right = null
5. 二叉搜索树的属性
6. 二叉搜索树的方法
1. insertItem(item) 向树中插入一个新的键
2. search(key) 查看树中是否包含指定的键值,若节点存在则返回true,否则返回false
3. preOrderTravel() 先序遍历
4. inOrderTravel() 中序遍历
5. postOrderTravel() 后序遍历
6. 层序遍历
7. min() 返回书中最小的值/键
8. max() 返回树中最大的值/键
9. remove(key) 从树中移除某个键
7. remove方法思路
删除的节点分三种情况:
1. 被删除的节点为叶节点(即没有子节点)
2. 被删除的节点只有一个子节点
3. 被删除的节点有两个子节点
8. 二叉搜索树的嗲马实现
function BinarySarchTree(){ // 1. 封装节点类 function Node(item){ this.item = item; this.left = null; this.right = null; } // 2. 二叉搜索树的属性 this.root = null; // // 3. 二叉搜索树的方法 // 1. 向树中插入一个新的键 BinarySarchTree.prototype.insertItem = function(key){ // 1. 首先创建节点 var newNode = new Node(key); // 2. 首先判断根节点是否有值 if(this.root == null){ this.root = newNode; }else{ this.insertNode(this.root, newNode); } } // 内部函数——插入节点 BinarySarchTree.prototype.insertNode = function(node, newNode){ if(newNode.item < node.item){ // 向左查找 if(node.left == null){ node.left = newNode; }else{ this.insertNode(node.left, newNode); } }else{ // 向右查找 if(node.right == null){ node.right = newNode; }else{ this.insertNode(node.right, newNode); } } } // 2. 查看树中是否包含指定的键值,若节点存在则返回true,否则返回false BinarySarchTree.prototype.search = function(key){ var node = this.root; while(node != null){ if(key < node.item){ node = node.left; }else if(key > node.item){ node = node.right; }else{ return true; } } return false; } // 3. 先序遍历 /* 遍历过程: 1. 访问根节点 2. 先序遍历其左子树 3. 先序遍历其右子树 */ BinarySarchTree.prototype.preOrderTravel = function(handler){ this.preOrderTravelNode(this.root, handler); } // 内部函数——先序遍历 BinarySarchTree.prototype.preOrderTravelNode = function(node, handler){ // 若节点不为空 if(node !== null){ // 1. 调用回调函数 handler(node.item); // 2. 处理左子树 this.preOrderTravelNode(node.left, handler); // 3. 处理右子树 this.preOrderTravelNode(node.right, handler); } } // 4. 中序遍历 /* 遍历过程: 1. 先序遍历其左子树 2. 访问根节点 3. 先序遍历其右子树 */ BinarySarchTree.prototype.inOrderTravel = function(handler){ this.inOrderTravelNode(this.root, handler); } // 内部函数——先序遍历 BinarySarchTree.prototype.inOrderTravelNode = function(node, handler){ // 若节点不为空 if(node !== null){ // 1. 处理左子树 this.inOrderTravelNode(node.left, handler); // 2. 调用回调函数 handler(node.item); // 3. 处理右子树 this.inOrderTravelNode(node.right, handler); } } // 5. 后序遍历 /* 遍历过程: 1. 先序遍历其左子树 2. 先序遍历其右子树 3. 访问根节点 */ BinarySarchTree.prototype.postOrderTravel = function(handler){ this.postOrderTravelNode(this.root, handler); } // 内部函数——先序遍历 BinarySarchTree.prototype.postOrderTravelNode = function(node, handler){ // 若节点不为空 if(node !== null){ // 1. 处理左子树 this.postOrderTravelNode(node.left, handler); // 2. 处理右子树 this.postOrderTravelNode(node.right, handler); // 3. 调用回调函数 handler(node.item); } } // 6. 层序遍历 // 7. 返回树中最小的值/键 BinarySarchTree.prototype.min = function(){ var cur = this.root; if(cur == null){ return null; } // 依次向左查找 while(cur.left != null){ cur = cur.left; } return cur.item; } // 8. 返回树中最大的值/键 BinarySarchTree.prototype.max = function(){ var cur = this.root; if(cur == null){ return null; } // 依次向右查找 while(cur.right != null){ cur = cur.right; } return cur.item; } // 9. 从树中移除某个键 BinarySarchTree.prototype.remove = function(key){ // 1. 寻找需要删除的节点 var cur = this.root; var parent = null; var isLeft = true; if(cur == null){ return false; }else{ while(key != cur.item){ parent = cur; if(key < cur.item){ cur = cur.left; isLeft = true; }else{ cur = cur.right; isLeft = false; } // 若cur为空,则说明没找到,直接返回 if(cur == null){ return false; } } // 能跳出while循环,则说明找到了 // 找到的节点为cur,其父节点为parent // 2. 判断所找到的节点类型 // 2.1 若被删除的节点为叶节点 if(cur.left == null && cur.right == null){ if(cur == this.root){ this.root = null; }else if(isLeft == true){ // 若需要删除的叶节点为父节点的左子节点,则将右子节点赋值给左子节点, 然后将右子节点置为空 parent.left = null } } // 2.2 若被删除的节点只有一个子节点 else if(cur.left == null){ if(cur == this.root){ this.root = cur.right; } // cur.left = null 说明cur节点的左节点为空,右节点不为空 else if(isLeft == true){ parent.left = cur.right; }else{ parent.right = cur.right; } }else if(cur.right == null){ if(cur == this.root){ this.root = cur.left; } // cur.right = null 说明cur节点的左节不为空,右节点为空 else if(isLeft == true){ parent.left = cur.left; }else{ parent.right = cur.left; } } } } }