ES6 实现二叉排序树

5 篇文章 1 订阅

ES6 实现二叉排序树

定义节点类

class Node { //定义节点类
    constructor(value) {
        this.value = value;
    }
    addParents(node) { //添加父节点
        this.parents = node
    }
    addChildLeft(node) { //添加左子节点
        this.childLeft = node;
    }
    addChildRight(node) { //添加右子节点
        this.childRight = node
    }
}

定义二叉树类

class Tree { //定义二叉树类
    constructor(arr) {
        this.nodeArr = this.createNode(arr); //生成Node节点数组
        this.preArr = [];//先序遍历数组
        this.MinArr = [];//中序遍历数组
        this.postArr = [];//后序遍历数组
        this.root = this.nodeArr[0]; //二叉排序树根节点
    }
}

二叉排序树特性

二叉排序树又称“二叉查找树”、“二叉搜索树”。

二叉排序树:或者是一棵空树,或者是具有下列性质的二叉树:

  1. 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;

  2. 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;

  3. 它的左、右子树也分别为二叉排序树。

  4. 在二叉排序树中能快速找到某个节点,期望O(logn),最坏O(n)。

生成二叉排序树

接收一组数据,默认第一个数据为根节点,然后遍历这组数据;
1.插入节点小于当前节点,插入到当前节点左边,若当前节点左节点为空将插入节点连接到当前节点的左节点,否则递归当前节点的左节点
2.插入节点大于当前节点,插入到当前节点右边,若当前节点右节点为空将插入节点连接到当前节点的右节点,否则递归当前节点的右节点

算法实现


	createNode(arr) { //生成Node节点数组
    let nodeArr = [];
    for (let i = 0; i < arr.length; i++) { //遍历传入数据
        let element = new Node(arr[i]); //生成node节点 
        nodeArr.push(element); //将节点放入节点数组
    }
    return nodeArr; //返回节点数组
}
	createTree() { //开始构建二叉排序树
        //let arr = [18,  16, 5, 12,11]
        for (let i = 1; i < this.nodeArr.length; i++) { //遍历节点数组
            if (this.nodeArr[i].value < this.nodeArr[0].value) { //如果节点小于根节点,将数据插入到左边
                this.createTreeLeft(this.nodeArr[0], this.nodeArr[i])
            } else { //如果节点小于根节点,将数据插入到右边
                this.createTreeRight(this.nodeArr[0], this.nodeArr[i])
            }
        }
    }
    createTreeLeft(nodeParent, node) {
        if (nodeParent.childLeft == null) { //如果左节点为空,直接将节点插入到节点左边   
            nodeParent.addChildLeft(node);
            node.addParents(nodeParent);
            return;
        } else { //如果左节点不为为空,判断节点是否大于父节点,大于插入到右边且 ,小于则插入到左节点 
            if (node.value <= nodeParent.childLeft.value) {
                this.createTreeLeft(nodeParent.childLeft, node)
            } else {
                this.createTreeRight(nodeParent.childLeft, node)
            }
        }
    }

    createTreeRight(nodeParent, node) { //如果右节点为空,直接将节点插入到节点右边   
        if (nodeParent.childRight == null) {
            nodeParent.addChildRight(node);
            node.addParents(nodeParent);
            return;
        } else { //如果右节点不为为空,判断节点是否小于父节点,小于插入到左节点,大于于则插入到右节点 
            if (node.value > nodeParent.childRight.value) {
                this.createTreeRight(nodeParent.childRight, node)
            } else {
                this.createTreeLeft(nodeParent.childRight, node)
            }
        }
    }

遍历方式

1 先序遍历
先访问根节点,然后依次访问左节点和右节点;


    preOrder(node) { //先序遍历
        if (node != null) {
            this.preArr.push(node)
            this.preOrder(node.childLeft);
            this.preOrder(node.childRight);
        }
    }

1 中序遍历
先访问左节点,然后依次访问根节点和右节点,中序遍历的结果为从小到大的排序结果

    MidOrder(node) { //中序遍历  
        if (node != null) {
            this.MidOrder(node.childLeft);
            this.MinArr.push(node)
            this.MidOrder(node.childRight);
        }
    }

1 后序遍历
先访问左节点,然后依次访问右节点和根节点

    PostOrder(node) { //后序遍历
        if (node != null) {
            this.PostOrder(node.childLeft);
            this.PostOrder(node.childRight);
            this.postArr.push(node)
        }
    }

二叉排序树的查找方式

