燕返 2019-06-30
可能有一部分人没有读过我上一篇写的二叉堆,所以这里把二叉树的基本概念复制过来了,如果读过的人可以忽略前面针对二叉树基本概念的介绍,另外如果对链表数据结构不清楚的最好先看一下本人之前写的js数据结构-链表
二叉树(Binary Tree)是一种树形结构,它的特点是每个节点最多只有两个分支节点,一棵二叉树通常由根节点,分支节点,叶子节点组成。而每个分支节点也常常被称作为一棵子树。

常用术语
在二叉树中,我们常常还会用父节点和子节点来描述,比如图中2为6和3的父节点,反之6和3是2子节点
在二叉树的第i层上,至多有2^i-1个节点
深度为k的二叉树至多有2^k-1个节点
二叉树分为完全二叉树(complete binary tree)和满二叉树(full binary tree)

二叉搜索树满足以下的几个性质:
我们来举个例子来深入理解以下
一组数据:12,4,18,1,8,16,20
由下图可以看出,左边的图满足了二叉树的性质,它的每个左子节点都小于父节点,右子节点大于其父节点,同时左子树的节点都小于根节点,右子树的节点都大于根节点

二叉搜索树主要的几个操作:
通过下图,可以知道二叉搜索树的节点通常包含4个域,数据元素,分别指向其左,右节点的指针和一个指向父节点的指针所构成,一般把这种存储结构称为三叉链表。
用代码初始化一个二叉搜索树的结点:
class BinaryTreeNode {
constructor(key, value){
this.parent = null;
this.left = null;
this.right = null;
this.key = key;
this.value = value;
}
}接着我们再用代码去初始化一个二叉搜索树
class BinarySearchTree {
constructor() {
this.root = null;
}
}static createNode(key, value) {
return new BinarySearchTree(key, value);
}看下面这张图,13是我们要插入的节点,它插入的具体步骤:

通过上面的描述,我们来看看代码是怎么写的
insert(node){
let p = this.root;
let tail = this.root;
// 循环遍历,去找到对应的位置
while(tail) {
p = tail;
// 要插入的节点key比当前节点小
if (node.key < tail.key){
tail = tail.left;
}
// 要插入的节点key比当前节点大
else {
tail = tail.right;
}
}
// 没有根节点,则直接作为根节点插入
if(!p) {
this.root = node;
return;
}
// p是最后一个节点,也就是我们要插入的位置的父节点
// 比父节点大则往右边插入
if(p.key < node.key){
p.right = node;
}
// 比父节点小则往左边插入
else {
p.left = node;
}
// 指向父节点
node.parent = p;
}查找就很简单了,其实和插入差多,都是去别叫左右节点的大小,然后往下找
search(key) {
let p = this.root;
if(!p) {
return;
}
while(p && p.key !== key){
if(p.key<key){
p = p.right;
}else{
p = p.left;
}
}
return p;
}最常用的一般是中序遍历,因为中序遍历可以得到一个已经排好序的列表,这也是为什么会用二叉搜索树排序的原因
根据上面对中序遍历的解释,那么代码就变的很简单,就是一个递归的过程,递归停止的条件就是节点为null
transverse() {
return this._transverse(this.root);
}
*_transverse(node){
if(!node){
return;
}
yield* this._transverse(node.left);
yield node;
yield* this._transverse(node.right)
}
看上面这张图,我们简化的来看一下,先访问左节点4,再自己12,然后右节点18,这样输出的就刚好是一个4,12,18
补充:这个地方用了generater,所以返回的一个迭代器。可以通过下面这种方式得到一个有序的数组,这里的前提就当是已经有插入的节点了
const tree = new BinaryTree();
//...中间省略插入过程
// 这样就返回了一个有序的数组
var arr = [...tree.transverse()].map(item=>item.key);class BinaryTreeNode {
constructor(key, value) {
// 指向父节点
this.p = null;
// 左节点
this.left = null;
// 右节点
this.right = null;
// 键
this.key = key;
// 值
this.value = value;
}
}
class BinaryTree {
constructor() {
this.root = null;
}
static createNode(key, value) {
return new BinaryTreeNode(key, value);
}
search(key) {
let p = this.root;
if (!p) {
return;
}
while (p && p.key !== key) {
if (p.key < key) {
p = p.right;
} else {
p = p.left;
}
}
return p;
}
insert(node) {
// 尾指针的父节点指针
let p = this.root;
// 尾指针
let tail = this.root;
while (tail) {
p = tail;
if (node.key < tail.key) {
tail = tail.left;
} else {
tail = tail.right;
}
}
if (!p) {
this.root = node;
return;
}
// 插入
if (p.key < node.key) {
p.right = node;
} else {
p.left = node;
}
node.p = p;
}
transverse() {
return this.__transverse(this.root);
}
*__transverse(node) {
if (!node) {
return;
}
yield* this.__transverse(node.left);
yield node;
yield* this.__transverse(node.right);
}
}二叉查找树就讲完了哈,其实这个和链表很像的,还是操作那么几个指针,既然叫查找树了,它主要还是用来左一些搜索,还有就是排序了,另外补充一下,二叉查找树里找最大值和最小值也很方便是不是,如果你大致读懂了的话。
这篇文章我写的感觉有点乱诶,因为总感觉哪里介绍的不到位,让一些基础差的人会看不懂,如果有不懂或者文章哪里写错了,欢迎评论留言哈
后续写什么呢,这个问题我也在想,排序算法,react第三方的一些模拟实现?,做个小程序组件库?还是别的,容我再想几个小时,因为可以,有建议的朋友们也可以留言说一下哈。
最后最后,最重要的请给个赞,请粉一个呢,谢谢啦