:非顺序数据结构,对于存储需要快速查找的数据非常有用。
二叉树:二叉树中的节点最多只能有两个子节点(左侧子节点和右侧子节点)。这些定义有助于我们写出更高效的向/从树中插入、查找和删除节点的算法。
二叉搜索树:二叉树的一种,但是它只允许你在左侧节点存储(比父节点)小的值,在右侧节点存储(比父节点)大/等于的值。
 
遍历一棵树:是指访问树的每个节点并对它们进行某种操作的过程。访问树的所有节点有三种方式:中序、先序和后序。
中序遍历:是一种以上行顺序访问 BST 所有节点的的遍历方式,也就是以从最小到最大的顺序访问所有节点。中序遍历的一种应用就是对树进行排序操作。
先序遍历:是以优先于后代节点的顺序访问每个节点的。先序遍历的一种应用是打印一个结构化的文档。
后序遍历:是先访问节点的后代节点,再访问节点本身。后序遍历的一种应用是计算一个目录和它的子目录中所有文件所占空间的大小。
搜索树中的值:在树中,有三种经常执行的搜索类型:最小值、最大值、搜索特定的值
 

BST 存在一个问题:取决于添加的节点树,树的一条边可能会非常深;也就是说,树的一条分支会有很多层,二其他的分支却只有几层。这会在需要在某条边上添加、移除和搜索某个节点时引起一些性能问题。

AVL树:为了解决 BST 的问题,有一种树叫作阿德尔森-维尔斯和兰迪斯树(AVL树)。AVL树是一种自平衡二叉搜索树,意思是任何一个节点两侧子树的高度之差最多为1。也就是说这种树会在添加或移除节点时尽量试着成为一棵完全树。
红黑树:特殊的二叉树,可以进行高效的中序遍历。
 
术语:
         术语             
                                  解释                                 
节点
树中的每个元素
根节点
树顶部的节点,没有父节点
内部节点
至少有一个子节点的节点
外部节点(叶节点)
没有子元素的节点
子树
由节点和它的后代构成
深度
节点的一个属性,取决于它的祖先节点的数量
高度
取决于所有节点深度的最大值

---------------------------------------------------------------------------------------------------------
二叉搜索树方法声明:
1. 和链表一样,通过指针来表示节点之间的关系(术语称其为边);
2. 声明 Node 来表示树中的每个节点。
注意:不同于之前将节点本身称作节点或项,我们会称其为键。键是树相关的术语中对节点的称呼。
序号
方法
说明
1
insert(key) 向树中插入一个新的键
2
search(key) 在树中查找一个键,如果节点存在,则返回 true;如果不存在,则返回 false
3
inOrderTraverse 通过中序遍历方式遍历所有节点
4
preOrderTraverse 通过先序遍历方式遍历所有节点
5
postOrderTraverse 通过后序遍历方式遍历所有节点
6
min
返回树种最小的值/键
7
max 返回树种最大的值/键
8
remove(key) 从树中移除某个键


