3.js-树

作者: 悠哈121 | 来源:发表于2021-02-14 16:08 被阅读0次

非顺序数据结构:散列表、树(存储需要快速查找的数据)
节点的的深度取决于它的祖先节点数量,树的高度取决于所有节点深度的最大值
1.二叉搜索树(BST)是二叉树的一种,但它只允许左侧节点存储比父节点值小,右侧节点存储比父节点大

//代码实现
//创建BinarySearchTree
function BinarySearchTree(){
    let Node = function(key){
        this.key = key;
        this.left = null;
        this.right = null;
    }
    let root = null;
    this.insert = function(key){
        let node = new Node(key);
        if(root === null){
            root = node;
        }else{
            insertNode(root,node)
        }
    }
    //遍历只实现中序遍历
    this.inOrderTraverse = function(printNode){
        inOrderTraverseNode(root,printNode)
    }
    //查找特定值
    this.select = function(key){
        return selectkey(root,key)
    }
    //移除一个节点
    this.remove = function(key){
        //这里的返回值是处理要删除节点的父节点指向的,比如5的右指针指向6,删除6之后除了将6设置为null,还需要将5的左指针设置为null
        //原因:let a = {},b = a; a = null; 此时的b为{},原因是改变了a的指向为null;b指向的堆内存并没有改变还是原来的
        //在处理链表的时候,也遇到过这个问题,仅仅赋一个null是不够的,还需要除了前驱指向
        root = removeNode(root,key)
    }
}
function insertNode(root,node){
    if(node.key < root.key){
        if(root.left === null){
            root.left = node
        }else{
            insertNode(root.left,node)
        }
    }else{
        if(root.right === null){
            root.right = node
        }else{
            insertNode(root.right,node)
        }
    }
}

function inOrderTraverseNode(node,printNode){
    if(node !== null){
        inOrderTraverseNode(node.left,printNode);
        printNode(node.key);
        inOrderTraverseNode(node.right,printNode)
    }
   
}
function selectkey(root,key){
    if(root === null) return false;
    if(key < root.key){
        return selectkey(root.left,key)
    }else if(key > root.key){
        return selectkey(root.right,key)
    }else{
        return true;
    }
}
function removeNode(root,key){
    if(root === null) return false;
    if(key <  root.key){
        root.left = removeNode(root.left,key)
        return root;
    }else if(key > root.key){
        root.right = removeNode(root.right,key)
        return root;
    }else{
        if(root.left === null && root.right === null){
            root = null;
            return root
        }else if(root.left === null){
            root = root.right
            return root
        }else if(root.right === null){
            root = root.left
            return root;
        }else{
            //左节点和右节点都不为空的情况下,找到右节点中的最小节点替换该元素
            let minNode = findMiniNode(root.right);
            root.key = minNode.key;
            root.right = removeNode(root.right,minNode.key)
            return root
        }
    }
}

function findMiniNode(root){
    while(root.left){
        root = root.left
    }
    return root
}

let tree = new BinarySearchTree();
tree.insert(4);
tree.insert(2);
tree.insert(1);
tree.insert(3);
tree.insert(5);
// tree.inOrderTraverse((key)=>{
//     console.log(key)
// })
// console.log(tree.select(4))
tree.remove(2)
tree.inOrderTraverse((key)=>{
    console.log(key)
})

2.自平衡树(AVL)添加或移除节点的时候,AVL树会尝试自平衡。任意一个节点的左子树和右子树高度最多相差1

