树是一种非线性的数据结构,以分层的方式存储数据。树被用来存储具有层级关系的数据。树可以分为几层,根节点是第0层,我们定义树的层数就是树的深度。
二叉树是一种特殊的树,它的子节点个数不超过两个。二叉查找树(BST)是一种特殊的二叉树,相对较小的值保存在左节点中,较大的值保存在右节点中。在二叉树查找上进行查找非常快,为二叉树添加或删除元素非常快。
BST的JS实现
网页展示
代码部分
1.构造
//BST.js
//包含两个类,Node()存储节点,BST()存储树。
function Node(data, left, right)
{
this.data = data;
this.count = 1;
this.left = left;
this.right = right;
this.show = show;//显示节点数据
this.update = update;//计数功能
}
function show(){
return this.data;
}
function update(){
return ++this.count;
}
function BST(){
this.root = null;
this.knots = 0;//记录节点个数
this.insert = insert;//插入操作
this.find = find;//查找操作
this.getMin = getMin;
this.getMax = getMax;
this.remove = remove;//删除操作
this.countKnots = countKnots;//返回节点个数
this.countEdges = countEdges;//返回边个数
}
2.插入
//BST.js
function insert(data){
var n = new Node(data, null, null);//新建包含该数据的节点
this.knots++;
if(this.root == null)
{
this.root = n;
}
else
{
var current = this.root;
while(true)
{
//如果待插入节点的数据小于当前节点,则设置其左节点为当前节点
if(data<current.data)
{
//如果当前节点的左节点为空,就将新的节点插入这个位置
if(current.left == null)
{
current.left = n;
break;
}
current = current.left;
}
//如果待插入节点的数据大于或者等于当前节点,则设置其右节点为当前节点
else{
//如果当前节点的右节点为空,就将新的节点插入这个位置
if(current.right == null)
{
current.right = n;
break;
}
current = current.right;
}
}
}
}
3. 遍历
有三种遍历:中序,先序和后序。使用递归的方法最容易实现。
//BST.js
//中序遍历按照节点上的键值,以升序访问所有节点
function inOrder(node){
var instr = "";
if(!(node == null)){
inOrder(node.left);
instr += node.show()+" ";
inOrder(node.right);
}
return instr;
}
//先序遍历先访问根节点,然后以相同的方式访问左子树和右子树
function preOrder(node){
var prestr = "";
if(!(node == null)){
prestr += node.show()+" ";
preOrder(node.left);
preOrder(node.right);
}
return prestr;
}
//后序遍历先访问叶子节点,然后以相同的方式访问左子树和右子树
function postOrder(node){
var poststr = "";
if(!(node == null)){
postOrder(node.left);
postOrder(node.right);
poststr += node.show()+" ";
}
return poststr;
}
4. 删除
function remove(data){
this.root = removeNode(this.root, data);
this.knots--;
}
//该方法中使用了递归操作
function removeNode(node, data)
{
if(node == null)
{
return null;
}
//巧了!待删除的数据刚好是这个节点
if(data == node.data){
//如果左右皆空,直接删除
if(node.left == null && node.right == null)
{
node = null;
}
//如果左空,将其右子树移过来
else if(node.left == null)
{
node = node.right;
}
//如果右空,将其左子树移过来
else if(node.right == null)
{
node = node.left;
}
//如果左右都不空,将右子树的最小值移到该节点
else{
var temp = getSmallest(node.right);
node.data = temp;
node.right = removeNode(node.right, temp);
}
}
//不巧!!!待删除的数据不是该节点,那一定在该节点的左子树或者右子树上
else if(data < node.data){
node.left = removeNode(node.left, data);
}
else{
node.right = removeNode(node.right, data);
}
//因为所有改动都是在当前节点node上进行的,所以直接返回node即可
return node;
}
function getSmallest(node){
if(node == null)
{
//空树
}
while(!(node.left == null)){
node = node.left;
}
return node.data;
}
5.查找
//找最左边那个值
function getMin(){
var current = this.root;
if(current == null)
{
//空树
}
while(!(current.left == null)){
current = current.left;
}
return current.data;
}
//找最右边那个值
function getMax(){
var current = this.root;
if(current == null)
{
//空树
}
while(!(current.right == null)){
current = current.right;
}
return current.data;
}
function find(data){
var current = this.root;
while(current != null)
{
if(data == current.data)
return current;
else if(data < current.data)
current = current.left;
else
current = current.right;
}
return null;
}
6. 其它
function countKnots(){
return this.knots;
}
function countEdges(){
return this.knots-1;
}
BST计数
计数是指记录一组数据中某数据出现的次数。
网页展示
代码部分
<!-- index.html-->
<!DOCTYPE html>
<html>
<head>
<title>JS structure - BST</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="BST.js" type="text/javascript"></script>
<script src="app.js" type="text/javascript"></script>
</head>
<style>
#element {
width: 60%;
margin: 30px auto;
padding: 10px;
border: 1px solid #333;
}
label {
font-style:normal;
font-size:16px;
}
</style>
<body>
<div id="element">
<h2>计数<h2>
<label for="num_of_grades">输入成绩个数:</label>
<input type="text" id="num_of_grades" />
<input type="button" value="随机生成成绩:" onclick="getGrades()" />
<textarea id="bst_grades"></textarea>
<div>
<label for="num_of_grades">查询获得该成绩的人数:</label>
<input type="text" id="num_of_certain_grade" />
<input type="button" value="计数:" onclick="BSTcount()" />
<textarea id="bst_count"></textarea>
</div>
</div>
</body>
</html>
//app.js
var gradesArr = [];
function getGrades(){
//随机获得一组成绩数据
var gradesNum = parseInt(document.getElementById("num_of_grades").value,10);
for(var i=0; i<gradesNum; i++)
{
gradesArr[i] = Math.floor(Math.random()*61+40);
}
//在网页上显示该组数据
var result = document.getElementById("bst_grades");
result.innerHTML = gradesArr;
}
function BSTcount(){
//将这组成绩数据插入到二叉查找树中
var grades = new BST();
for(var i=0; i<gradesArr.length; i++)
{
var currGrade = gradesArr[i];
var currNode = grades.find(currGrade);
if(currNode==null)
grades.insert(currGrade);
else
//如果遇到重复数据,则将该节点的count属性+1
currNode.update();
}
//输入待查找的成绩
var certainGradeNum = parseInt(document.getElementById("num_of_certain_grade").value,10);
//在网页上显示该得分的人数
var str="";
if(grades.find(certainGradeNum) == null)
str = "没有人得到"+certainGradeNum+"分。";
else
str = grades.find(certainGradeNum).count+"人得到"+certainGradeNum+"分。";
var result = document.getElementById("bst_count");
result.innerHTML = str;
}