树是一种非线性的数据结构,以分层的方式存储数据,特别是有序列表。树可以分为几个层次,根节点是第0层。没有任何子节点的节点称为叶子节点。
二叉树是一种特殊的树,二叉树进行查找、添加、删除都非常快。二叉树每个节点的子节点不允许超过两个。相对较小的值保存在左节点中,较大的值保存在右节点中。
- Node对象既保存数据,也保存和其他节点的连接。
- BST对象的构造函数将根节点初始化为null,以此创建一空节点。
- 插入节点的时候先判断根节点是否为null,不为null的时候通过遍历,用一个变量存储当前节点,一层层遍历BST,比较数值,直到查找到正确插入点。因为要把插入点和父节点连接起来,所以要有一个指向“父节点”一个指向“当前节点”。然后通过遍历一步步移动。
- 中序遍历是通过递归,先访问子左树,再访问根节点,最后访问右子树
//节点类
function Node(dara,left,right) {
this.data = data;
this.left = left;
this.right = right;
this.show = show;
}
function show() {
return this.data;
}
//树
function BST() {
this.root = null;
this.insert = insert;
this.inOrder = inOrder;
}
function insert(data) {
var n = new Node(data,null,null);
if(this.root == null) {
this.root = n;
}else {
var current = this.root;
var parent;
while(true) {
parent = current;
if(data < current.data) {
current = current.left;
if(current == null) {
parent.left = n;
break;
}
}else {
current = current.right;
if(current == null) {
parent.right = n;
break;
}
}
}
}
}
//中序遍历
function inOrder(node) {
if(node !== null) {
inOrder(node.left);
console.log(node.show() + " ");
inOrder(node.right);
}
}
BST通常有三种类型的查找
- 查找最小值
-因为较小值总在左子节点,所以只需要遍历左子树,直到找到最后一个节点。 - 查找最大值
-同理,因为较大值总在右子节点,所以只需要遍历右子树。 - 查找给定值
-需要比较该值和当前节点上的值大小,确定该左遍历还是右遍历
//找最小值
function getMin() {
var current = this.root;
while(current.left !== null) {
current = current.left;
}
return current.data;
}
//找最大值
function getMax() {
var current = this.root;
while(current.right !== null) {
current = current.right;
}
return this.current.data;
}
//查找给定值
function find(data) {
var current = this.root;
while(current.data !== null) {
if(data == current.data) {
return current;
}else if(data < current.data) {
current = current.left;
}else {
current = current.right;
}
}
return null;
}
从二叉树删除节点的最复杂的,也是分三种情况
- 是叶子节点
-只需要将从父节点指向他的链接指向null。 - 只包含一个子节点
-如果只有一个子节点,使父节点的链接指向它的子节点。 - 包含两个子节点
-要么查找待删除节点子左子树上的最大值,要么查找其右子树上的最小值。创建一个临时节点,将临时节点上的值复制到待删除节点,再删除临时节点。
//接受待删除数据,调用removeNode()删除它
function remove(data) {
root = this.removeNode(this.root,data);
}
function removeNode(node,data) {
if(node == null) {
return null;
}
if(data == node.data) {
if(node.left == null && node.right == null) {
return null;
}else if(node.left == null) {
return node.right;
}else if(node.right == null) {
return node.left;
}else {
var tempNode = this.getSmallest(node.right); //创建一个临时节点,等于右子数上的最小值
node.data = tempNode.data;
node.right = this.removeNode(node.right,data); //删除右子数上的最小值的节点
return node;
}
}else if(data < node.data){
node.left = this.removeNode(node.left,data);
return node;
}else {
node.right = this.removeNode(node.right,data);
return node;
}
}
function getSmallest(node) {
var current = node;
while(current.left !== null) {
current = current.left;
}
return current;
}
BST的一个用途是记录一组数据集中数据出现的次数。
- 修改Node对象,增加一个记录成绩出现频次的成员。并且插入数据的时候判断一下。
function Node(data,left,right) {
this.data = data;
this.left = left;
this.right = right;
this.count = 1;
}
//插入数据时如果已经存在就使用updata()
function updata(data) {
var grade = this.find(data);
grade.count++;
return grade;
}
var g = "123";
var bst = new BST();
var aGrade = bst.find(g);
if(aGrade == null) {
bst.insert(g);
}else {
bst.updata(g);
}
其实。。。我想了下,感觉那些方法好像可以加到BST的原型上,这样就不会每创建一个BST对象就创建一堆方法,构造函数就不用写一堆this.方法 = 方法。而且这样写把方法定义到全局变量中,使得其他对象也能调用。这样写的方式还是为了附和Java这类语言的吧~