【数据结构】自己动手使用JavaScript实现二叉搜索树、二叉堆(第三篇)

1. 二叉搜索树(Binary Search Tree)

<待补充>

class Node {
    constructor(key) {
        this.key = key;
        this.left = null;
        this.right = null;
    }
}

const compareFn = (a, b) => {
    if(a < b) {
        return -1
    } else if(a > b) {
        return 1;
    } else {
        return 0;
    }
}

compareFn.LESS_THAN = -1;
compareFn.MORE_THAN = 1;
compareFn.EQ = 0;

export class BinarySearchTree {
    constructor(compare = compareFn) {
        this.compare = compare;
        this.root = null;
    }
    /**
     * @description: 
     * @param {*} key
     * @return {*}
     */
    insert(key) {
        const node = new Node(key);
        if(!this.root) {
            this.root = node;
            return true;
        } else {
            return this.insetNode(node, this.root)
        }
    }
    /**
     * @description: 
     * @param {*} node
     * @param {*} parent
     * @return {*}
     */    
    insetNode(node, parent) {
        const compareRes = this.compare(node.key, parent.key);
        if(compareRes === compareFn.LESS_THAN) {
            if(!parent.left) {
                parent.left = node;
                return true;
            } else {
                return this.insetNode(node, parent.left);
            }
        } else if(compareRes === compareFn.MORE_THAN) {
            if(!parent.right) {
                parent.right = node;
                return true;
            } else {
                return this.insetNode(node, parent.right);
            }
        } else {
            return false;
        }
    }
    /**
     * @description: 
     * @param {*} key
     * @return {*}
     */
    remove(key) {
        if(!this.root) {
            return null;
        }
        const node = this.root;
        if(this.compare(key, node.key) === compareFn.EQ) {
            this.root = null;
            return node;
        }
        const res = this.removeNode(key, node);
        return res.deletedNode;
    }

    removeNode(key, current) {
        const compareRes = this.compare(key, current.key);
        if(compareRes === compareFn.LESS_THAN) {
            if(!current.left) {
                return null;
            } else {
                const res = this.removeNode(key, current.left);
                if(res.needLinked) {
                    current.left = res.linkedNode;
                }                
                return {deletedNode: res.deletedNode };
            }
        } else if(compareRes === compareFn.MORE_THAN) {
            if(!current.right) {
                return null;
            } else {
                const res = this.removeNode(key, current.right);
                if(res.needLinked) {
                    current.right = res.linkedNode;
                }                
                return {deletedNode: res.deletedNode };
            }
        } else {
            const left = current.left;
            const right = current.right;
            if(!left && !right) {
                return {deletedNode: current, linkedNode: null, needLinked: true};
            } else if(left && !right) {
                return {deletedNode: current, linkedNode: left, needLinked: true};
            } else if(!left && right) {
                return {deletedNode: current, linkedNode: right, needLinked: true};
            } else {
                const tempNode = {...current};
                const minNode = this.findMinNode(right);
                current.key = minNode.key;
                const res = this.removeNode(minNode.key, right);
                if(res.needLinked) {
                    current.right = res.linkedNode;
                }
                return { deletedNode: tempNode };
            }
        }
    }

    deepth() {
        if(!this.root) {
            return null;
        }
        return this.searchDeepth(this.root);
    }

    searchDeepth(current) {
        if(!current.left && !current.right) {
            return 0;
        }
        if(current.left && !current.right) {
            return this.searchDeepth(current.left) + 1;
        } else if(!current.left && current.right) {
            return this.searchDeepth(current.right) + 1;
        } else if(current.left && current.right) {
            return Math.max(this.searchDeepth(current.left), this.searchDeepth(current.right)) + 1;
        }
    }

    find(key) {
        return this.findNode(key, this.root)
    }

