概念

  • 有一个根节点
  • 每一个节点有左右子节点
  • n层二叉树最多2^n-1个节点(满二叉树)
  • 完全二叉树前n-1层位满二叉树,最后一层左节点必须先于右节点存在
  • 完全二叉树节点数量2^(n-1)~2^n-1

节点类型

1
2
3
4
function TreeNode(val) {
this.val = val;
this.left = this.right = null;
}

前序遍历

根节点->左子树->右子树
image_1bdrc0di41ojo16no1qqb3aack89.png-4.4kB
前序遍历:abdefgc
中序遍历:debgfac
后序遍历:edgfbca

递归实现

递归实现最简单,时间复杂度与空间复杂度为O(n).

1
2
3
4
5
6
7
8
9
10
11
12
13
function preorderTraversal(root) {
var array=[];
if(!root) return array;
preorder(root, array);
return array;
}

function preorder(root, array) {
if(!root) return;
array.push(root.val);
preorder(root.left, array);
preorder(root.right,array);
}

迭代实现

用栈来存储未遍历的右节点

1
2
3
4
5
6
7
8
9
10
11
12
13
function preorder(root) {
var array=[],stackNodes=[];
while(root || stackNodes.length) {
if(root) {
array.push(root.val);
if(root.right) stackNodes.push(root.right);
root=root.left;
} else {
root=stackNodes.pop();
}
}
return array;
}

Morris遍历

Morris遍历类似利用线索二叉树,空域查找存储前驱节点来扫描,时间复杂度O(n),空间复杂度O(1)。


中序遍历

递归实现

递归实现最简单,时间复杂度与空间复杂度为O(n).

1
2
3
4
5
6
7
8
9
10
11
12
13
function inorderTraversal(root) {
var array=[];
if(!root) return array;
preorder(root, array);
return array;
}

function inorder(root, array) {
if(!root) return;
inorder(root.left, array);
array.push(root.val);
inorder(root.right,array);
}

迭代实现

用栈来存储已遍历但不能输出的根节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function preorder(root) {
var array=[],stackNodes=[];
while(root || stackNodes.length) {
if(root) {
stackNodes.push(root);
root=root.left;
} else {
var topNode=stackNodes.pop();
array.push(topNode.val);
root=topNode.right;
}
}
return array;
}

Morris遍历


后序遍历

递归实现

递归实现最简单,时间复杂度与空间复杂度为O(n).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function preorderTraversal(root) {
var array=[];
if(!root) return array;
preorder(root, array);
return array;
}

function preorder(root, array) {
if(!root) return;

preorder(root.left, array);
preorder(root.right,array);
array.push(root.val);
}

迭代实现

用栈来存储未遍历的右节点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function preorder(root) {
var array=[],stackNodes=[].,lastNode=null;
while(root || !array.length) {
if(root) {
stackNodes.push(root);
root=root.left;
} else {
var topNode = stackNodes[stackNodes.length-1];
if(!topNode.right && topNode.right!=lastNode) {
root=topNode.right;
} else {
stackNodes.pop();
array.push(topNode.val);
lastNode=topNode;
}
}
}
return array;
}

### Morris遍历

层次遍历

即每一层从左向右输出,元素需要储存有先进先出的特性,所以选用队列存储。

1
2
3
4
5
6
7
8
9
10
11
12
13
function levelTraverse(root) {
var array=[];
if(!root) return array;
var queue=[];
queue.push(root);
while(!queue.length) {
var tmpNode = queue.shift();
array.push(tmpNode.val);
if(tmpNode.left) queue.push(tmpNode.left);
if(tmpNode.right) queue.push(tmpNode.right);
}
return array;
}

层次遍历构建二叉树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//[123#56#] '#'means empty node
function levelCreateBinaryTree(arr) {
if(!arr.length) return null;
//use queue to store the uncreated node
var queue=[];
var root=new TreeNode(arr.shift());
queue.push(root);
var p;
while(queue.length) {
var leftValue=arr.shift();
var rightValue=arr.shift();
p = queue.shift();
if(leftValue && rightValue && leftValue != '#' && rightValue !='#') {
p.left=new TreeNode(leftValue);
p.right=new TreeNode(rightValue);
queue.push(p.left);
queue.push(p.right);
} else if((leftValue===undefined || leftValue=='#') && rightValue && rightValue!='#'){
p.right=new TreeNode(rightValue);
queue.push(p.right);
} else if(leftValue && leftValue!='#' && (rightValue=='#' || rightValue===undefined)){
p.left=new TreeNode(leftValue);
queue.push(p.left);
}
}
return root;
}

二叉树打印

1
2
3
4
5
6
7
8
9
function printBinaryTree(root, prefix, isTail) {
console.log(prefix,isTail?"└──":"├──",root.val);
if(root.left && root.right) {
printBinaryTree(root.left,prefix+(isTail?" ":" | "),false);
printBinaryTree(root.right,prefix+(isTail?" ":" | "),true);
} else if(root.left) {
printBinaryTree(root.left,prefix+(isTail?" ":" | "),true);
}
}

二叉树查找

归根究底也是一种遍历

1
2
3
4
5
6
function searchBinaryTree(root,val) {
if(!root) return null;
if(root.val==val) return root;
return searchBinaryTree(root.left,val)?searchBinaryTree(root.left,val):searchBinaryTree(root.right,val);

}

二叉树节点数量统计

1
2
3
4
5
function countBinaryTree(root,val) {
if(!root) return 0;
return countBinaryTree(root.left)+countBinaryTree(root.right)+1;

}

二叉树比较

1
2
3
4
5
6
7
8
9
function isEqual(root1,root2) {
if(!root1 && !root2) return true;
if(root1 && root2 && root1.val==root2.val) {
if(isEqual(root1.left, root2.left) && isEqual(root1.right,root2.right)) {
return true;
}
}
return false;
}

二叉树深度

1
2
3
4
5
6
7
8
function depthOfTree(root) {
if(!root) return 0;
var depth,leftH,rightH;
leftH = depthOfTree(root.left);
rightH = depthOfTree(root.right);
depth = Math.max(leftH,rightH)+1;
return depth;
}

二叉查找树

Binary Search Tree(BST) 对于每个节点,其值大于或等于左孩子,小于等于右孩子。其中序遍历是有序的。BST的查找操作平均复杂度O(lgn),最坏情况O(n),故引申出一些平衡搜索树结构:红黑树、AVL、B树等。