JavaScript_SA 树

树是一种分层数据的抽象模型
一个树结构包含一系列存在子父关系的节点 每个节点都有一个父节点(除了顶部的第一个节点)以及零个或多个子节点
位于树顶部的节点叫做根节点
至少有一个子节点的节点称为内部节点
没有子元素的节点称为外部节点或叶节点
子树:由节点和它的后代构成
深度:节点的深度取决于它祖先节点的数量
高度:树的高度取决于所有节点深度的最大值 根节点在第0层 根节点的子节点在第1层 以此类推
在这里插入图片描述
1、二叉树与二叉搜索树
二叉树中的节点最多只能有两个节点 一个左侧子节点 一个右侧子节点
二叉搜索树(BST)是二叉树的一种 但是它只允许你在左侧节点存储比父节点小的值 在右侧节点存储比父节点大或者等于父节点的值
二叉搜索树的组织方式:

function BinarySearchTree() { 
    var Node = function(key){ /*和链表一样,将通过
指针来表示节点之间的关系(术语称其为边)。在双向链表中,
每个节点包含两个指针,一个指向下一个节点,另一个指向上
一个节点。对于树,使用同样的方式(也使用两个指针)。但是,
一个指向左侧子节点,另一个指向右侧子节点。因此,将声明一
个Node类来表示树中的每个节点*/
        this.key = key; 
        this.left = null; 
        this.right = null; 
    }; 
    var root = null; //根元素
}

在这里插入图片描述
★方法:
① insert(key):向树中插入一个新的键。

this.insert = function (key) {
    var newNode = new Node(key); /*创建用来表示
新节点的Node类实例。只需要向构造函数传递我们想用来
插入树的节点值,它的左指针和右指针的值会由构造函数
自动设置为null。*/
    if (root === null) { /*要验证这个插入操作是否
为一种特殊情况。这个特殊情况就是我们要插入的节点是树
的第一个节点。如果是,就将根节点指向新节点。*/ 
        root = newNode;
    } else {
        insertNode(root, newNode); /*将节点加在非
根节点的其他位置。这种情况下,需要一个私有的辅助函数*/ 
    }
};
//调用
var tree = new BinarySearchTree(); 
tree.insert(num);

insertNode函数:insertNode函数会帮助我们找到新节点应该插入的正确位置。

/*如果树非空,需要找到插入新节点的位置。因此,在调用
insertNode方法时要通过参数传入树的根节点和要插入的节点。*/    
var insertNode = function (node, newNode) {
    if (newNode.key < node.key) { /*如果新节点的键小于当
    前节点的键(现在,当前节点就是根节点)*/ 
        if (node.left === null) { /*那么需要检查当
        前节点的左侧子节点。如果它没有左侧子节点,就在
        那里插入新的节点。*/
            node.left = newNode;  
        } else {
            insertNode(node.left, newNode); /*如果有左
侧子节点,需要通过递归调用insertNode方法继续找到树的下一层。*/ 
        }
    } else {
        if (node.right === null) { /*如果节点的键比当
前节点的键大,同时当前节点没有右侧子节点,就在那里插入新的
节点。如果有右侧子节点,同样需要递归调用insertNode方法,
但是要用来和新节点比较的节点将会是右侧子节点。*/
            node.right = newNode;  
        } else {
            insertNode(node.right, newNode); 
        }
    }
};

②search(key):在树中查找一个键,如果节点存在,则返回true;如果不存在,则返回
false。
③inOrderTraverse:前中后序遍历。
④search:搜索一个特定的值。

this.search = function (key) {
    return searchNode(root, key); //辅助函数{1}
};
/*searchNode方法可以用来寻找一棵树或它的任意子
树中的一个特定的值。调用它的时候传入树的根节点
作为参数。在开始算法之前,先要验证作为参数传入
的node是否合法(不是null)。如果是null的话,
说明要找的键没有找到,返回false。如果传入的节点
不是null,需要继续验证。*/
var searchNode = function (node, key) {
    if (node === null) { //是否合法{2}
        return false;
    }
    if (key < node.key) {
        //如果要找的键比当前的节点小{3}
        return searchNode(node.left, key);
        //那么继续在左侧的子树上搜索{4}
    } else if (key > node.key) {
        //如果要找的键比当前的节点大{5}
        return searchNode(node.right, key);
        //那么就从右侧子节点开始继续搜索{6}
    } else {
        return true;
        //否则就说明要找的键和当前节点的键相等{7}
    }
};
//调用
console.log(tree.search(1) ? 'Key 1 found.' : 'Key 1 not found.');

(1) 调用searchNode方法,传入根节点作为参数(行{1})。(node[root[11]])不是null
(行{2}),因此我们执行到行{3}。
(2) (key[1] < node[11])为ture(行{3}),因此来到行{4}并再次调用searchNode方法,传入(node[7], key[1])作为参数。
(3) (node[7])不是null({2}),因此继续执行行{3}。
(4) (key[1] < node[7])为ture(行{3}),因此来到行{4}并再次调用searchNode方法,传入(node[5], key[1])作为参数。
(5) (node[5])不是null(行{2}),因此继续执行行{3}。
(6) (key[1] < node[5])为ture(行{3}),因此来到行{4}并再次调用searchNode方法,传入(node[3], key[1])作为参数。
(7) (node[3])不是null(行{2}),因此来到行{3}。
(8) (key[1] < node[3])为真(行{3}),因此来到行{4}并再次调用searchNode方法,传入(null, key[1])作为参数。null被作为参数传入是因为node[3]是一个叶节点(它没有子节点,所以它的左侧子节点的值为null)。
(9) 节点(null)的值为null(行{2},这时要搜索的节点为null),因此返回false。
(10) 然后,方法调用会依次出栈,代码执行过程结束。
★遍历

function BinarySearchTree() {
    var Node = function (key) { 
        this.key = key;
        this.left = null;
        this.right = null;
    };
    var root = null; 
    this.insert = function (key) {
        var newNode = new Node(key); 
        if (root === null) { 
            root = newNode;
        } else {
            insertNode(root, newNode); 
        }
    };
    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);  
            }
        }
    };
    this.inOrderTraverse = function (callback) {
         anode(root, callback); 
    };
    var anode = function (node, callback) {
        if (node !== null) { 
    //中序遍历 首先遍历左子树,然后访问根结点,最后遍历右子树。
            anode(node.left, callback); 
            callback(node.key); 
            anode(node.right, callback);  
    /*前序遍历 
            callback(node.key); 
            anode(node.left, callback); 
            anode(node.right, callback); */
    /*后序遍历
            anode(node.left, callback); 
            anode(node.right, callback);
            callback(node.key);                       */                 
        }
    };
}
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);
function printNode(value) {  
    console.log(value);
}
tree.inOrderTraverse(printNode); //3,5,7,8,9,11,15

二叉搜索树(BST)存在一个问题 树的一条边可能会非常深 为了解决这个问题 出现了一种自平衡二叉搜索树(AVL)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值