    findNode(key, current) {
        if(!current) {
            return null;
        }
        const compareRes = this.compare(key, current.key);
        if(compareRes === compareFn.LESS_THAN) {
            return this.findNode(key, current.left);
        } else if(compareRes === compareFn.MORE_THAN) {
            return this.findNode(key, current.right);
        } else {
            return current;
        }
    }

    findMinNode(current) {
        if(!current){
            return null;
        }
        while(current.left) {
            current = current.left;
        }
        return current;
    }

    max() {
        if(!this.root) {
            return undefined;
        }
        let current = this.root;
        while(current.right) {
            current = current.right;
        }
        return current.key;
    }

    min() {
        if(!this.root) {
            return undefined;
        }
        let current = this.root;
        while(current.left) {
            current = current.left;
        }
        return current.key;
    }

    inorder() {
        const keys = [];
        this.inorderTraverse(this.root, keys);
        console.log(keys.toString());
    }

    inorderTraverse(current, keys) {
        if(!current) {
            return false;
        }
        this.inorderTraverse(current.left, keys);
        keys.push(current.key);
        this.inorderTraverse(current.right, keys);
    }

    preorder() {
        const keys = [];
        this.preorderTraverse(this.root, keys);
        console.log(keys.toString());
    }

    preorderTraverse(current, keys) {
        if(!current) {
            return false;
        }
        keys.push(current.key);
        this.preorderTraverse(current.left, keys);
        this.preorderTraverse(current.right, keys);
    }

    postorder() {
        const keys = [];
        this.postorderTraverse(this.root, keys);
        console.log(keys.toString());
    }

    postorderTraverse(current, keys) {
        if(!current) {
            return false;
        }
        this.postorderTraverse(current.left, keys);
        this.postorderTraverse(current.right, keys);
        keys.push(current.key);
    }
}

const bst = new BinarySearchTree();

bst.insert(200);

bst.insert(100);
bst.insert(300);

bst.insert(50);
bst.insert(150);

bst.insert(250);
bst.insert(350);

bst.insert(25);
bst.insert(75);

bst.insert(125);
bst.insert(175);

bst.insert(225);
bst.insert(275);

bst.insert(325);
bst.insert(375);

bst.postorder();
bst.preorder();
bst.inorder();

bst.deepth();

bst.remove(250);

bst.inorder();
bst.deepth();

bst.max();
bst.min();

2. 二叉堆(Heap)

最大堆和最小堆

const compareFn = (a, b) => {
    if(a < b) {
        return -1
    } else if(a > b) {
        return 1;
    } else {
        return 0;
    }
}

compareFn.LESS_THAN = -1;
compareFn.MORE_THAN = 1;
compareFn.EQ = 0;

export class Heap {
    constructor(compare = compareFn) {
        this.items = [];
        this.compare = compare;
    }

    insert(item) {
        if(item) {
            this.items.push(item);
            this.shiftUp(this.items.length - 1)
        }
    }

    extract() {
        if(this.isEmpty()) {
            return undefined;
        }
        const size = this.size();
        if(size === 1) {
            return this.items.shift();
        }
        const item = this.items[0];
        this.items[0] = this.items.pop();
        this.shiftDown(0);
        return item;
    }

    isEmpty() {
        return this.items.length === 0;
    }

    size() {
        return this.items.length;
    }

    min() {
        return this.items[0];
    }

    max() {
        return this.items[0];
    }

    swap(array, indexA, indexB) {
        const temp = array[indexA];
        array[indexA] = array[indexB];
        array[indexB] = temp;
    }

    getParentIndex(index) {
        return Math.floor((index - 1) / 2);
    }

    getLeftIndex(index) {
        return 2 * index + 1;
    }

    getRightIndex(index) {
        return 2 * index + 2;
    }

    toString() {
        return this.items.toString();
    }
}

class MaxHeap extends Heap {
    constructor(compareFn) {
        super(compareFn);
    }