二叉搜索树的实现:
 function BinarySearchTree() {
// 辅助类Node定义
var Node = function(key) {
this.key = key;
this.left = null;
this.right = null;
}
var root = null; // 向树中插入一个新的键
this.insert = function(key) {
var newNode = new Node(key); if (root === null) {
root = newNode;
} else {
insertNode(root, newNode); // 私有的辅助函数
}
} this.insertNode = function(node, newNode) {
if (newNode.key < node.key) {
if (node.left === null) {
node.left = newNode;
} else {
insertNode(node.left, newNode); // 如果有左侧子节点,则通过递归调用继续找到树的下一层
}
} else {
if (node.right === null) {
node.right = newNode;
} else {
insertNode(node.right, newNode); // 如果有右侧子节点,则通过递归调用继续找到树的下一层
}
}
} /* 中序遍历
* inOrderTraverse方法接收一个回调函数作为参数。
* 回调函数用来定义我们对遍历到的每个节点进行的操作(也叫访问者模式)
*/
this.inOrderTraverse = function(callback) {
inOrderTraverseNode(root, callback);
} this.inOrderTraverseNode = function(node, callback) {
if (node !== null) {
inOrderTraverseNode(node.left, callback);
callback(node.key);
inOrderTraverseNode(node.right, callback);
}
} // 先序遍历
this.preOrderTraverse = function(callback) {
preOrderTraverseNode(root, callback);
} this.preOrderTraverseNode = function(node, callback) {
if (node !== null) {
callback(node.key);
preOrderTraverseNode(node.left, callback);
preOrderTraverseNode(node.right, callback);
}
} // 后序遍历
this.postOrderTraverse = function(allback) {
postOrderTraverseNode(root, callback);
} this.postOrderTraverseNode = function(node, callback) {
if (node !== null) {
postOrderTraverseNode(node.left, callback);
postOrderTraverseNode(node.right, callback);
callback(node.key);
}
} // 搜索树中的最小值
this.min = function() {
return minNode(root);
} var minNode = function(node) {
if (node) {
while (node && node.left !== null) {
node = node.lfet;
}
return node.key;
}
return null;
} // 搜索树中的最大值
this.max = function() {
return maxNode(root);
} this.maxNode = function(node) {
if (node) {
while (node && node.right !== null) {
node = node.right;
}
return node.key;
}
return null;
} // 搜索树中的特定值
this.search = function(key) {
return searchNode(root, key);
} var searchNode = function(node, key) {
if (node === null) {
return false;
}
if (key < node.key) {
return searchNode(node.left ,key);
} else if (key > node.key) {
return searchNode(node.right, key);
} else {
return true;
}
} // 从树中移除某个键
this.remove = function(key) {
root = removeNode(root, key); // root被赋值为removeNode方法的返回值
} var removeNode = function(node, key) {
if (node === null) { // 键不存在于树中,则返回null
return null;
}
if (key < node.key) { // 如果要找的键比当前节点的值小,就沿着树的左边找到下一个节点
node.left = removeNode(node.left, key);
return node;
} else if (key > node.key) { // 如果要找的键比当前节点的值大,就沿着树的左边找到下一个节点
node.right = removeNode(node.right, key);
return node;
} else { // 键等于node.key // 第一种情况——一个叶节点
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;
} // 第三种情况——一个有两个子节点的节点
var aux = findMinNode(node.right);
node.key = aux.key; // 用右侧子树中的最小节点的键去更新这个节点的值
node.right = removeNode(node.right, aux.key); // 移除右侧子树中的最小节点
return node;
}
}
}

BinarySearchTree.js

 
 参考书籍:《学习JavaScript数据结构与算法》 
 

