目录

数据结构与算法二叉搜索树,使用TreeMap将键值对存储在一棵二叉搜索树的节点

数据结构与算法——二叉搜索树,使用TreeMap将键值对存储在一棵二叉搜索树的节点

二叉搜索树

二叉搜索树 (BST)】:对于树中的每个节点,其 左子树的每个节点 的值都要小于这个节点的值, 右子树的每个节点 的值都要大于这个节点的值。 左小右大中序遍历结果是有序的 ,会从小到大排序。

    7
   / \
  4   9
 / \   \
1   8   10	(不符合)

可以使用 TreeMap 把键值对存储在一棵二叉搜索树的节点里

通过遍历这棵二叉搜索树,比遍历普通的二叉树能更快实现增删查改

class TreeNode {
    constructor(key, value) {
        this.key = key;
        this.value = value;
        this.left = null;
        this.right = null;
        this.size = 1;
    }
}

1. 常用操作:

其中包括:

【插入或更新键值对】

【获取键对应的值】

【检查是否包含键】

【返回所有键的有序集合】

【找到最小/最大键】

【找到小于等于key的最大键/大于等于key的最小键】

【区间查询】

class MyTreeMap {
    constructor() {
        this.root = null;
    }

    _size(node) {
        return node ? node.size : 0;
    }

    //插入或更新键值对
    put(key, value) {
        //根节点
        this.root = this._put(this.root, key, value);
    }

    _put(node, key, value) {
        if (node === null) {
            return new TreeNode(key, value);
        }

        if (key < node.key) {
            node.left = this._put(node.left, key, value);
        }else if (key > node.key) {
            node.right = this._put(this.right, key, value);
        }else {
            node.value = value;
        }

        node.size = 1 + this._size(node.left) + this._size(node.right);
        return node;
    }

    //获取键对应的值
    get(key) {
        let node = this.root;
        while (node !== null) {
            if (key < node.key) {
                node = node.left;
            }else if (key > node.key) {
                node = node.right;
            }else {
                return node.value;
            }
        }
        return false;
    }

    //检查是否包含键
    containKey(key) {
        let node = this.root;
        while (node !== null) {
            if (key < node.key) {
                node = node.left;
            }else if (key > node.key) {
                node = node.right;
            }else {
                return true;
            }
        }
        return false;
    }


    //返回所有键的有序集合
    keys() {
        const result = [];
        this._inOrder(this.root, result);
        return result;
    }

    _inOrder(node, result) {
        if (node === null) { return; }
        this._inOrder(node.left, result);//左
        result.push(node.key);//中
        this._inOrder(node.right, result);//右
    }


    //找到最小键
    firstKey() {
        let node = this.root;
        while (node && node.left !== null) { node = node.left;}
        return node ? node.key : null;
    }

    //找到最大键
    lastKey() {
        let node = this.root;
        while (node && node.right !== null) { node = node.right;}
        return node ? node.key : null;
    }

    //小于等于key的最大键
    //分两种情况: 节点key的值===要查找的key值;  节点key的值大于要查找的值
    min_maxKey() {
        let node = this.root;
        let data = null;
        while (node !== null) {
            if (node.key === key) return key;
            if (node.key > key ){
                node = node.left;
            }else {
                data = node.key;
                node = node.right;
            }
        }
        return data;
    }

    //大于等于key的最小值
    max_minKey() {
        let node = this.root;
        let data = null;
        while (node !== null) {
            if (node.key === key ) return key;
            if (node.key < key) {
                node = node.right;
            }else {
                data = node.key;
                node = node.left;
            }
        }
        return data;
    }

    //区间查询
    rangeKeys(low, high) {
        const result = [];
        this._rangeKeys(this.root, low, high, result);
        return result;
    }

    _rangeKeys(node, low, high, result) {
        if (node === null) return;
        if (low < node.key) {
            this._rangeKeys(node.left, low, high, result);
        }
        if (node.key >= low && node.key <= high) {
            result.push(node.key);
        }
        if (node.key < high) {
            this._rangeKeys(node.right, low, high, result);
        }
    }
}

2. 理解删除操作

删除键

// 核心:

// 二叉搜索树的性质:左子树所有节点 < 当前节点 < 右子树所有节点

// 寻找要删除键A的右子树中最小值节点B,并替代A,然后删除B节点

分为以下情况:

假设红色框中节点待删除,为键A

图1、图2对应键A左子树为null,图三对应J键A右子树为null,图四对应键A左右子树都不为null

https://i-blog.csdnimg.cn/direct/90068ff6103b4a8ab76cce8ea95e45a6.png

//删除键
    // 核心:
    // 二叉搜索树的性质:左子树所有节点 < 当前节点 < 右子树所有节点
    // 寻找要删除键A的右子树中最小值节点B,并替代A,然后删除B节点
    remove(key) {
        this.root =  this._remove(this.root, key);
    }

    _remove(node, key) {
        if (node === null) { return false;}

        //递归搜索,直到找到key
        if (key < node.key) {
            node.left = this._remove(node.left, key);
        }else if (key > node.key) {
            node.right = this._remove(node.right, key);
        }else {//找到key
            if (node.left === null) { return node.right;}
            if (node.right === null) { return node.left;}
            const minNode = this._min(node.right);
            node.key = minNode.key;
            node.value = minNode.value;
            node.right = this._deleteMin(node.right);
        }
        node.size = 1 + this._size(node.left) + this._size(node.right);
        return node; 
    }

    _min(node) {
        while (node.left !== null) { node = node.left;}
        return node;
    }

    _deleteMin(node) {
        //当左子树为空时,直接将该节点的右子树返回,即删除了该节点
        if (node.left === null) {return node.right;}

        node.left = this._deleteMin(node.left);
        node.size = 1 + this._size(node.left) + this._size(node.right);
        return node;
    }