1、树的定义
首先给出树的相关定义:树(tree)是包含n(n>0)个结点的有穷集,其中:
1)每个元素称为结点(node);
2)有一个特定的结点被称为根结点或树根(root);
3)除根结点之外的其余数据元素被分为m(m≥0)个互不相交的集合T1,T2,……Tm-1,其中每一个集合Ti(1<=i<=m)本身也是一棵树,被称作原树的子树。
树也可以这样定义:树是由根结点和若干颗子树构成的。树是由一个集合以及在该集合上定义的一种关系构成的。集合中的元素称为树的结点,所定义的关系称为父子关系。父子关系在树的结点之间建立了一个层次结构。在这种层次结构中有一个结点具有特殊的地位,这个结点称为该树的根结点,或称为树根。
2、树的相关术语
节点的度:一个节点含有的子树的个数称为该节点的度;
叶节点或终端节点:度为0的节点称为叶节点;
非终端节点或分支节点:度不为0的节点;
双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点;
孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点;
兄弟节点:具有相同父节点的节点互称为兄弟节点;
树的度:一棵树中,最大的节点的度称为树的度;
节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;
树的高度或深度:树中节点的最大层次;
堂兄弟节点:双亲在同一层的节点互为堂兄弟;
节点的祖先:从根到该节点所经分支上的所有节点;
子孙:以某节点为根的子树中任一节点都称为该节点的子孙。
森林:由m(m>=0)棵互不相交的树的集合称为森林;
下面给出常见的树的概念,大部分内容可参考严蔚敏版《数据结构》:
3、二叉树
二叉树是数据结构中一种重要的数据结构,也是树表家族最为基础的结构。
二叉树的定义:二叉树的每个结点至多只有二棵子树(不存在度大于2的结点),二叉树的子树有左右之分,次序不能颠倒。二叉树的第i层至多有2i-1个结点;深度为k的二叉树至多有2k-1个结点;对任何一棵二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0=n2+1。
4、满二叉树
一棵深度为k且有2k-1(2的k次幂减1)个结点的二叉树称为满二叉树。
5、完全二叉树
深度为k的,有n个结点的二叉树,当且仅当其每一个结点都与深度为k的满二叉树中编号从1至n的结点一一对应时,称之为完全二叉树。
6、二叉排序树
二叉查找树定义:又称为是二叉排序树(Binary Sort Tree)或二叉搜索树。二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:
1) 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
2) 若它的右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;
3) 它的左、右子树也分别为二叉排序树。
7、平衡二叉树
平衡二叉树(Balanced Binary Tree)又被称为AVL树。它或者是一棵空树,或者是具有下列性质的二叉树:它的左子树和右子树都是平衡二叉树,且左子树和右子树的深度之差的绝对值不超过1。(注:平衡二叉树应该是一棵二叉排序树)
二叉排序树的实现
function BinarySearchTree() {
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);
}
};
var 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);
}
}
};
// 中序遍历
this.inOrderTraverse = function(callback) {
inOrderTraverseNode(root, callback);
};
var inOrderTraverseNode = function(node, callback) {
if (node != null) {
inOrderTraverseNode(node.left, callback);
callback(node.key);
inOrderTraverseNode(node.right, callback);
}
};
// 先序遍历
this.preOrderTraverse = function(callback) {
preOrderTraverseNode(node, callback);
};
var preOrderTraverseNode = function(node, callback) {
if (node != null) {
callback(node.key);
preOrderTraverseNode(node.left, callback);
preOrderTraverseNode(node.right, callback);
}
};
// 后序遍历
this.postOrderTraverse = function(callback) {
postOrderTraverseNode(root, callback);
};
var postOrderTraverseNode = function(node, callback) {
if (node != null) {
postOrderTraverseNode(node.left, callback);
postOrderTraverseNode(node.right, callback);
callback(node.value);
}
};
function printNode(value) {
console.log(value);
}
this.min = function(node) {
return minNode(root);
};
var minNode = function(node) {
if(node) {
while(node && node.left !== null) {
node = node.left;
}
return node.key;
}
return null;
};
this.max = function() {
return maxNode(root);
};
var 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);
};
var removeNode = function(node, key){
if(node === null) {
return false;
}
if(key < node.key) {
node.left = removeNode(node, key);
return node;
} else if(key > node.key) {
node.right = removeNode(node, key);
return node;
} else {
// 第一种情况叶节点
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;
}
};
var findMinNode = function(node) {
while(node && node.left !== null){
node = node.left;
}
return node;
}
}