二叉树
该图片来自于维基百科
在计算机科学中,二叉树(英语:Binary tree)是每个节点最多只有两个分支(即不存在分支度大于2的节点)的树结构。通常分支被称作“左子树”或“右子树”。二叉树的分支具有左右次序,不能随意颠倒。
以上是维基百科关于 二叉树
的定义,即:
- 二叉树是
树形结构
的一种 - 它限制了每个节点最多只有
两个分支
左或右 - 思想类似于
二分查找
但是二叉树是一种链式结构
排序二叉树
该图片来自于维基百科
二叉查找树(英语:Binary Search Tree),也称为二叉搜索树、
有序二叉树(ordered binary tree)或排序二叉树(sorted binary tree),
是指一棵空树或者具有下列性质的二叉树:
1. 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
2. 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
3. 任意节点的左、右子树也分别为二叉查找树;
4. 没有键值相等的节点。
以上是维基百科关于 排序二叉树
的定义,其实说白了就一句话,即:
- 排序二叉树的左节点一定小于右节点
- 上条规则同样适用于子树
实现一个排序二叉树
class BinarySearchTree{
constructor() {
this.root = null // 初始化根节点root
}
createNode(val) { // 创建新节点
let left = null; // 左节点
let right = null // 右节点
return {
val,
left,
right
}
}
// 插入操作
insert(val) {
let new_node = this.createNode(val); // 创建一个新节点
if (!this.root) {
// 如果当前二叉树的根节点为null 说明是个空树 直接插入
this.root = new_node;
} else {
// 不是空树 继续判断需要插入到左边还是右边
this.insertNode(this.root, new_node);
}
}
insertNode(node, new_node) {
if (node.val > new_node.val) {
// 比父节点小 需插入左边
if (!node.left) {
node.left = new_node;
} else {
// 递归操作 直到node.left 为null的时候插入节点node即可
this.insertNode(node.left, new_node);
}
} else {
// 比父节点大 需插入右边
if (!node.right) {
node.right = new_node;
} else {
// 类比同上
this.insertNode(node.right, new_node);
}
}
}
}
ok 至此,便简单的实现了一个排序二叉树。类似于数组或者链表的方法一样,有了树之后就是要对它进行操作
遍历
- 遍历的本质是访问树中的
每个节点
-
由于二叉排序树的特殊性 根据访问根节点的
先后顺序
不同 遍历顺序可分为- 先序遍历: 先访问
根节点
再访问左节点
最后右节点
- 中序遍历: 先访问
左节点
再访问根节点
最后右节点
- 后序遍历: 先访问
左节点
再访问右节点
最后根节点
- 先序遍历: 先访问
- 通过
递归
实现遍历 通过回塑
来控制节点的顺序
此处需要注意的是 顺序是根据访问 根节点
的先后顺序。先访问根
就是先序
, 后访问根
就是后序
class BinarySearchTree{
constructor() {
this.root = null // 初始化根节点root
}
// 省略以上代码...
// 先序遍历
preOrderTraverse(cb){ // cb 是回调函数 callback
this.preOrderTraverseNode(this.root, cb)
}
preOrderTraverseNode(node, cb){
if(node){ // 如果节点不为null 就继续遍历
// 1. 先访问根节点 直接获取到根节点this.root
cb(node.val);
// 2. 再访问左节点
this.preOrderTraverseNode(node.left, cb)
// 3. 最后访问右节点
this.preOrderTraverseNode(node.right, cb)
}
}
// 中序遍历 理解同上
inOrderTraverse(cb) {
this.inOrderTraverseNode(this.root, cb);
}
inOrderTraverseNode(node, cb) {
if (node !== null) {
this.inOrderTraverseNode(node.left, cb);
cb(node);
this.inOrderTraverseNode(node.right.cb);
}
}
// 后序遍历 理解同上
postOrderTraverse(cb) {
this.postOrderTraverseNode(this.root, cb);
}
postOrderTraverseNode(node, cb) {
if (node !== null) {
this.postOrderTraverseNode(node.left);
this.postOrderTraverseNode(node.right);
cb(node);
}
}
}
获取最大值
排序二叉树获取最大或最小值特别方便, 因为本身排序二叉树就是一个排好序的树。
排序二叉树的右子树一定大于左字树,所以只需直到最右边的子树即可满足条件。
class BinarySearchTree{
constructor() {
this.root = null // 初始化根节点root
}
// 省略以上代码...
findMax(){
let p = this.root
if(p){
// while循环终止条件: p为null 或者 p没有了right节点
while(p && p.right){
p = p.right
}
}
return p // 此时的p就是排序二叉树最大节点
}
}
查找某个值是否存在
基于上述的排序二叉树的特点,查找某个值是否在该排序二叉树上也变得十分简单
class BinarySearchTree{
constructor() {
this.root = null // 初始化根节点root
}
// 省略以上代码...
search(val){
let p = this.root
// 拿到根节点和val一并传入searchNode方法
this.searchNode(p, val)
}
searchNode(node, val){
if(!node){
return false
}
if(node.val > val){
// 该值比节点值小 去左子树去接着递归查找
this.searchNode(node.left, val)
}else if(node.val < val){
// 该值比节点值大 去右子树去接着递归查找
this.searchNode(node.left, val)
}else{
// 该值 等于 节点值 找到了
return true
}
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。