1.若b是空树,则搜索失败,否则:
2.若x等于b的根节点的数据域之值,则查找成功;否则:
3.若x小于b的根节点的数据域之值,则搜索左子树;否则:
4.查找右子树。
算法实现

findNode(value, node) { //查找节点
        if (node != null) {
            if (value == node.value) {
                return node
            } else if (value < node.value) { //小于遍历左边
                return this.findNode(value, node.childLeft);
            } else { //大于遍历右边
                return this.findNode(value, node.childRight)
            }
        } else {
            return false
        }
    }

增加节点

遍历二叉树将新生成的节点插入到指点位置

addNode(value) { //增加节点
        let node = new Node(value)
        this.nodeArr.push(node)
        if (node.value < this.nodeArr[0].value) { //如果节点小于根节点,将数据插入到左边
            this.createTreeLeft(this.nodeArr[0], node)
        } else { //如果节点小于根节点,将数据插入到右边
            this.createTreeRight(this.nodeArr[0], node)
        }
    }

删除节点

先找到要删除的节点,然后根据情况修改节点信息
1. 该节点没有子节点
2. 该节点左节点和右节点都存在
3. 该节点只有左节点
4. 该节点只有右节点

    removeNode(value) { //删除节点
        let node = this.nodeArr.find(item => item.value == value); //根据值查找node节点
        if (node != undefined) { //如果存在
            this.nodeArr.splice(this.nodeArr.findIndex(item => item.value === value), 1) //在nodeArr中删除节点
            if (node.childRight == null && node.childLeft == null) { //如果要删除的节点没有左节点和右节点
                if (node == node.parents.childLeft) { //判断该节点是父节点的左节点还是右节点
                    node.parents.childLeft = null //删除该节点
                } else {
                    node.parents.childRight = null //删除该节点
                }
            } else if (node.childRight != null && node.childLeft != null) { //如果该节点左节点右节点都存在
                node.childRight.parents = node.childLeft; //将该节点右节点的父节点变成该节点的左节点
                node.childLeft.childRight = node.childRight //将该节点左节点的右节点变成该节点的右节点
                node.childLeft.parents = node.parents; //将该节点的左节点的父节点变成该节点的父节点
                if (node == node.parents.childLeft) { //判断该节点是父节点的左节点还是右节点
                    node.parents.childLeft = node.childLeft //将该节点的左节点变成该节点父节点的左节点
                } else {
                    node.parents.childRight = node.childLeft; //将该节点的左节点变成该节点父节点的右节点
                }
            } else if (node.childLeft == null) { //如果该节点的左节点为空
                if (node == node.parents.childLeft) { //判断该节点是父节点的左节点还是右节点
                    node.parents.childLeft = node.childRight //将该节点的右节点变成该节点父节点的左节点
                } else {
                    node.parents.childRight = node.childRight; //将该节点的右节点变成该节点父节点的右节点
                }
            } else { //如果该节点的右节点为空
                if (node == node.parents.childLeft) { //判断该节点是父节点的左节点还是右节点
                    node.parents.childLeft = node.childLeft //将该节点的左节点变成该节点父节点的左节点
                } else {
                    node.parents.childRight = node.childLeft; //将该节点的左节点变成该节点父节点的右节点
                }
            }
        }
        this.init() //重新遍历
    }

修改节点

先找到该节点,然后修改对应的值,最后重新生成二叉排序树

    updateNode(oldValue, newValue) { //更新节点
        let node = this.findNode(oldValue, this.root); //获取要更新的节点
        if (node) {
            node.value = newValue; //更新节点的值
            this.updateTree(); //重新生成二叉树
        } else { //找不到返回false
            return false
        }
    }

其他方法

init() {
        this.reset() //重置遍历数组
        this.preOrder(this.nodeArr[0]);
        this.MidOrder(this.nodeArr[0]);
        this.PostOrder(this.nodeArr[0])
    }

    reset() { //重置遍历数组
        this.preArr = [];
        this.MinArr = [];
        this.postArr = [];
    }

    distoryTree() { //删除二叉搜索树
        for (let index = 0; index < this.nodeArr.length; index++) {
            this.nodeArr[index].parents = null
            this.nodeArr[index].childRight = null
            this.nodeArr[index].childLeft = null
        }
    }

    updateTree() { //更新二叉搜索树
        this.distoryTree()
        this.createTree()
        this.init()
    }

GitHub

https://github.com/linqiangchen/web-dataStructure
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值