树结构
树是一种重要的非线性数据结构,直观地看,它是数据元素(在树中称为结点)按分支关系组织起来的结构,很象自然界中的树那样。
- HTML结构就是典型的树结构
二叉搜索树
- 特点:
- 节点最多只能有两个子节点,一个左子节点,一个右子节点,左右子节点的顺序不能颠倒。
- 在左侧存储比父节点小的值
- 在右侧存储比父节点大的值
- 实现:
- 树(Tree)有:根节点,内部的Node类,查找,删除,插入,遍历
- 树(Tree)有:根节点,内部的Node类,查找,删除,插入,遍历
- 插入节点
function Tree(){
var Node = function(val){
this.value = val
this.left = null
this.right = null
}
var root = null
// 插入节点
/**
* 1、树为空树:root = value
* 2、树不是空的:对比节点
*/
var insertNode = function(node,newNode){
if(newNode.value>node.value){
if(node.right===null){
node.right = newNode
}else{
insertNode(node.right,newNode)
}
}else if(newNode.value<node.value){
if(node.left===null){
node.left = newNode
}else{
insertNode(node.left,newNode)
}
}
}
this.insert = function(value){
var node = new Node(value)
if(root===null){
root = node
}else{
insertNode(root,node)
}
}
}
- 遍历树
// 遍历节点
// 借助递归
function traverse(node, callback){
if(node===null) return;
traverse(node.left,callback)
traverse(node.right,callback)
callback(node.value)
}
this.traverse = function(callback){
traverse(root,callback)
}
- 获取最小值
- 移除节点
移除节点有很多种情况:
- 移除有2个子节点的?——选哪个子节点来代替被删除的节点
- 移除末位节点(叶节点)
- 移除只有1个子节点
/**
* 根节点 root
* 插入 insert
* 查找 search
* 遍历 traverse
* 删除 remove
* 内部的Node类
*
*/
function Tree(){
var Node = function (value){
this.value = value
this.left = null
this.right = null
}
var root = null
// 插入
function insert(node,newNode){
if(node.value<newNode.value){
if(node.right===null){
node.right = newNode
}else{
insert(node.right,newNode)
}
}else{
if(node.left===null){
node.left = newNode
}else{
insert(node.left,newNode)
}
}
}
this.insert = function(value){
var node = new Node(value)
if(!root){
root = node
}else{
insert(root,node)
}
}
// 搜索
var searchNode = function(node,value){
if(node===null) return null
if(value<node.value) return searchNode(node.left,value)
else if(value>node.value) return searchNode(node.right,value)
else return node
}
this.search = function(val){
searchNode(root,value)
}
// 遍历
function traverse (node,callback){
if(!node) return;
// callback(node.value) //前序遍历 —— 访问根节点的操作发生在遍历其左右子树之前。
traverse(node.left,callback)
// callback(node.value) //中序遍历 —— 访问根节点的操作发生在遍历其左右子树之间。
traverse(node.right,callback)
callback(node.value) //后序遍历 —— 访问根节点的操作发生在遍历其左右子树之后
}
this.traverse = function(callback){
traverse(root,callback)
}
// 最小值
this.min = function(node){
if(node===null) return null;
while(node&&node.left!==null){
node = node.left
}
return node
}
// 最大值
this.max = function(node){
if(node===null) return null
while(node&&node.right!==null){
node = node.right
}
return node
}
// 删除——重新构建树
function findMinNode(node){
if(node === null) return null
while(node && node.left!== null){
node = node.left
}
return node
}
let removeNode = function (node, key) {
if (node === null) return null;
// 查找
if (key < node.value) {
node.left = removeNode(node.left, key);
return node;
}else if (key > node.value) {
node.right = removeNode(node.right, key);
return node;
}else {
// 找到节点后,删除
// 第一种情况:一个叶子节点(没有子节点)
if (node.left === null && node.right === null) {
node = null;
return null;
}
// 第二种情况:只包含一个子节点
if (node.left === null) {
node = node.right;
return node;
}
else if (node.right === null) {
node = node.left;
return node;
}
// 第三种情况:有两个子节点
let aux = findMinNode(node);
node.value = aux.key;
node.right = removeNode(node.right, aux.value);
return node;
}
};
this.remove = function(key){
root = removeNode(root,key)
}
this.getTree = function(){
return root
}
}
var t = new Tree
t.insert(8)
t.insert(2)
t.insert(3)
t.insert(9)
// t.remove(2)
// console.log(t.getTree())