学习js数据结构与算法6—树

8.1 树的相关术语

  • 位于树顶部的节点叫做根节点
    • 内部节点(至少有一个子节点)和外部节点(没有子节点)
  • 节点的深度,取决于它祖先节点的个数
  • 树的高度取决于所有节点深度的最大值
  • 键是树中对节点的称呼

8.2 二叉树和二叉搜索树

  • 二叉树的节点最多只能有两个子节点
    • 一个是左侧子节点
    • 一个是右侧子节点
    • ==有助于写出更高效的向树中插入,查找和删除节点的算法==
  • 二叉搜索树是二叉树的一种
    • 只允许在左侧节点存储比父节点小的值
    • 在右侧节点存储比父节点大的值
    // 创建二叉搜索树类
    function BinarySearchTree() {
        // 声明Node类来表示树中的每个节点
        var Node = function (key) {
            this.key = key;
            this.left = null;
            this.right = null;
        };        
        // 根元素
        var root = null;
        /*
            insert(key): 向树中插入一个新的键
            search(key): 在树中查找一个键,存在返回true,否则false
            inOrderTraverse: 通过中序遍历方式遍历所有节点
            preOrderTraverse: 通过先序遍历方式遍历所有节点
            postOrderTraverse:通过后序遍历方式遍历所有节点
            min:返回树中最小的值/键
            max:返回树中最大的值/键
            remove(key):从树中移除某个键
        */
        var insertNode = function (node, newNode) {
            if (newNode.key < node.key) {
                if (node.left === null) {
                    node.left = newNode;
                } else {
                    insertNode(node.left, newNode);
                }
            } else {
                if (node.right === null) {
                    node.right = newNode;
                } else {
                    insertNode(node.right, newNode); 
                }
            }
        };
    
        // insert(key)
        this.insert = function (key) {
            var newNode = new Node(key);
    
            if (root === null) {
                root = newNode;
            } else {
                insertNode(root, newNode);
            }
        };
    }

8.3 树的遍历

    中序遍历就是从最小到最大的顺序访问所有节点。
    应用于对树进行排序操作
    
    this.inOrderTraverse = function(callback) {
        inOrderTraverseNode(root, callback);
    };

    function inOrderTraverseNode(node, callback) {
        if (node !== null) {
            inOrderTraverseNode(node.left, callback);
            callback(node.key);
            inOrderTraverseNode(node.right, callback);
        }
    }
    
    先序遍历是以优先于后代节点的顺序访问每个节点
    应用于打印一个结构化的文档
    
    this.preOrderTraverse = function (callback) {
        preOrderTraverseNode(root, callback);
    };

    function preOrderTraverseNode(node, callback) {
        if (node !== null) {
            callback(node.key);
            preOrderTraverseNode(node.left, callback);
            preOrderTraverseNode(node.right, callback);
        }
    }

    后序遍历是先访问节点的后代节点,再访问节点本身
    应用于计算一个目录和它的子目录中所有文件所占空间的大小
    
    this.postOrderTraverse = function (callback) {
        postOrderTraverseNode(root, callback);
    };

    function postOrderTraverseNode(node, callback) {
        if (node !== null) {
            postOrderTraverseNode(node.left, callback);
            postOrderTraverseNode(node.right, callback);
            callback(node.key);
        }
    }
    
    function printNode(val) {
        console.log(val);
    }
    // 使用二叉搜索树类
    var tree = new BinarySearchTree();
    tree.insert(11);
    tree.insert(7);
    tree.insert(15);
    tree.insert(5);
    tree.insert(3);
    tree.insert(9);
    tree.insert(8);
    tree.insert(10);
    tree.insert(13);
    tree.insert(12);
    tree.insert(14);
    tree.insert(20);
    tree.insert(18);
    tree.insert(25);
    
    tree.insert(6);
    // 中序遍历,从小到大
    // tree.inOrderTraverse(printNode);
    
    // 先序遍历
    // tree.preOrderTraverse(printNode);
    
    // 后序遍历
    tree.postOrderTraverse(printNode);
    搜索树中的值
    在树中,有三种经常执行的搜索类型
    最大值、最小值、搜索特定的值
    // 最小值
    var minNode = function (node) {
        if (node) {
            while (node && node.left !== null) {
                node = node.left
            }

            return node.key;
        }
        return null;
    };
    this.min = function () {
        return minNode(root);
    };

    // 最大值
    var maxNode = function (node) {
        if (node) {
            while (node && node.right !== null) {
                node = node.right;
            }

            return node.key;
        }
        return null;
    };
    this.max = function () {
        return maxNode(root);
    }

    // 搜索一个特定的值
    var searchNode = function (node, key) {

        if (node === null) {
            return false;
        }
        if (key < node.key) {
            return searchNode(node.left, key);
        } else if (key > node.key) {
            return searchNode(node.right, key);
        } else {
            return true;
        }
    };
    this.search = function (key) {
        return searchNode(root, key);
    };

    // 移除一个节点
    var removeNode = function (node, key) {
        if (node === null) {
            return null;
        }
        if (key < node.key) {
            node.left = removeNode(node.left, key);
            return node;
        } else if (key > node.key) {
            node.right = removeNode(node.right, key);
            return node;
        } else {    // 键等于node.key

            // 第一种情况——一个外部节点(无子节点)
            if (node.left === null && node.right === null) {
                node = null;
                return node;
            }

            // 第二种情况——一个只有一个子节点的节点
            if (node.left === null) {
                node = node.right;
                return node;
            } else if (node.right === null) {
                node = node.left;
                return node;
            }

            // 第三种情况——一个有两个子节点的节点
            var aux = findMinNode(node.right);
            node.key = aux.key;
            node.right = removeNode(node.right, axu.key);
            return node;
        }
    };

    function findMinNode(node) {
        if (node) {
            while (node && node.left !== null) {
                node = node.left;
            }

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

推荐阅读更多精彩内容