//代码实现
function BinarySearchTree(){
    let Node = function(key){
        this.key = key;
        this.left = null;
        this.right = null;
    }
    let root = null;
    this.insert = function(key){
        let node = new Node(key);
        if(root === null){
            root = node;
        }else{
            root = insertNode(root,node)
        }
    }
    //只实现先序遍历
    this.preOrderTraverse = function(printNode){
        preOrderTraverseNode(root,printNode)
    }
}
function insertNode(root,node){
    //AVL树的不同之处在于我们需要检验它的平衡因子,如果有需要,则将其逻辑应用于树的自平衡
    if(node.key < root.key){
        if(root.left === null){
            root.left = node
        }else{
            //平衡因子的计算是需要节点插入完成之后计算的,所以这里需要返回
            root.left = insertNode(root.left,node)
        }
        if(root.left !== null){
            //确认是否需要平衡
            if((heightNode(root.left) - heightNode(root.right)) > 1){
                if(node.key < root.left.key){
                   root = rotationLL(root)
                }else{
                    root = rotationLR(root)
                }
            }
        }
    }else{
        if(root.right === null){
            root.right = node
        }else{
            root.right=insertNode(root.right,node)
        }
        if(root.right !== null){
            //确认是否需要平衡
            if((heightNode(root.right) - heightNode(root.left)) > 1){
                if(node.key > root.right.key){
                    root = rotationRR(root)
                }else{
                    root = rotationRL(root)
                }
            }
        }
    }
    return root
}
function preOrderTraverseNode(node,printNode){
    if(node !== null){
        printNode(node.key);
        preOrderTraverseNode(node.left,printNode);
        preOrderTraverseNode(node.right,printNode)
    }
   
}
//该函数为计算树高度的函数,每递归一层,则深度+1,如果当前节点的右子树比左子树深,即该树的高度为 右子树的高度
function heightNode(root){
    if(root === null){
        // 返回-1的原因是,计算树的高度时候,(不计算根节点所在层,根节点所在是第0层),
        // 在这里计算树的高的时候是相反的
        // 叶子节点所在的为0层,而叶子的上一级(父节点)为1,在上一级为2..以此类推
        return -1
    }else{
        return Math.max(heightNode(root.left),heightNode(root.right))+1
    }
}
//实现左旋 RR:(以当前节点为根,第一个R指当前节点的右子树(tr),第二个R指右子树(tr)的右子树)
//需要左旋是由于在当前节点的右子树的右子树的子树插入了一个节点
function rotationRR(root){
    let tmp = root.right
    root.right = tmp.left;
    tmp.left = root;
    return tmp
}
//实现右旋LL:需要右旋是由于在当前节点的左子树的左子树的子树插入了一个节点
function rotationLL(root){
    let tmp = root.left
    root.left = tmp.right;
    tmp.right = root;
    return tmp
}
//先右旋后左旋RL:需要先右旋后左旋的原因是因为在当前节点的右子树的左子树插入了一个节点(先将右子树右旋,再将当前节点左旋)
function rotationRL(root){
    root.right = rotationLL(root.right)
    return rotationRR(root);
}
//先左旋后右旋LR:需要先左旋后右旋的原因是因为在当前节点的左子树的右子树插入了一个节点(先将左子树左旋,再将当前节点右旋)
function rotationLR(root){
    root.left = rotationRR(root.left)
    return rotationLL(root);
}

let tree = new BinarySearchTree();
//测试左旋
// tree.insert(4);
// tree.insert(2);
// tree.insert(1);
// tree.insert(3);
// tree.insert(5);
//测试右旋
// tree.insert(5);
// tree.insert(4);
// tree.insert(3);
// tree.insert(2);
// tree.insert(1);
//测试LR
// tree.insert(10);
// tree.insert(7);
// tree.insert(14);
// tree.insert(5);
// tree.insert(9);
// tree.insert(8);
//测试RL
tree.insert(10);
tree.insert(7);
tree.insert(14);
tree.insert(13);
tree.insert(18);
tree.insert(12);
//这里用先序遍历测试
tree.preOrderTraverse((key)=>{
    console.log(key)
})

相关文章

  • 3.js-树

    非顺序数据结构:散列表、树(存储需要快速查找的数据)节点的的深度取决于它的祖先节点数量,树的高度取决于所有节点深度...

  • 水彩过程 | 树树树树

    练习了一下树的画法,用毛笔勾树干,扇形笔画树叶还是又快又方便的。因为不是写实风格,只要把树的意象画出来就可以,所以...

  • 树·树

    ​如果有来生,要做一棵树,站成永恒,没有悲欢姿势,一半在尘土里安详。一半在风里飞扬,一半洒落阴凉,一半沐浴阳光。 ...

  • 树,树……

    树,树…… ——洛尔迦 树,树, 枯了又绿。 脸蛋美丽的姑娘 在那里摘橄榄。 风,塔楼上的求爱者, 拦腰把她...

  • 橄榄树树树

    在建班级群的时候,我顺手打了三个树——橄榄树树树。是的,这是橄榄树第三次起航。 第一次,在北京,我说,我愿意在无人...

  • 树,与树

    (第一次学着简书里文友看图写诗,2020的图,各位讲究着看吧) 文/三少爷的糖 一颗树站在山头 遥望着远方,朦胧中...

  • 树,与树

    我不是一个很喜欢女生哭闹的人。 哭闹,意味着理智被情感摧毁。 理智没了,沟通渠道也就关闭了。 没有了沟通,剩下的就...

  • 树和树

    我的家门前有一棵柏树,不是什么稀罕的树,但它却挺直腰杆儿,坚定的伫立在我家门前,望着远方,似乎在等什么人又不像在等...

  • 树树秋声

    余秋雨说:生命,是一树花开,或安静或热烈,或寂寞或璀璨。日子,就在岁月的年轮中渐次厚重,那些天真的、跃动的、抑或沉...

  • 短篇‖树树

    这是一条幽静的古道,两旁尽是残垣断壁,竟也有一些台阶通向几栋还算有顶篷的石质的建筑物。我和我的伙伴着级上了一段...

网友评论

      本文标题:3.js-树

      本文链接:https://www.haomeiwen.com/subject/hhhexltx.html