二叉树的基本术语
- 结点之间的关系
- 若一个结点有子树,那么该结点称为子树根的双亲,子树的根称为该结点的孩子
- 有相同双亲的结点互为兄弟
- 一个结点的所有子树上的任何结点都是该结点的后裔
- 从根结点到某个结点的路径上的所有结点都是该结点的祖先
- 结点层:根结点的层定义为第一层,根的孩子为第二层,依此类推
- 树的深度:树中最大的结点层
- 结点的度:结点拥有的子树的个数
- 树的度: 树中最大的结点度
- 叶子结点:也叫终端结点,是度为 0 的结点
- 分枝结点:度不为0的结点
二叉查找树
二叉查找树是一种 特殊的二叉树,相对较小的值保存在左节点中,较大的值保存在右节点中。这一特性使得 查找的效率很高,对于数值型和非数值型的数据,比如单词和字符串,都是如此。
实现二叉查找树
二叉查找树由节点组成,所以我们要定义的第一个对象就是 Node,该对象和前面介绍链表
时的对象类似。
function Node(data, left, right) {
this.data = data
this.left = left
this.right = right
this.show = show
}
function show() {
return this.data;
}
Node 对象既保存数据,也保存和其他节点的链接(left 和 right),show() 方法用来显示 保存在节点中的数据。
function BST() {
this.root = null; // 根节点
this.insert = insert; // 插入节点
this.preOrder = preOrder; // 先序遍历
this.inOrder = inOrder; // 中序遍历
this.postOrder = postOrder; // 后序遍历
this.find = find; // 查找节点
this.getMin = getMin; // 查找最小值
this.getMax = getMax; // 查找最大值
}
//insert:向树中添加新节点
function insert(data) {
var n = new Node(data, null, null)
if (this.root === null) {
this.root = n
} else {
var curNode = this.root
while (true) {
if (data < curNode.data) {
if (curNode.left === null) {
curNode.left = n
break
}
curNode = curNode.left
}
else {
if (curNode.right === null) {
curNode.right = n
break
}
curNode = curNode.right
}
}
}
}
var nums = new BST();
//插入数据
nums.insert(23);
nums.insert(45);
nums.insert(16);
nums.insert(37);
nums.insert(3);
nums.insert(99);
nums.insert(22);
nums.insert(45);
nums.insert(-1);
/* console.log('Node: /n ');
console.log(nums.root)
console.log('\n 前序 /n ');
preOrder(nums.root);
console.log('\n 中序 /n ');
inOrder(nums.root)
console.log('\n 后序 /n ');
postOrder(nums.root) */
/* 二叉树查找 */
//查找最小值
function getMin() {
var current = this.root
while (current.left !== null) {
current = current.left
}
return current.show()
}
//查找最大值
function getMax() {
var current = this.root
while (current.right !== null) {
current = current.right
}
return current.show()
}
/* console.log('min:',nums.getMin())
console.log('max:',nums.getMax())
*/
/* find */
function find(data) {
var current = this.root
while (current !== null && current.data !== data) {
if (data < current.data) {
current = current.left
} else {
current = current.right
}
}
if (current === null) return null
return current
}
console.log('find result:', nums.find(45));
遍历二叉树
有三种遍历 BST 的方式:中序、先序和后序。中序遍历按照节点上的键值,以升序访问 BST 上的所有节点。先序遍历先访问根节点,然后以同样方式访问左子树和右子树。后序 遍历先访问叶子节点,从左子树到右子树,再到根节点。
先序遍历
根结点 -> 左子树 -> 右子树
//递归方式
function preOrder(node) {
if (!node) {
console.log(node.show() + ' ')
preOrder(node.left)
preOrder(node.right)
}
}
//非递归方式
function preOrder(root)
{
var stack = [];
var node = root;
while(node || stack.length != 0){
//循环访问节点的左子结点并入栈
while(node){
console.log(node.val);
stack.push(node);
node = node.left;
}
if(stack.length != 0){
node = stack.pop();
node = node.right();
}
}
}
中序遍历
左子树 -> 根结点 -> 右子树
//当node不为空,一直沿着左先遍历
//递归
function inOrder(node) {
if (!(node == null)) {
inOrder(node.left)
console.log(node.show() + ' ')
inOrder(node.right)
}
}
//非递归
function inOrder(root)
{
var stack = [];
var node = root;
while(node || stack.length != 0){
while(node){
stack.push(node);
node = node.left;
}
if(stack.length != 0){
node = stack.pop();
console.log(node.val);
node = node.right();
}
}
}
后序遍历
左子树 -> 右子树 -> 根结点
//递归
function postOrder(node) {
if (!(node == null)) {
postOrder(node.left)
postOrder(node.right)
console.log(node.show() + ' ')
}
}
//非递归
function postOrder(root)
{
var stack = [];
var node = root;
var lastVisit = null; //标记每次遍历最后一次访问的结点
while(node || stack.length != 0){
while(node){
stack.push(node);
node = node.left;
}
if(stack.length != 0){
node = stack.pop();
//判断节点是否有右子结点,同时判断lastVisit避免重复输出右子结点)
if(node.right == null || node.right == lastVisit){
//如果没有则输出
console.log(node.val);
lastVisit = node;
node = null;
}
else{
//如果有则再次入栈,并访问节点的右子节点
stack.push(node);
node = node.right();
}
}
}
}
层序遍历
层序遍历用队列实现
function levelOrder(root)
{
var queue = [], res = [];
queue.push(root);
while(queue.length != 0){
let len = queue.length; //一层结点个数
let temp = [];
for(let i = 0; i < len; i++){
var node = queue.shift();
temp.push(node.val);
if(node.left)
queue.push(node.left);
if(node.right)
queue.push(node.right);
}
res.push(temp);
}
return res;
}