zoukankan      html  css  js  c++  java
  • javascript实现常见的数据结构

    电脑配置
    CPU:AMD X4 640
    内存: 宏想 DDR3 1600MHz 8g
    主板:华擎 980DE3/U3S3 R2.0
    浏览器:chrome 79.0.3945.88(正式版本) (64 位)

    时间测试函数

            function testRunTime(fn) {
                let start = new Date();
                let end = null;
                fn();
                end = new Date();
                console.log(`运行时间: ${(end - start) / 1000}秒`);
            }
    

    参考书籍:《算法第4版》


    数据结构

    存储相关
    集合 存储的元素唯一
    链表
    队列 先进先出
    后进先出
    最大堆 最大元素排最前面,数组实现

    排序相关
    数组

    查找相关
    并查集
    映射 根据key返回value
    二叉查找树
    自平衡二叉查找树
    红黑树
    哈希表

    数组

    // 数组
    class MyArray {
        constructor(capacity=10) {
            this._data = new Array(capacity);
            this._size = 0;
        }
        get length() {
            return this._size;
        }
        get capacity() {
            return this._data.length;
        }
    
        // 插入指定位置
        insert(index, e) { 
            if (index < 0 || index >= this._data.length) {
                throw new RangeError("index is invalid");
            }
            for (let i=this._size-1; i>=index; i--) {
                this._data[i+1] = this._data[i];
            }
            this._data[index] = e;
            this._size++;
        }
        // 添加到最后
        insertLast(e) { 
            this.insert(this._size, e);
        }
        // 添加到开头
        insertFirst(e) { 
            this.insert(0, e);
        }
    
        // 获取位置为index的元素
        get(index) { 
            if (index < 0 || index >= this._data.length) {
                throw new RangeError("index is invalid");
            } 
            return this._data[index];
        }
    
        // 删除位置为index的元素
        remove(index) { 
            if (index < 0 || index >= this._data.length) {
                throw new RangeError("index is invalid");
            } 
            let ret = this._data[index];
            for (let i=index,len=this._size-1; i<=len; i++) {
                this._data[i] = this._data[i+1];
            }
            this._size--;
            return ret;
        }
    
        // 更新元素
        set(index, e) { 
            if (index < 0 || index >= this._data.length) {
                throw new RangeError("index is invalid");
            } 
            if (this._data[index]) {
                this._data[index] = e;
            } else { // 不存在就添加
                this.insertLast(e);
            }
        }
    
        // 是否包含元素
        includes(e) {
            for (let i=0,len=this._size; i<len; i++) {
                if (Object.is(this._data[i], e)) {
                    return true;
                }
            }
            return false;
        }
    
        // 查找元素, 返回索引
        find(e) {
            for (let i=0,len=this._size; i<len; i++) {
                if (Object.is(this._data[i], e)) {
                    return i;
                }
            }
            return -1;
        }
    
        toString() {
            let str = "[";
            for (let i=0,len=this._size; i<len; i++) {
                str += this._data[i];
                if (i != len-1) {
                    str += ",";
                }
            }
            str += "]";
            return str;
        }
    }
    
    export default MyArray;
    



    链表

    单向链表

    // 链表
    class LinkedListNode {
        constructor(e, next=null) {
            this.e = e;
            this.next = next;
        }
    }
    class LinkedList {
        constructor() {
            this._dummyhead = new LinkedListNode(null);
            this._tail = null; // 尾指针
            this._size = 0;
        }
        get length() {
            return this._size;
        }
        get isEmpty() {
            return this._size == 0;
        }
    
        // 插入元素
        insert(index, e) {
            if (index < 0 || index>this._size) {
                throw new RangeError("index is invalid");
            }
            let cur = this._dummyhead;
            for (let i=0; i<index; i++) {
                cur = cur.next;
            }
            cur.next = new LinkedListNode(e, cur.next);
            if (this._size === index) {
                this._tail = cur.next;
            }
            this._size++;
        }
        // 插入表头
        insertFirst(e) {
            this._dummyhead.next = new LinkedListNode(e, this._dummyhead.next);
            if (this._size == 0) {
                this._tail = this._dummyhead.next;
            }
            this._size++;
        }
        // 插入表尾
        insertLast(e) {
            if (this._size == 0) {
                this._dummyhead.next = new LinkedListNode(e);
                this._tail = this._dummyhead.next;
            } else {
                this._tail.next = new LinkedListNode(e);
                this._tail = this._tail.next;
            }
            this._size++;
        }
        
        // 删除元素
        removeElement(e) {
            if (this.isEmpty) {
                return new Error("Element is empty");
            }
            let prev = this._dummyhead;
            while (prev != null) {
                if (Object.is(prev.next.e,e)) {
                    break;
                }
                prev = prev.next;
            }
            if (prev != null) {
                let ret = prev.next;
                prev.next = ret.next;
                ret.next = null;
                if (Object.is(ret.e, this._tail.e)) {
                    this._tail = prev;
                }
                this._size--;
                return ret;
            }
            return null;
        }
        // 根据位置删除元素
        removeIndex(index) {
            if (index < 0 || index>this._size) {
                throw new RangeError("index is invalid");
            }
            if (this.isEmpty) {
                return new Error("Element is empty");
            }
            let prev = this._dummyhead;
            let ret;
            for (let i=0; i<index; i++) {
                prev = prev.next;
            }
            ret = prev.next;
            prev.next = ret.next;
            ret.next = null;
            if (Object.is(ret.e, this._tail.e)) {
                this._tail = prev;
            }
            this._size--;
            return ret;
        }
    
        // 查找元素
        find(e) {
            let cur = this._dummyhead.next;
            let index = 0;
    
            while (cur !== null) {
                if (Object.is(cur.e, e)) {
                    break;
                }
                index++;
                cur = cur.next;
            }
            if (cur == null) {
                return -1;
            } else {
                return index;
            }
        }
        contains(e) {
            let result = this.find(e);
            return result != -1 ? true : false;
        }
        // 访问元素
        get(index) {
            if (index < 0 || index>this._size) {
                throw new RangeError("index is invalid");
            }
            let cur = this._dummyhead.next;
            for (let i=0; i<index; i++) {
                cur = cur.next;
            }
            return cur;
        }
        toString() {
            let res = "";
            let cur = this._dummyhead.next;
    
            for (let i=0,len=this._size; i<len; i++) {
                res += cur.e;
                if (i != len-1) {
                    res += " > ";
                }
                cur = cur.next;
            }
            return res;
        }
    }
    
    export default LinkedList;
    

    双向链表

    class LinkedListNode {
        constructor(item, next = null, prev = null) {
            this.item = item;
            this.next = next;
            this.prev = prev;
        }
    }
    // 双向链表
    class LinkedList {
        constructor() {
            this._dummyhead = new LinkedListNode(null);
            this._tail = null; // 尾指针
            this._size = 0;
        }
        get size() {
            return this._size;
        }
        get isEmpty() {
            return this._size === 0;
        }
        // 插入元素
        insert(index, e) {
            if (index < 0 || index > this._size) {
                throw new RangeError("index is invalid");
            }
            let cur = this._dummyhead;
            for (let i = 0; i < index; i++) {
                cur = cur.next;
            }
            cur.next = new LinkedListNode(e, cur.next, cur);
            if (cur.next.next) {
                cur.next.next.prev = cur.next;
            }
            if (this._size === index) {
                this._tail = cur.next;
            }
            this._size++;
        }
        // 插入表头
        unshift(e) {
            this._dummyhead.next = new LinkedListNode(e, this._dummyhead.next);
            if (this._size == 0) {
                this._tail = this._dummyhead.next;
            }
            this._size++;
        }
        // 插入表尾
        push(e) {
            if (this._size == 0) {
                this._dummyhead.next = new LinkedListNode(e, null, this._dummyhead);
                this._tail = this._dummyhead.next;
            } else {
                this._tail.next = new LinkedListNode(e, null, this._tail);
                this._tail = this._tail.next;
            }
            this._size++;
        }
        // 删除元素
        removeElement(e) {
            if (this.isEmpty) {
                return new Error("Element is empty");
            }
            let prev = this._dummyhead;
            while (prev != null) {
                if (prev.next !== null && Object.is(prev.next.item, e)) {
                    break;
                }
                prev = prev.next;
            }
            if (prev != null) {
                let ret = prev.next;
                prev.next = ret.next;
                if (ret.next) {
                    ret.next.prev = prev; // 调整上一个元素指向
                }
                ret.next = null;
                if (Object.is(ret.item, this._tail.item)) {
                    this._tail = prev;
                }
                this._size--;
                return ret;
            }
            return null;
        }
        // 根据位置删除元素
        removeIndex(index) {
            if (index < 0 || index > this._size) {
                throw new RangeError("index is invalid");
            }
            if (this.isEmpty) {
                return new Error("Element is empty");
            }
            let prev = this._dummyhead;
            let ret;
            for (let i = 0; i < index; i++) {
                prev = prev.next;
            }
            ret = prev.next;
            prev.next = ret.next;
            if (ret.next) {
                ret.next.prev = prev; // 调整上一个元素指向
            }
            ret.next = null;
            if (Object.is(ret.item, this._tail.item)) {
                this._tail = prev;
            }
            this._size--;
            return ret;
        }
        pop() {
            return this.removeIndex(this.size - 1);
        }
        shift() {
            return this.removeIndex(0);
        }
        // 查找元素
        find(e) {
            let cur = this._dummyhead.next;
            let index = 0;
    
            while (cur !== null) {
                if (Object.is(cur.item, e)) {
                    break;
                }
                index++;
                cur = cur.next;
            }
            if (cur == null) {
                return -1;
            } else {
                return index;
            }
        }
        contains(e) {
            let result = this.find(e);
            return result != -1 ? true : false;
        }
        // 访问元素
        get(index) {
            if (index < 0 || index > this._size) {
                throw new RangeError("index is invalid");
            }
            let cur = this._dummyhead.next;
            for (let i = 0; i < index; i++) {
                cur = cur.next;
            }
            return cur;
        }
        toString() {
            let res = "";
            let cur = this._dummyhead.next;
    
            for (let i = 0, len = this._size; i < len; i++) {
                res += cur.item;
                if (i != len - 1) {
                    res += " > ";
                }
                cur = cur.next;
            }
            return res;
        }
        iterator() { // 迭代器
            return {
                _item: this._dummyhead,
                next() {
                    if (this.hasNext()) {
                        let ret = this._item.next;
                        this._item = this._item.next;
                        return ret;
                    }
                    return null;
                },
                hasNext() {
                    return this._item.next !== null; 
                }
            }
        }
    }
    



    1. 数组实现
    class Stack {
        constructor() {
            this._data = [];
        }
        push(e) {
            this._data.push(e);
        }
        pop() {
            return this._data.pop();
        }
        peek() {
            return this._data[0];
        }
        isEmpty() {
            return this._data.length == 0;
        }
        get length() {
            return this._data.length;
        }
    }
    export default Stack;
    
    1. 链表实现
    import LinkedList from "./LinkedList.js";
    // 先引入链表
    
    class Stack {
       constructor() {
           this._data = new LinkedList();
       }
       push(e) {
           this._data.insertFirst(e);
       }
       pop() {
           return this._data.removeIndex(0);
       }
       peek() {
           return this._data.get(0);
       }
       get isEmpty() {
           return this._data.isEmpty;
       }
       get lenght() {
           return this._data.length;
       }
    }
    
    export default Stack;
    



    队列

    1. 数组实现
    class Queue {
       constructor() {
           this._data = [];
       }
       enqueue(e) {
           this._data.push(e);
       }
       dequeue() {
           return this._data.shift();
       }
       front() {
           return this._data[0];
       }
       get isEmpty() {
           return this._data.length == 0;
       }
       get length() {
           return this._data.length;
       }
       toString() {
           return "Front ["+this._data.toString+"]";
       }
    }
    
    export default Queue;
    
    1. 链表实现
    import LinkedList from "./LinkedList.js";
    
    class Queue {
        constructor() {
            this._data = new LinkedList();
        }
    
        // 进队
        enqueue(e) {
            this._data.insertLast(e);
        }
    
        // 出队
        dequeue() {
            return this._data.removeIndex(0);
        }
    
        // 队首元素
        front() {
            return this._data.get(0);
        }
        get isEmpty() {
            return this._data.length == 0;
        }
        get length() {
            return this._data.length;
        }
        toString() {
            return "Front "+this._data.toString();
        }
    }
    
    export default Queue;
    
    



    二叉查找树

    最好情况O(log2^n), 最坏情况 O(n)
    最坏的情况时会退化成链表。于是有了自平衡二叉树,在任何情况都能保持O(log2^n)

    class Node {
        constructor(key, value, size = 0) {
            this.key = key;
            this.value = value;
            this.size = size;
            this.left = this.right = null;
        }
    }
    class BST {
        constructor() {
            this.root = null;
        }
        get size() {
            return this._getSize(this.root);
        }
        _getSize(node) {
            if (node === null) {
                return 0;
            } else {
                return node.size;
            }
        }
        get(key) {
            function _get(node, key) {
                if (node === null) return null;
                if (key > node.key) {
                    return _get(node.right, key);
                } else if (key < node.key) {
                    return _get(node.left, key);
                } else {
                    return node.value;
                }
            }
            key = this._strToNum(key);
            return _get(this.root, key);
        }
        put(key, value) { 
            let _this = this;
            key = this._strToNum(key);
            this.root = _put(this.root, key, value);
            function _put(node, key, value) {
                if (node === null) { return new Node(key, value) };
                if (key < node.key) {
                    node.left = _put(node.left, key, value);
                } else if (key > node.key) {
                    node.right = _put(node.right, key, value);
                } else {
                    node.value = value;
                }
                node.size = _this._getSize(node.left) + _this._getSize(node.right) + 1;
                return node;
            }
        }
        contains(key) {
            return this.get(key) !== null;
        }
        delete(key) {
            // 删除思路:拿到被删除元素的右子树最小的元素,放到当前位置。因为被删除元素的右子树最小的元素 满足 大于左子树任意一个且小于右子树任意一个,不会打破顺序。
            let ret = null;
            let _this = this;
            key = this._strToNum(key);
            function _delete(node, key) {
                if (node === null) { return null }
                if (key < node.key) {
                    node.left = _delete(node.left, key);
                } else if (key > node.key) {
                    node.right = _delete(node.right, key)
                } else {
                    ret = node;
                    if (node.right === null) return node.left;
                    if (node.left === null) return node.right;
                    node = _this._min(node.right);
                    _this._deleteMin(node.right);
                }
                node.size = _this._getSize(node.left) + _this._getSize(node.right) + 1;
                return node;
            }
            this.root = _delete(this.root, key);
            return ret;
        }
        // 前序遍历
        preOrder() {
            _preOrder(this.root);
            function _preOrder(node) {
                if (node == null) {
                    return;
                }
                console.log(node.value);
                _preOrder(node.left);
                _preOrder(node.right);
            }
        }
        // 中序遍历
        inOrder() {
            _inOrder(this.root);
            function _inOrder(node) {
                if (node == null) {
                    return;
                }
                _inOrder(node.left);
                console.log(node.value);
                _inOrder(node.right);
            }
        }
        // 后序序遍历
        postOrder() {
            _postOrder(this.root);
            function _postOrder(node) {
                if (node == null) {
                    return;
                }
                _postOrder(node.left);
                _postOrder(node.right);
                console.log(node.value);
            }
        }
    
        // 层序遍历
        levelOrder() {
            let queue = []; // 引入队列
            let node;
            queue.push(this.root);
    
            while (queue.length) {
                node = queue.shift();
                console.log(node.value);
                if (node.left != null) {
                    queue.push(node.left);
                }
                if (node.right != null) {
                    queue.push(node.right);
                }
            }
        }
        _min(node = this.root) { // 是按键值转成数字的大小比较,并非按照value比较,所以最小的指的是键值转成数字后的大小
            if (node === null) { return null }
            return _min(node);
            function _min(node) {
                if (node.left === null) return node;
                return _min(node.left);
            }
        }
        _deleteMin(node = this.root) { // 最左边那个就是最小的
            let ret = this._min(this.root);
            let _this = this;
            if (ret === null) { return null }
            this.root = _deleteMin(node);
            return ret;
            function _deleteMin(node) {
                if (node === null) { return node }
                if (node.left === null) {
                    node = node.right;
                } else if (node.left.left === null) {
                    node.left = node.left.right;
                } else {
                    node.left = _deleteMin(node.left);
                }
                if (node) {
                    node.size = _this._getSize(node.left) + _this._getSize(node.right) + 1;
                }
                return node;
            }
        }
        _strToNum(key) { // 将字符串转成数字,方便比较大小
            if (typeof key !== "string") { throw ("key need string type") }
            let num = "";
            for (let i = 0; i < key.length; i++) {
                num += String(key.charAt(i).charCodeAt());
            }
            return Number(num);
        }
    }
    

    自平衡二叉查找树

    查找复杂度:O(log2^n)
    插入和删除都要判断平衡,进行相应的旋转

    // 学习前提:需要了解自平衡二叉树的4种倾斜状态、4种倾斜状态对应的旋转操作、判断是否平衡:左右子树高度差大于等于2为不平衡
    // key 最终以数字形式保存,目的是方便比较。如果key有用处于,可以在比较时再进行转换,但是这需要额外的成本
    // 自平衡的关键:旋转操作、用平衡因子判断属于哪种倾斜然后使用哪种旋转操作
    // 节点高度 =  子节点高度最高那个。默认为1
    class Node {
        constructor(key, value, height = 1) {
            this.key = key;
            this.value = value;
            this.height = height; 
            this.left = this.right = null;
        }
    }
    class AVL {
        constructor() {
            this.root = null;
        }
        get height() {
            return this._getHeight(this.root);
        }
        _getHeight(node) {
            if (node === null) {
                return 0;
            } else {return node.height}
        }
        _leftRotate(node) { // 右倾斜使用
            let n = node;
            node = node.right;
            n.right = node.left;
            node.left = n;
            n.height = Math.max(this._getHeight(n.left), this._getHeight(n.right))+1;
            node.height = Math.max(this._getHeight(node.left), this._getHeight(node.right))+1;
            return node;
        }
        _rightRotate(node) { // 左倾斜使用
            let n = node;
            node = node.left;
            n.left = node.right;
            node.right = n;
            n.height = Math.max(this._getHeight(n.left), this._getHeight(n.right))+1;
            node.height = Math.max(this._getHeight(node.left), this._getHeight(node.right))+1;
            return node;
        }
        _rlRotate(node) { // 右-左倾斜使用
            node.right = this._rightRotate(node.right);
            node = this._leftRotate(node);
            return node;
        }
        _lrRotate(node) { // 左-右倾斜使用
            node.left = this._leftRotate(node.left);
            node = this._rightRotate(node);
            return node;
        }
        _getBalanceFactor(node) { // 获取平衡因子用于判断倾斜状态
            if(node == null) {
                return 0;
            }
            return this._getHeight(node.left) - this._getHeight(node.right);
        }
        _rotate(node) { // 用于平衡二叉树
            let balanceFactor = this._getBalanceFactor(node);
            if (Math.abs(balanceFactor) > 1) { // 任意一边倾斜 任意一边高度差高于2
                if (balanceFactor > 1 && this._getBalanceFactor(node.left) >= 0) { // 左倾斜
                    node = this._rightRotate(node);
                }
                if (balanceFactor < -1 && this._getBalanceFactor(node.right) <= 0) { // 右倾斜
                    node = this._leftRotate(node);
                }
                if(balanceFactor > 1 && this._getBalanceFactor(node.left) < 0) { // 左-右倾斜
                    node = this._lrRotate(node);
                }
                if (balanceFactor < -1 && this._getBalanceFactor(node.right) > 0) { // 右-左倾斜
                    node = this._rlRotate(node);
                }
            }
            return node;
        }
        get(key) {
            function _get(node, key) {
                if (node === null) return null;
                if (key > node.key) {
                    return _get(node.right, key);
                } else if (key < node.key) {
                    return _get(node.left, key);
                } else {
                    return node.value;
                }
            }
            key = this._strToNum(key);
            return _get(this.root, key);
        }
        put(key, value) { 
            let _this = this;
            key = this._strToNum(key);
            this.root = _put(this.root, key, value);
            function _put(node, key, value) {
                if (node === null) { return new Node(key, value) };
                if (key < node.key) {
                    node.left = _put(node.left, key, value);
                } else if (key > node.key) {
                    node.right = _put(node.right, key, value);
                } else {
                    node.value = value;
                }
                node.height = Math.max(_this._getHeight(node.left), _this._getHeight(node.right))+1;
                return _this._rotate(node);
            }
        }
        contains(key) {
            return this.get(key) !== null;
        }
        delete(key) {
            // 删除思路:拿到被删除元素的右子树最小的元素,放到当前位置。
            // 因为被删除元素的右子树最小的元素 满足 大于左子树任意一个且小于右子树任意一个,不会打破顺序。
            let ret = null;
            let _this = this;
            key = this._strToNum(key);
            function _delete(node, key) {
                if (node === null) { return null }
                if (key < node.key) {
                    node.left = _delete(node.left, key);
                } else if (key > node.key) {
                    node.right = _delete(node.right, key)
                } else {
                    ret = node;
                    if (node.right === null) return node.left;
                    if (node.left === null) return node.right;
                    node = _this._min(node.right);
                    _this._deleteMin(node.right);
                }
                node.height = Math.max(_this._getHeight(node.left), _this._getHeight(node.right))+1;
                return _this._rotate(node);
            }
            this.root = _delete(this.root, key);
            return ret;
        }
        // 前序遍历
        preOrder() {
            _preOrder(this.root);
            function _preOrder(node) {
                if (node == null) {
                    return;
                }
                console.log(node.value);
                _preOrder(node.left);
                _preOrder(node.right);
            }
        }
        // 中序遍历
        inOrder() {
            _inOrder(this.root);
            function _inOrder(node) {
                if (node == null) {
                    return;
                }
                _inOrder(node.left);
                console.log(node.value);
                _inOrder(node.right);
            }
        }
        // 后序序遍历
        postOrder() {
            _postOrder(this.root);
            function _postOrder(node) {
                if (node == null) {
                    return;
                }
                _postOrder(node.left);
                _postOrder(node.right);
                console.log(node.value);
            }
        }
    
        // 层序遍历
        levelOrder() {
            let queue = []; // 引入队列
            let node;
            queue.push(this.root);
    
            while (queue.length) {
                node = queue.shift();
                console.log(node.value);
                if (node.left != null) {
                    queue.push(node.left);
                }
                if (node.right != null) {
                    queue.push(node.right);
                }
            }
        }
        _min(node = this.root) { // 是按键值转成数字的大小比较,并非按照value比较,所以最小的指的是键值转成数字后的大小
            if (node === null) { return null }
            return _min(node);
            function _min(node) {
                if (node.left === null) return node;
                return _min(node.left);
            }
        }
        _deleteMin(node = this.root) { // 最左边那个就是最小的
            let ret = this._min(this.root);
            let _this = this;
            if (ret === null) { return null }
            this.root = _deleteMin(node);
            return ret;
            function _deleteMin(node) {
                if (node === null) { return node }
                if (node.left === null) {
                    node = node.right;
                } else if (node.left.left === null) {
                    node.left = node.left.right;
                } else {
                    node.left = _deleteMin(node.left);
                }
                if (node) {
                    node.size = _this._getSize(node.left) + _this._getSize(node.right) + 1;
                }
                return node;
            }
        }
        _strToNum(key) { // 将字符串转成数字,方便比较大小
            if (typeof key !== "string") { throw ("key need string type") }
            let num = "";
            for (let i = 0; i < key.length; i++) {
                num += String(key.charAt(i).charCodeAt());
            }
            return Number(num);
        }
    }
    



    集合

    1. 数组实现
    class Set {
       constructor() {
           this._data = [];
       }
       contains(e) {
           return this._data.includes(e);
       }
       add(e) {
           if (!this.contains(e)) {
               this._data.push(e);
           }
       }
       remove(e) {
           let index = this._data.indexOf(e);
           this._data.splice(index,1);
           return this._data[index];
       }
       get length() {
           return this._data.length;
       }
       get isEmpty() {
           return this.length == 0;
       }
    }
    
    export default Set;
    
    1. 链表实现
    import LinkedList from "./LinkedList.js";
    
    class Set {
        constructor() {
            this._data = new LinkedList();
        }
        contains(e) {
            return this._data.contains(e);
        }
        add(e) {
            if (!this.contains(e)) {
                this._data.insertFirst(e);
            }
        }
        remove(e) {
            return this._data.removeElement(e);
        }
        get length() {
            return this._data.length;
        }
        get isEmpty() {
            return this.length == 0;
        }
    }
    
    export default Set;
    



    映射

    插入数据量 双向链表映射 数组映射 二叉查找树 js对象
    3万9.965秒0.108秒0.037秒0.018秒
    10万33.22秒0.247秒0.064秒0.043秒
    **双向链表实现** 查找和设置复杂度都是O(n) ```js class Node { constructor(key,value,prev=null,next=null) { this.key = key; this.value = value; this.next = next; this.prev = prev; } } class LinkedListMap { constructor() { this._root = null; this._tail = null; this._size = 0; } get size() {return this._size} get isEmpty() {return this._size === 0} contains(key) { if (typeof key !== "string") {throw("key need string type")} for(let cur=this._root; cur!=null; cur=cur.next) { if (cur.key === key) { return cur; } } return null; } get(key) { if (typeof key !== "string") {throw("key need string type")} let ret = this.contains(key); return ret ? ret.value : null; } put(key, value) { if (typeof key !== "string") {throw("key need string type")} let ret = this.contains(key); if (ret !== null) { // 有则更新 ret.value = value; } else { // 没有就创建 let node = new Node(key,value); if (this.size === 0) { this._root = node; this._tail = node; } else { node.prev = this._tail; this._tail.next = node; this._tail = node; } this._size++; } } delete(key) { if (typeof key !== "string") {throw("key need string type")} let node = this.contains(key); if (node !== null) { if (key === this._root.key) { let next = this._root.next; this._root.next = null; this._root = next; if (next != null) { next.prev = null; } else { // 只有一个节点 this._tail = null } } else { node.prev.next = node.next; if (key === this._tail.key) { this._tail = node.prev; } else { node.next = null; node.next.prev = null; } } this._size--; } }

    }

    **数组实现**
    查找和插入 log2^n
    ```javascript
    // key 最终以数字形式保存,目的是方便比较。如果key有用处于,可以在比较时再进行转换,但是这需要额外的成本
    // 使用两个数组,1保存key,2保存value。
    // 插入时使用二分法插入排序。插完元素后是有序的,key-value插入的位置在两个数组中也是一致的
    // 因为key-value位置一致,所以用二分法找到key的索引,对应的就是value数组的索引
    class ArrayMap {
        constructor() {
            this.keys = [];
            this.values = [];
        }
        get size() {return this.keys.length;}
        get isEmpty() {return this.keys.length === 0}
        get(key) {
            key = this._strToNum(key); 
            let i = this._search(key,0, this.size-1);
            return i !== -1 ? this.values[i] : null;
        }
        put(key, value) {
            key = this._strToNum(key);
            let index = this._search(key,0,this.size-1);
            if (index !== -1) {
                this.values[index] = value;
            } else {
                let begin = 0;
                let end = this.size-1;
                let middle = Math.floor(end/2);
                while (begin < end && this.keys[middle] != key) { // 二分排序法
                    if (this.keys[middle] > key) {
                        end = middle-1;
                    } else if (this.keys[middle] < key) {
                        begin = middle+1;
                    }
                    middle = Math.floor(begin+(end-begin)/2);
                }
                if (this.keys[middle] > key) { // 最后找到的中间值,只有两种结果
                    this.keys.splice(middle-1,0,key);
                    this.values.splice(middle-1,0,value);
                } else {
                    this.keys.splice(middle+1,0,key);
                    this.values.splice(middle+1,0,value);
                }
            }
        }
        contains(key) {
            key = this._strToNum(key);
            return this._search(key,0, this.size-1) != -1;
        }
        delete(key) {
            key = this._strToNum(key);
            let i = this._search(key,0, this.size-1);
            if (i!==-1) {
                this.keys.splice(i,1);
                return this.values.splice(i,1)[0];
           } else {
               return null
           }
        }
        _strToNum(key) { // 这里将key转成数字类型,这样就可以使用二分查找了
            if (typeof key !== "string") {throw("key need string type")}
            let num = "";
            for (let i=0; i<key.length; i++) {
                num += String(key.charAt(i).charCodeAt());
            }
            return Number(num);
        }
        _search(key, begin, end) { // 二分查找
            if (begin > end) {
                return -1;
            }
            let middle = Math.floor(begin+(end-begin)/2);
            if (key === this.keys[middle]) {
                return middle;
            } else if (key < this.keys[middle]) {
                return this._search(key, begin, middle-1);
            } else if (key > this.keys[middle]) {
                return this._search(key, middle+1, end);
            }
        }
    }
    



    最大堆

    从底部到顶部,O(log2^n)

    // 数组从1开始计算,这样左子元素索引=2*k,右子元素=2*k+1;
    // 如果从0开始计算,左子元素索引=2*k+1,右子元素=2*k+2;
    // 插入时进行上浮操作,移到相应位置
    // 弹出最大元素后再进行下沉操作,将现有最大元素排到顶部
    class MaxHeap {
        constructor() {
            this.list = [-1];
        }
        get isEmpty() {return this.list.length-1 === 0}
        get size() {return this.list.length-1}
        get max() {
            return this.list[1];
        }
        exch(k,p) {
            let list = this.list;
            let t = list[k];
            list[k] = list[p];
            list[p] = t;
        }
        // 上浮,大的往上走
        swim() {
            let k = this.size;
            let p = Math.floor(k/2);
            let list = this.list;
            while (p != 0 && list[k] > list[p]) {
                this.exch(k,p);
                k = p;
                p = Math.floor(k/2);
            }
        }
        // 下沉,小的往小走
        sink() {
            let k = 1;
            let list = this.list;
            let left = 2*k;
            let right = 2*k+1
            while (left <= this.size) {
                if (right <= this.size) {
                    if (list[left] > list[right] && list[k] < list[left]) {
                        this.exch(left,k);
                        k = left;
                    } else if (list[left] < list[right] && list[k] < list[right]) {
                        this.exch(right,k);
                        k = right;
                    } else {
                        break;
                    }
                } else {
                    if (list[left] > list[k]) {
                        this.exch(left,k);
                        k = left;
                    }
                }
                left = 2*k;
                right = 2*k+1
            }
        }
        push(item) {
            this.list.push(item);
            this.swim();
        }
        pop() {
            let ret = this.list[1];
            this.list[1] = this.list[this.size];
            this.list.splice(this.size,1);
            this.sink();
            return ret;
        }
    }
    



    优先队列

    import MaxHeap from "./MaxHeap.js";
    
    class PriorityQueue {
        constructor() {
            this._data = new MaxHeap();
        }
        get length() {
            return this._data.length;
        }
        get isEmpty() {
            return this._data.isEmpty;
        }
        enqueue(e) {
            this._data.add(e);
        }
        dequeue() {
            return this._data.remove();
        }
        front() {
            return this._data.get();
        }
    }
    
    export default PriorityQueue;
    



    前缀树

    class Node {
        constructor(isWord=false) {
            this.isWord = isWord;
            this.next = {};
        }
    }
    class Trie {
        constructor() {
            this._root = new Node();
            this._size = 0;
        }
        get size() {
            return this._size;
        }
        add(word) {
            let cur = this._root;
            for (let i=0; i<word.length; i++) {
                let key = word.charAt(i);
                if (cur.next[key] == undefined) {
                    cur.next[key] = new Node();
                }
                cur = cur.next[key];
            }
            if (!cur.isWord) {
                cur.isWord = true;
                this._size++;
            }
        }
        contains(word) {
            let cur = this._root;
            for(let i=0; i<word.length; i++) {
                let key = word.charAt(i);
                if (cur.next[key] == undefined) {
                    return false;
                }
                cur = cur.next[key];
            }
            return cur.isWord;
        }
        isPrefix(prefix) {
            let cur = this._root;
            for(let i=0; i<prefix.length; i++) {
                let key = prefix.charAt(i);
                if (cur.next[key] == undefined) {
                    return false;
                }
                cur = cur.next[key];
            }
            return true;
        }
    }
    
    export default Trie;
    



    并查集

    class UnionFind {
        constructor(size) { // size 集合数量
            if (!size) {
                throw new TypeError("size is empty");
            }
            this._parent = new Array(size);
            this._rank = new Array(size); // 优先级
    
            for (let i=0; i<this._parent.length; i++) {
                this._parent[i] = i; 
                this._rank[i] = 1;
            }
        }
        get size() {
            return this._parent.length;
        }
        _find(p) { // 查找所属集合
            if (p<0 && p>=parent.length) {
                throw new RangeError(`${p} is invalid`);
            }
            while (p != this._parent[p]) {
                this._parent[p] = this._parent[this._parent[p]];
                p = this._parent[p];
            }
            return p;
        }
        isConnected(p, q) {
            return this._find(p) == this._find(q);
        }
        unionElement(p, q) {
            let pRoot = this._find(p);
            let qRoot = this._find(q);
    
            if (pRoot == qRoot) {
                return;
            }
            if (this._rank[pRoot] < this._rank[qRoot]) { // 小的合并到大的集合
                this._parent[pRoot] = qRoot;
            } else if (this._rank[pRoot] > this._rank[qRoot]) {
                this._parent[qRoot] = pRoot;
            } else {
                this._parent[qRoot] = pRoot;
                this._rank[pRoot] += 1;
            }
        }
    
    }
    
    export default UnionFind;
    



    哈希表

    class HashTable {
        constructor(capacity) {
            if (!capacity) {
                throw new RangeError("capacity is empty");
            }
            this._data = new Array(capacity);
            this._size = 0;
            for (let i=0; i<capacity; i++) {
                this._data[i] = {}; // 冲突时保持到对象里
            }
        }
        hashCode(key) { // 根据不同场景设计不同的哈希函数
            let hash = 5381;
            for (let i = 0; i < key.length; i++) {
                hash = ((hash << 5) + hash) + key.charCodeAt(i);
            }
            return Math.abs(hash % this._data.length);
        }
        get size() {
            return this._size;
        }
        add(key, value) {
            let map = this._data[this.hashCode(key)];
            if (map[key]) {
                map[key] = value;
            } else {
                map[key] = value;
                this._size++;
            }
        }
        remove(key) {
            let map = this._data[this.hashCode(key)];
            let ret = map[key];
            if (map[key]) {
                delete map[key];
                this._size--;
            }
            return ret;
        }
        get(key) {
            return this._data[this.hashCode(key)][key];
        }
        set(key, value) {
            let map = this._data[this.hashCode(key)];
            if (!map[key]) {
                throw new RangeError("key is not found");
            }
            map[key] = value;
        }
        contains(key) {
            return !!(this.get(key));
        }
    }
    
    export default HashTable;
    



    // 邻接矩阵
    class DenseGraph {
        constructor(n, directed) {
            this._n = n; // 点
            this._m = 0; // 边
            this._directed = directed; // 是否有向图
            this._g = [];
            for (let i = 0; i < n; i++) {
                let arr = new Array(n).fill(false);
                this._g.push(arr);
            }
        }
        get V() { return this._n }
        get E() { return this._m }
        addEdge(v, w) {
            if (this.hasEdge(v, w)) return;
    
            this._g[v][w] = true;
            if (!this._directed) {
                this._g[w][v] = true;
            }
            this._m++;
        }
        hasEdge(v, w) {
            if (v < 0 || v >= this._n) throw RangeError(v + " not exist");
            if (w < 0 || w >= this._n) throw RangeError(w + " not exist");
            return this._g[v][w];
        }
        DFS(v) { // 深度优先遍历
            if (!this._g[0].includes(v)) {throw new RangeError(v+" is not exist")}
            let visited = [];
            let _this = this;
            _dfs(v);
            function _dfs(v) {
                visited[v] = true;
                console.log(v);
                for (let i = v; i < _this._g.length; i++) {
                    for (let j = 0; j < _this._g[i].length; j++) {
                        if (_this._g[i][j] && !visited[j]) {
                            _dfs(j);
                        }
                    }
                }
                // 防止孤立的点没被遍历到
                // for (let i = 0; i < _this._g.length; i++) {
                //     for (let j = 0; j < _this._g[i].length; j++) {
                //         if (_this._g[i][j] && !visited[j]) {
                //             _dfs(j);
                //         }
                //     }
                // }
    
            }
        }
        BFS(v) { // 广度优先遍历
            if (!this._g[0].includes(v)) {throw new RangeError(v+" is not exist")}
            let queue = [];
            let visited = [];
            let node;
            queue.push(v);
            while (queue.length) {
                visited[v] = true;
                node = queue.shift();
                console.log(node);
                for (let i=node; i<this._g.length; i++) {
                    for (let j=0; j<this._g[i].length; j++) {
                        if (this._g[i][j] && !visited[j]) {
                            queue.push(j);
                            visited[j] = true;
                        }
                    }
                }
            }
        }
    }
    
    // 邻接表
    class SparseGraph {
        constructor(directed) {
            this._n = []; // 点
            this._edge = {};
            this._m = 0; // 边
            this._directed = directed; // 是否有向图
        }
        get V() { return this._n.length }
        get E() { return this._m }
        addEdge(v, w) {
            if (!this._edge[v]) {
                this._edge[v] = new Set();
                this._n.push(v);
            }
            if (!this._edge[v].has(w)) {
                this._edge[v].add(w);
                this._m++;
            }
            if (!this._directed) {
                if (!this._edge[w]) {
                    this._edge[w] = new Set();
                    this._n.push(w);
                }
                this._edge[w].add(v);
            }
        }
        DFS(v) {
            if (!this._edge[v]) {throw new RangeError(v+" is not exist")}
            let visited = {};
            let _this = this;
            _dfs(v);
            function _dfs(v) {
                visited[v] = true;
                console.log(v);
                for (let key in _this._edge) {
                    _this._edge[key].forEach(item=>{
                        if (!visited[item]) {
                            _dfs(item);
                            visited[item] = true;
                        }
                    })
                }
            }
        }
        BFS(v) {
            if (!this._edge[v]) {throw new RangeError(v+" is not exist")}
            let visited = {};
            let queue = [];
            let node;
            visited[v] = true;
            queue.push(v);
    
            while (queue.length) {
                node = queue.shift();
                console.log(node);
                this._edge[node].forEach(item=>{
                    if (!visited[item]) {
                        queue.push(item);
                        visited[item] = true;
                    }
                })
            }
        }
    }
    

    红黑树

    // 前提
    // 了解红黑树的性质,满足红黑树的性质就达到了平衡
    // 了解插入时不满足红黑树性质进行的操作(颜色翻转、旋转操作)
    const RED = true;
    const BLACK = false;
    class Node {
        constructor(key, value) {
            this.key = key;
            this.value = value;
            this.left = null;
            this.right = null;
            this.color = RED;
        }
    }
    class RBTree {
        constructor() {
            this.root = null;
            this.size = 0;
        }
        get getsize() {
            return this.size;
        }
        get isEmpty() {
            return this.size == 0;
        }
        put(key, value) {
            let _this = this;
            this.root = put(this.root, this._strToNum(key), value);
            this.root.color = BLACK;
            function put(node, key, value) {
                if (node == null) {
                    _this.size++;
                    //默认红色
                    return new Node(key, value);
                }
    
                if (key < node.key) {
                    node.left = put(node.left, key, value);
                } else if (key > node.key) {
                    node.right = put(node.right, key, value);
                } else {
                    node.value = value;
                }
                if (_this.isRed(node.right) && !_this.isRed(node.left)) {
                    node = _this.leftRotate(node);
                }
                if (_this.isRed(node.left) && _this.isRed(node.left.left)) {
                    node = _this.rightRotate(node);
                }
                if (_this.isRed(node.left) && _this.isRed(node.right)) {
                    _this.flipColors(node);
                }
    
                return node;
            }
        }
        remove(key) {
            let node = this.getNode(this.root, this._strToNum(key));
            let _this = this;
            if (node != null) {
                this.root = remove(this.root, this._strToNum(key));
                return node.value;
            }
            function remove(node, key) {
                if (node == null) {
                    return null;
                }
                if (key < node.key) {
                    node.left = remove(node.left, key);
                    return node;
                } else if (key > node.key) {
                    node.right = remove(node.right, key);
                    return node;
                } else {
                    if (node.left == null) {
                        let rightNode = node.right;
                        node.right = null;
                        _this.size--;
                        return rightNode;
                    } else if (node.right == null) {
                        let leftNode = node.left;
                        node.left = null;
                        _this.size--;
                        return leftNode;
                    } else {
                        //待删除节点左右子树都不为空的情况
                        //调用minimum方法,寻找右子树中的最小节点
                        let successor = _this.minimum(node.right);
                        //removeMin操作中已经维护过size了
                        successor.right = _this.removeMin(node.right);
                        successor.left = node.left;
                        node.left = node.right = null;
                        return successor;
                    }
                }
            }
            return null;
        }
        get(key) {
            let node = this.getNode(this.root, this._strToNum(key));
            return node == null ? null : node.value;
        }
        contains(key) {
            return this.getNode(this.root, this._strToNum(key)) != null;
        }
        // 前序遍历
        preOrder() {
            _preOrder(this.root);
            function _preOrder(node) {
                if (node == null) {
                    return;
                }
                console.log(node.value);
                _preOrder(node.left);
                _preOrder(node.right);
            }
        }
        // 中序遍历
        inOrder() {
            _inOrder(this.root);
            function _inOrder(node) {
                if (node == null) {
                    return;
                }
                _inOrder(node.left);
                console.log(node.value);
                _inOrder(node.right);
            }
        }
        // 后序序遍历
        postOrder() {
            _postOrder(this.root);
            function _postOrder(node) {
                if (node == null) {
                    return;
                }
                _postOrder(node.left);
                _postOrder(node.right);
                console.log(node.value);
            }
        }
    
        // 层序遍历
        levelOrder() {
            let queue = []; // 引入队列
            let node;
            queue.push(this.root);
    
            while (queue.length) {
                node = queue.shift();
                console.log(node.value);
                if (node.left != null) {
                    queue.push(node.left);
                }
                if (node.right != null) {
                    queue.push(node.right);
                }
            }
        }
        // 左旋
        leftRotate(node) {
            let x = node.right;
            node.right = x.left;
            x.left = node;
            x.color = node.color;
            node.color = RED;
    
            return x;
        }
        // 右旋
        rightRotate(node) {
            let x = node.left;
            node.left = x.right;
            x.right = node;
            x.color = node.color;
            node.color = RED;
    
            return x;
        }
        // 颜色反转
        flipColors(node) {
            node.color = RED;
            node.right.color = BLACK;
            node.left.color = BLACK;
        }
        // 判断节点node的颜色
        isRed(node) {
            if (node == null) {
                return BLACK;
            }
            return node.color;
        }
        _strToNum(key) { // 将字符串转成数字,方便比较大小
            if (typeof key !== "string") { throw ("key need string type") }
            let num = "";
            for (let i = 0; i < key.length; i++) {
                num += String(key.charAt(i).charCodeAt());
            }
            return Number(num);
        }
    
        minimum(node = this.root) {
            if (this.size === 0) throw ("size 0");
            return minimum(node);
            function minimum(node) {
                if (node.left == null) {
                    return node;
                }
                return minimum(node.left);
            }
        }
        removeMin(node = this.root) {
            let _this = this;
            return removeMin(node);
            function removeMin(node) {
                if (node.left == null) {
                    let rightNode = node.right;
                    node.right = null;
                    _this.size--;
                    return rightNode;
                }
                node.left = removeMin(node.left);
                return node;
            }
        }
        // 返回以node为根节点的二分搜索树中key所在的节点
        getNode(node, key) {
            if (node == null) {
                return null;
            }
            if (key == node.key) {
                return node;
            } else if (key < node.key) {
                return this.getNode(node.left, key);
            } else {
                return this.getNode(node.right, key);
            }
        }
    
    }
    

    算法分析
    数据结构与算法可视化

  • 相关阅读:
    flash 3d基础学习
    3d中的镜头
    [转]Android Canvas 切割 clipRect
    绘制球形
    绘制圆筒
    stage3d学习笔记1
    (转)Region.Op效果解析
    游戏中的镜头
    无向网的最小生成树——Prim算法(转)
    最短路径之——Dijkstra算法(转)
  • 原文地址:https://www.cnblogs.com/niepeizhi/p/12068399.html
Copyright © 2011-2022 走看看