这是我参与8月更文挑战的第8天,活动详情查看:8月更文挑战node
(n >= 0)
个节点构成的有限集合(n > 0)
,具有如下性质:
(m > 0)
个互不相交的有限集T一、T二、...、Tm
,其中每一个集合自己又是一棵树,称为原来树的**"子树"**树的性质是不少的...数组
一个二叉树第i层的最大节点数为:2^(i-1), i>=1
markdown
好比第一层(根节点)为1个;第二层最多为2节点函数
深度为k的二叉树有最大节点总数为:2^k-1, k>=1
post
对任何非空二叉树T,若n0
表示叶节点(度为0)的个数,n2
表示度为2的非叶节点个数,那么二者知足关系n0 = n2 + 1
ui
除二叉树最后一层外,其余各层的节点数都达到最大个数this
且最后一层从左向右达到叶节点连续存在,只缺右侧若干节点spa
下面的图从左到右看,E有右子节点可是D没有,因此不是彻底二叉树。若是给D加一个右子节点,那么它就是彻底二叉树prototype
二叉树的存储方式能够是数组也能够是链表,可是咱们通常用链表。由于使用数组的是否若是该二叉树不是满二叉树,会形成不少空间的浪费。指针
首先,二叉搜索树有一个根节点,初始化让这个根节点指向空;this.root = null;
其次,二叉搜索树的每个节点包含3个元素,左子节点、右子节点和键值;初始状态下指针指向空
function Node() {
this.key = key;
this.left = null;
this.right = null;
}
复制代码
insert(key):
向树中插入一个新的键search(key):
在树中查找一个键,若是节点存在,则返回true;若是不存在,返回falseinOrderTraverse:
经过中序遍历方式遍历全部节点preOrderTraverse:
经过先序遍历方式遍历全部节点postOrderTraverse:
经过后序遍历方式遍历全部节点min:
返回树中的最小的值/键max:
返回树中的最大的值/键remove(key):
从树中移除某个键insert
方法根据key建立节点
判断根节点是否有值;若是根节点为null时直接插入,不然进行下一步操做
BinarySearchTree.prototype.insert = function (key) {
var newNode = new Node(key);
if (this.root == null) {
this.root = newNode;
} else {
this.insertNode(this.root, newNode);
}
}
复制代码
在搜索树进行插入操做的时候,若是插入的值大于根节点,那么就要把该节点插到根节点的右子节点;若是此时根节点已经有右子节点了,那就应该继续让这个要插入的节点的值和该右子节点进行比较插入;这个过程其实就是在套娃,一直到这个左或者右节点为空的时候就中止,因此这里用递归来实现,用另外一个函数来进行对节点的插入。
BinarySearchTree.prototype.insertNode = function (node, newNode) {
if (newNode.key < node.key) {
if (node.left == null) {
node.left = newNode;
} else {
this.insertNode(node.left, newNode);
}
} else {
if (node.right == null) {
node.right = newNode;
} else {
this.insertNode(node.right, newNode);
}
}
}
复制代码
因为树的结构是比较特殊的,在遍历节点的时候咱们每每都是采用递归的方法来实现。
BinarySearchTree.prototype.preOrderTraversalNode = function (node, handler) {
if (node != null) {
handler(node.key);
this.preOrderTraversalNode(node.left, handler);
// 3. 处理通过节点的右子节点
this.preOrderTraversalNode(node.right, handler);
}
}
//--------
var resultString = ''
tree.preOrderTraversal(function (key) {
resultString += key + ' ';
})
复制代码
这里的handler是一个处理结点的回调函数,便于咱们看遍历的结果;在先序遍历中,咱们要先遍历全部的左子节点,再处理通过节点的右子节点;好比下面这张图:
这里用的递归思路仍是有一点复杂的,是一个个函数的嵌套,遍历结束以后一个个跳出来的,须要花一点时间来理解。
遍历7的左节点到5的时候,先遍历3,3是叶节点,继续遍历6(此时的node是5),遍历完5的左右节点以后,就继续遍历7的右子节点。
if (node != null) {
this.inOrderTraversalNode(node.left, handler);
handler(node.key);
this.inOrderTraversalNode(node.right, handler);
}
复制代码
if (node != null) {
this.inOrderTraversalNode(node.left, handler);
this.inOrderTraversalNode(node.right, handler);
handler(node.key);
}
复制代码
理解了先序遍历以后,中序遍历和后序遍历都是用递归的方式实现,不一样之处在于什么时候来处理节点。
最大值和最小值在数中是很容易找的。最左边的子节点(左下)就是最小值;最右边的子节点(右下)就是最大值。这里演示查找最大值。
BinarySearchTree.prototype.max = function () {
var node = this.root;
var key = null;
while (node != null) {
key = node.key
node = node.right
}
return node.key
}
复制代码
在查找的时候,一直都找右节点,直到这个右节点的值为空的时候返回这个节点的键值。
这个方法能够经过递归的方法实现,也能够经过循环来进行搜索
递归;将查找值和当前节点的值进行对比,若是较小就往左子树找,若是较大就往右子树上查找,直到node.key == key
时,返回true,若是通过这些步骤以后仍是找不到的话就返回false。
BinarySearchTree.prototype.searchNode = function (node, key) {
if (node == null) {
return false;
}
if (node.key > key) {
return this.searchNode(node.left, key);
} else if (node.key < key) {
return this.searchNode(node.right, key);
} else {
return true;
}
return false;
}
复制代码
循环 先获取根节点,再循环搜索key
循环的话会比较好理解一点,就是键值比较,决定往左子树仍是右子树遍历,直到找到目标值。
var node = this.root;
while (node != null) {
if (node.key > key) {
node = node.left;
} else if (node.key < key) {
node = node.right;
} else {
return true;
}
}
return false;
复制代码
删除操做是最复杂的,那就放在下一篇文章吧!今天学不下去了aaa...codewhy老师真的讲的好棒!