目录
二叉树相关
定义
二叉树是一个连通的无环图,并且每一个顶点的度不大于3。有根二叉树还要满足根结点的度不大于2。有了根结点之后,每个顶点定义了唯一的父结点,和最多2个子结点。
基本概念
二叉树是递归定义的,其结点有左右子树之分,逻辑上二叉树有五种基本形态:
(1)空二叉树——如图(a);
(2)只有一个根结点的二叉树——如图(b);
(3)只有左子树——如图(c);
(4)只有右子树——如图(d);
(5)完全二叉树——如图(e)。
注意:尽管二叉树与树有许多相似之处,但二叉树不是树的特殊情形。[1]
类型
(1)完全二叉树——若设二叉树的高度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第h层有叶子结点,并且叶子结点都是从左到右依次排布,这就是完全二叉树。
(2)满二叉树——除了叶结点外每一个结点都有左右子叶且叶子结点都处在最底层的二叉树。
(3)平衡二叉树——平衡二叉树又被称为AVL树(区别于AVL算法),它是一棵二叉排序树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。[2]
相关术语
- 树的结点:包含一个数据元素及若干指向子树的分支;
- 孩子结点:结点的子树的根称为该结点的孩子;
- 双亲结点:B 结点是A 结点的孩子,则A结点是B 结点的双亲;
- 兄弟结点:同一双亲的孩子结点; 堂兄结点:同一层上结点;
- 祖先结点: 从根到该结点的所经分支上的所有结点子孙结点:以某结点为根的子树中任一结点都称为该结点的子孙
- 结点层:根结点的层定义为1;根的孩子为第二层结点,依此类推;
- 树的深度:树中最大的结点层
- 结点的度:结点子树的个数
- 树的度: 树中最大的结点度。
- 叶子结点:也叫终端结点,是度为 0 的结点;
- 分枝结点:度不为0的结点;
- 有序树:子树有序的树,如:家族树;
- 无序树:不考虑子树的顺序;[3]
二叉树性质
(1) 在非空二叉树中,第i层的结点总数不超过 , i>=1;
(2) 深度为h的二叉树最多有 个结点(h>=1),最少有h个结点;
(3) 对于任意一棵二叉树,如果其叶结点数为N0,而度数为2的结点总数为N2,则N0=N2+1;
(4) 具有n个结点的完全二叉树的深度为
(5)有N个结点的完全二叉树各结点如果用顺序方式存储,则结点之间有如下关系:
若I为结点编号则 如果I>1,则其父结点的编号为I/2;
如果2*I<=N,则其左儿子(即左子树的根结点)的编号为2*I;若2*I>N,则无左儿子;
如果2*I+1<=N,则其右儿子的结点编号为2*I+1;若2*I+1>N,则无右儿子。
(6)给定N个节点,能构成h(N)种不同的二叉树。
h(N)为卡特兰数的第N项。h(n)=C(2*n,n)/(n+1)。
(7)设有i个枝点,I为所有枝点的道路长度总和,J为叶的道路长度总和J=I+2i
遍历
先序遍历
首先访问根,再先序遍历左(右)子树,最后先序遍历右(左)子树。
中序遍历
首先中序遍历左(右)子树,再访问根,最后中序遍历右(左)子树。
后序遍历
首先后序遍历左(右)子树,再后序遍历右(左)子树,最后访问根。
js代码实现
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>二叉树</title>
<link rel="stylesheet" href="">
</head>
<body>
<script type="text/javascript">
function BinaryTree() {
var Node = function(key){
this.key = key;
this.left = null;
this.right = null;
}
var root = null;
var insertNode = function(node, newNode) {
if (newNode.key < node.key) {
if (node.left != null) {
insertNode(node.left, newNode);
} else {
node.left = newNode;
}
}
if (newNode.key > node.key) {
if (node.right != null) {
insertNode(node.right, newNode);
} else {
node.right = newNode;
}
}
}
this.insert = function(key) {
var newNode = new Node(key);
if (root === null) {
root = newNode;
} else {
insertNode(root, newNode);
}
}
var inOrderTraverseNode = function(node,callback){
if(node !==null){
inOrderTraverseNode(node.left,callback);
callback(node.key);
inOrderTraverseNode(node.right,callback);
}
}
this.inOrderTraverse = function(callback){
inOrderTraverseNode(root,callback);
}
var preOrderTraverseNode = function(node,callback){
if (node!==null) {
callback(node.key);
preOrderTraverseNode(node.left,callback);
preOrderTraverseNode(node.right,callback);
}
}
this.preOrderTraverse = function(callback){
preOrderTraverseNode(root,callback);
}
var postOrderTraverseNode = function(node,callback){
if (node!==null) {
postOrderTraverseNode(node.left,callback);
postOrderTraverseNode(node.right,callback);
callback(node.key);
}
}
this.postOrderTraverse = function(callback){
postOrderTraverseNode(root,callback);
}
var minNode = function(node){
if(node){
while(node && node.left!==null){
node = node.left;
}
return node.key;
}
}
this.min = function(){
return minNode(root);
}
var maxNode = function(node){
if(node){
while(node && node.right!==null){
node = node.right;
}
return node.key;
}
}
this.max = function(){
return maxNode(root);
}
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.search = function(key){
return searchNode(root,key);
}
var findMinNode = function(node){
if (node) {
while(node && node.left!==null){
node = node.left;
}
return node;
}
return null;
}
var removeNode = function(node,key){
if (node ===null) {
return null;
}
if(key>node.key){
node.right = removeNode(node.right,key);
return node;
}else if(key<node.key){
node.left = removeNode(node.left,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;
}
}
this.remove = function(key){
root = removeNode(root,key);
console.log(root);
}
}
var nodes = [8,3,10,1,6,14,4,7,13];
var binaryTree = new BinaryTree();
nodes.forEach(function(key){
binaryTree.insert(key);
});
var callback = function(key){
console.log(key);
}
//binaryTree.inOrderTraverse(callback);
//binaryTree.preOrderTraverse(callback);
//binaryTree.postOrderTraverse(callback);
//callback(binaryTree.min());
//callback(binaryTree.max());
//callback(binaryTree.search(7));
//callback(binaryTree.search(17));
binaryTree.remove(3);
//binaryTree.postOrderTraverse(callback);
</script>
</body>
</html>