    shiftUp(index) {
        let parent = this.getParentIndex(index);
        while(index > 0 && this.compare(this.items[index], this.items[parent]) === compareFn.MORE_THAN) {
             this.swap(this.items, index, parent);
             index = parent;
             parent = this.getParentIndex(index);
        }
    }

    shiftDown(index) {
        let element = index;
        const left = this.getLeftIndex(element);
        const right = this.getRightIndex(element);
        const size = this.size();
        if(left < size && right < size) {
            const leftCompareRes = this.compare(this.items[element], this.items[left]);
            const rightCompareRes = this.compare(this.items[element], this.items[right]);
            if(leftCompareRes === compareFn.LESS_THAN && rightCompareRes === compareFn.LESS_THAN) {
                if(this.compare(this.items[left], this.items[right]) === compareFn.MORE_THAN) {
                    element = left;
                } else {
                    element = right;
                }
            } else if(leftCompareRes === compareFn.LESS_THAN) {
                element = left;
            } else if(rightCompareRes === compareFn.LESS_THAN) {
                element = right;
            }
        } else if(left < size) {
            if(this.compare(this.items[element], this.items[left]) === compareFn.LESS_THAN) {
                element = left;
            }
        } else if(right < size) {
            if(this.compare(this.items[element], this.items[right]) === compareFn.LESS_THAN) {
                element = right;
            }
        }
        if(index !== element) {
            this.swap(this.items, index, element);
            this.shiftDown(element);
        }
    }
}

class MinHeap extends Heap {
    constructor() {
        super();
    }

    shiftUp(index) {
        const parent = this.getParentIndex(index);
        if(index > 0 && this.compare(this.items[index], this.items[parent]) === compareFn.LESS_THAN) {
            this.swap(this.items, index, parent);
            index = parent;
            this.shiftUp(index);
        }
    }

    shiftDown(index) {
        let element = index;
        const left = this.getLeftIndex(element);
        const right = this.getRightIndex(element);
        const size = this.size();
        if(left < size && right < size) {
            const leftCompareRes = this.compare(this.items[element], this.items[left]);
            const rightCompareRes = this.compare(this.items[element], this.items[right]);
            if(leftCompareRes === compareFn.MORE_THAN && rightCompareRes === compareFn.MORE_THAN) {
                if(this.compare(this.items[left], this.items[right]) === compareFn.LESS_THAN) {
                    element = left;
                } else {
                    element = right;
                }
            } else if(leftCompareRes === compareFn.MORE_THAN) {
                element = left;
            } else if(rightCompareRes === compareFn.MORE_THAN) {
                element = right;
            }
        } else if(left < size) {
            if(this.compare(this.items[element], this.items[left]) === compareFn.MORE_THAN) {
                element = left;
            }
        } else if(right < size) {
            if(this.compare(this.items[element], this.items[right]) === compareFn.MORE_THAN) {
                element = right;
            }
        }
        if(index !== element) {
            this.swap(this.items, index, element);
            this.shiftDown(element);
        }
    }
}

const maxHp = new MaxHeap();

maxHp.insert(55);
maxHp.insert(45);
maxHp.insert(35);
maxHp.insert(25);
maxHp.insert(15);
maxHp.insert(10);
maxHp.insert(20);
maxHp.insert(30);
maxHp.insert(40);
maxHp.insert(50);
maxHp.insert(60);
maxHp.insert(70);
maxHp.insert(80);

const minHp = new MinHeap();

minHp.insert(55);
minHp.insert(45);
minHp.insert(35);
minHp.insert(25);
minHp.insert(15);
minHp.insert(10);
minHp.insert(20);
minHp.insert(30);
minHp.insert(40);
minHp.insert(50);
minHp.insert(60);
minHp.insert(70);
minHp.insert(80);

下一篇:【数据结构】自己动手使用JavaScript实现单向链表、双向链表(第四篇)-CSDN博客

注:以上,如有不合理之处,还请帮忙指出,大家一起交流学习~

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值