JavaScript数据结构——树的更多相关文章

  1. JavaScript数据结构——树的实现

    在计算机科学中,树是一种十分重要的数据结构.树被描述为一种分层数据抽象模型,常用来描述数据间的层级关系和组织结构.树也是一种非顺序的数据结构.下图展示了树的定义: 在介绍如何用JavaScript实现 ...

  2. JavaScript数据结构-树

    我认为这社会上,也不差钱好多人,可能好多人也不差权力.可是我认为能得到这样的满足的也不多. –郭小平<临汾红丝带学校校长> ​ 树是计算机科学中经经常使用到的一种数据结构. 树是一种非线性 ...

  3. 学习javascript数据结构(四)——树

    前言 总括: 本文讲解了数据结构中的[树]的概念,尽可能通俗易懂的解释树这种数据结构的概念,使用javascript实现了树,如有纰漏,欢迎批评指正. 原文博客地址:学习javascript数据结构( ...

  4. 为什么我要放弃javaScript数据结构与算法(第八章)—— 树

    之前介绍了一些顺序数据结构,介绍的第一个非顺序数据结构是散列表.本章才会学习另一种非顺序数据结构--树,它对于存储需要快速寻找的数据非常有用. 本章内容 树的相关术语 创建树数据结构 树的遍历 添加和 ...

  5. JavaScript 数据结构与算法之美 - 非线性表中的树、堆是干嘛用的 ?其数据结构是怎样的 ?

    1. 前言 想学好前端,先练好内功,内功不行,就算招式练的再花哨,终究成不了高手. 非线性表(树.堆),可以说是前端程序员的内功,要知其然,知其所以然. 笔者写的 JavaScript 数据结构与算法 ...

  6. javascript数据结构与算法-- 二叉树

    javascript数据结构与算法-- 二叉树 树是计算机科学中经常用到的一种数据结构.树是一种非线性的数据结构,以分成的方式存储数据,树被用来存储具有层级关系的数据,比如文件系统的文件,树还被用来存 ...

  7. 为什么我要放弃javaScript数据结构与算法(第九章)—— 图

    本章中,将学习另外一种非线性数据结构--图.这是学习的最后一种数据结构,后面将学习排序和搜索算法. 第九章 图 图的相关术语 图是网络结构的抽象模型.图是一组由边连接的节点(或顶点).学习图是重要的, ...

  8. 为什么我要放弃javaScript数据结构与算法(第七章)—— 字典和散列表

    本章学习使用字典和散列表来存储唯一值(不重复的值)的数据结构. 集合.字典和散列表可以存储不重复的值.在集合中,我们感兴趣的是每个值本身,并把它作为主要元素.而字典和散列表中都是用 [键,值]的形式来 ...

  9. JavaScript数据结构——字典和散列表的实现

    在前一篇文章中,我们介绍了如何在JavaScript中实现集合.字典和集合的主要区别就在于,集合中数据是以[值,值]的形式保存的,我们只关心值本身:而在字典和散列表中数据是以[键,值]的形式保存的,键 ...

随机推荐

  1. netty4 Handler的执行顺序

    转载:https://my.oschina.net/jamaly/blog/272385 Handler在netty中,无疑占据着非常重要的地位.Handler与Servlet中的filter很像,通 ...

  2. spring校验相关

    转载:http://elim.iteye.com/blog/1812584 对于任何一个应用而言在客户端做的数据有效性验证都不是安全有效的,这时候就要求我们在开发的时候在服务端也对数据的有效性进行验证 ...

  3. hadoop工作流引擎之azkaban [转]

    介绍 Azkaban是twitter出的一个任务调度系统,操作比Oozie要简单很多而且非常直观,提供的功能比较简单.Azkaban以Flow为执行单元进行定时调度,Flow就是预定义好的由一个或多个 ...

  4. Ext grid checkbox 分页 翻页 勾选 问题

    timeArray = new Array(); //临时数组变量 var timeStatusBar = new Ext.ux.StatusBar({ id: 'statusbar', defaul ...

  5. javascript密码强度验证!

    //CharMode函数 //测试某个字符是属于哪一类 function CharMode(iN) { if (iN>=48 && iN <=57) //数字 return ...

  6. [Js]面向对象的拖拽

    <html xmlns="http://www.w3.org/1999/xhtml"><head><style>#div1 {width:100 ...

  7. SQL Server 自定义字符串分割函数

    一.按指定符号分割字符串,返回分割后的元素个数,方法很简单,就是看字符串中存在多少个分隔符号,然后再加一,就是要求的结果(标量值函数)   create function Func_StrArrayL ...

  8. Codeforces Round #378 (Div. 2) D题(data structure)解题报告

    题目地址 先简单的总结一下这次CF,前两道题非常的水,可是第一题又是因为自己想的不够周到而被Hack了一次(或许也应该感谢这个hack我的人,使我没有最后在赛后测试中WA).做到C题时看到题目情况非常 ...

  9. 数列F[19] + F[13]的值

    已知数列如下:F[1]=1, F[2]=1, F[3]=5,......,F[n] =F[n-1] + 2*F[n-2],求F[19] + F[13]? #include <stdio.h> ...

  10. BeanUtils组件

    引入jar包(需要引入依赖的日志jar包) Person p = new Person(); p.setName("Daisy"); p.setAge(12); //对象的copy ...