二叉树的应用

完美二叉树(满二叉树)

除了最下一层的节点外,每层节点都有两个子节点的二叉树为满二叉树

完全二叉树

除二叉树最后一层外,其余各层节点都为2,且最后一层从左向右的叶节点连续存在,只缺右侧若干节点


完美二叉树与完全二叉树

常见的题目

  • 一个二叉树第i层的最大节点数为:2^(i-1),i>=1
  • 深度为k的二叉树最大节点数总数为:2^k-1,k>=1
  • 对任何非空二叉树,n1表示叶节点个数,n2是度为2的非叶节点个数,那么两者满足关系:n1 = n2 + 1

二叉搜索树(BST)

BST:Binary Search Tree
特性:
1.非空左子树的所有键值小于其根节点的键值
2.非空右子树的所有键值大于其根节点的键值

二叉搜索树的三种遍历

  1. 前序遍历:树根->左子树->右子树(ABDGHCEIF)


    前序遍历
  2. 中序遍历:左子树->树根->右子树(GDHBAEICF)


    中序遍历
  3. 后序遍历:左子树->右子树->树根(GHDBIEFCA)


    后续遍历
二叉搜索树的常见操作

insert(key):向树中插入一个新的键
search(key):在树中查找某个键,返回布尔值
preOrderTraversal:先序遍历所有节点
midOrderTraversal():中序遍历所有节点
postOrderTraversal():后序遍历所有节点>min():返回树中最小值/键
max():返回树中最大值/键
remove(key):从树中移除一个键

代码实现
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <script>
        //封装二叉搜索树
        function BinarySerachTree() {

            //内部类
            function Node(key) {
                this.key = key
                this.left = null
                this.right = null
            }

            //属性
            this.root = null

            //方法
            //插入数据
            BinarySerachTree.prototype.insert = function (key) {
                //1.根据key创建节点
                var newNode = new Node(key)

                //2.判断根节点是否有值
                if (this.root == null) {
                    this.root = newNode
                } else {
                    this.insertNode(this.root, newNode)
                }

                //递归插入
                BinarySerachTree.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)
                        }
                    }
                }

                //先序遍历
                BinarySerachTree.prototype.preOrderTraversal = function (handler) {
                    this.preOrderTraversalNode(this.root, handler)
                }

                BinarySerachTree.prototype.preOrderTraversalNode = function (node, handler) {
                    if (node !== null) {
                        //处理经过的节点
                        handler(node.key)
                        //处理经过的节点的左子节点
                        this.preOrderTraversalNode(node.left, handler)
                        //处理经过的节点的右子节点
                        this.preOrderTraversalNode(node.right, handler)
                    }
                }

                //中序遍历
                BinarySerachTree.prototype.midOrderTraversal = function (handler) {
                    this.midOrderTraversalNode(this.root, handler)
                }

                BinarySerachTree.prototype.midOrderTraversalNode = function (node, handler) {
                    if (node !== null) {
                        //处理经过的节点的左子节点
                        this.midOrderTraversalNode(node.left, handler)
                        //处理经过的节点
                        handler(node.key)
                        //处理经过的节点的右子节点
                        this.midOrderTraversalNode(node.right.handler)
                    }
                }

                //后序遍历
                BinarySerachTree.prototype.postOrderTraversal = function (handler) {
                    this.postOrderTraversalNode(this.root, handler)
                }

                BinarySerachTree.prototype.postOrderTraversalNode = function (node, handler) {
                    if (node !== null) {
                        //处理经过的节点的左子节点
                        this.postOrderTraversalNode(node.left, handler)
                        //处理经过的节点的右子节点
                        this.postOrderTraversalNode(node.right.handler)
                        //处理经过的节点
                        handler(node.key)
                    }
                }

                //寻找最大值
                BinarySerachTree.prototype.max = function () {
                    //获取根节点
                    var node = this.root

                    var key = null
                    //依次向右查找,直到节点为null
                    while(node != null){
                        key = node.key
                        node = node.right
                    }

                    return key
                }

                //寻找最小值
                BinarySerachTree.prototype.min = function () {
                    //获取根节点
                    var node = this.root

                    var key = null
                    //依次向左查找,直到节点为null
                    while(node != null){
                        key = node.key
                        node = node.left
                    }

                    return key
                }
            
                //寻找是否存在某节点
                BinarySerachTree.prototype.search = function(key){
                    return this.searchNode(this.root,key)
                }

                BinarySerachTree.prototype.searchNode = function(node,key){
                    //如果传入的node值为null,就退出递归
                    if(node == null){
                        return false
                    }

                    //判断node节点的值和传入的key的大小
                    if(node.key > key){
                        //传入的key较小,向左查找
                        return this.searchNode(node.left,key)
                    }else if(node.key < key){
                        //传入的key较大,向左查找
                        return this.searchNode(node.right,key)
                    }else{
                        //key相同,找到了
                        return true
                    }
                }
            
                //删除节点
                BinarySerachTree.prototype.remove = function(key){
                    //寻找要删除的节点
                    var current = this.root
                    var parent = null
                    var isLeftChild = true

                    while(current.key != key){
                        parent = current
                        if(ket < current.key){
                            //在左边
                            isLeftChild = true
                            current = current.left
                        }else{
                            isLeftChild = false
                            current = current.right
                        }

                        //没有找到
                        if(current == null) return false
                    }

                    //删除节点
                    //1.叶子节点
                    if(current.left == null && current.right == null){
                        if(current == this.root){
                            this.root = null
                        }else if(isLeftChild){
                            parent.left = null
                        }else{
                            parent.right = null
                        }
                    }

                    //根节点且有一个子节点
                    else if(current.right == null){
                        if(current == this.root){
                            this.root = current.left
                        }else if(isLeftChild){
                            parent.left = current.left
                        }else{
                            parent.right = current.left
                        }
                    }else if(current.left == null){
                        if(current == this.root){
                            this.root = current.right
                        }else if(isLeftChild){
                            parent.left = current.right
                        }else{
                            parent.right = current.right
                        }
                    }

                    //根节点且有两个子节点
                    else{
                        //获取后继节点
                        var successor = this.getSuccssor(current)

                        if(current == this.root){
                            //是根节点
                            this.root = successor
                        }else if(isLeftChild){
                            parent.left = successor
                        }else{
                            parent.right = successor
                        }

                        successor.left = current.left
                    }

                }

                //找后继方法
                BinarySerachTree.prototype.getSuccssor = function(delNode){
                    var successor = delNode
                    var current = delNode.right
                    var successorParent = delNode

                    //循环查找
                    while(current != null){
                        successorParent = successor
                        successor = current
                        current = current.left
                    }

                    //后继节点是delNode的right节点
                    if(successor != delNode.right){
                        successorParent.left = successor.right
                        successor.right = delNode.right
                    }

                    return successor
                }
            }

        }

    </script>
</body>

</html>
END
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容