数据结构在JavaScript中的体现

一.概述


        数据结构是计算机中存储、组织数据的方式。通常情况下,精心选择的数据结构可以带来最优效率的算法,其实算法并不是一个很高级的东西,它充斥在每一种代码组织方式中;而且各种语言关于数据结构方面的内容都是大同小异的,会了一种语言的数据结构方面的内容就可以快速掌握其它语言的的数据结构;有一部分人对JavaScript有偏见,觉得这种语言没有档次,但又有多少人在学完JavaScript敢说精通它。

二.见识数据结构


(1)>>数组


        你没有看错,常见的数组就是一种数据结构,对于数组就是掌握一下它的各种方法,如push(),pop(),shift(),unshift(),indexOf(),sort(),slice(),splice()等,在这里就不赘述了。

(2)>>栈


 A.图解

               遵循的是后进先出

  B.封装代码 

class Stack {
    //加#是为了保证其是私有属性,不让外界随意调用
    #items = [];
    pop() {
        return this.#items.pop()
    }
    push(data) {
        return this.#items.push(data)
    }
    //返回栈顶
    peek() {
        return this.#items.at(-1)
    }
    isEmpty() {
        return this.#items.length > 0 ? false : true
    }
    size() {
        return this.#items.length
    }
    clear() {
        this.#items = []
    }
    toString(){
        return this.#items.join(' ')
    }
}

C.应用场景

        将十进制数转换为其它进制的数时用到了辗转相除法,刚好是把得到的余数从后到前输出得到对应进制下的数,如果把这些数从前到后推到栈里,再取出来岂不妙哉。

function convert(decNumber, binaryNumber) {
    let number = decNumber
    let stack = new Stack()
    let string = ''
    //防止转换成十六进制的时候乱码
    let baseString = '0123456789ABCDEF'
    while (number > 0) {
        stack.push(number % binaryNumber)
        number = Math.floor(number / binaryNumber)
    }
    while (!(stack.isEmpty())) {
        string += baseString[stack.pop()]
    }
    return string
}

console.log(convert(50, 2));

(3)>>队列


 A.图解

        先进先出,后端进,前端出,类似于排队

 B.封装代码

             有缺点的封装方式
class Queue {
    #items = [];
    //一旦元素变多,还用shift会造成运行效率低
    deleteQueue() {
        return this.#items.shift()
    }
    enterQueue(data) {
        return this.#items.push(data)
    }
    //返回队头
    frontQueue() {
        return this.#items.at(0)
    }
    isEmpty() {
        return this.#items.length > 0 ? false : true
    }
    size() {
        return this.#items.length
    }
    clear() {
        this.#items = []
    }
    toString() {
        return this.#items.join(' ')
    }
}
        修正之后的封装方式 
class Queue {
    #items = {};
    #count = 0;
    #lowCount = 0;
    //出队
    deleteQueue() {
        if (this.isEmpty()) {
            return undefined
        }
        let res = this.#items[this.#lowCount]
        delete this.#items[this.#lowCount]
        this.#lowCount++
        return res
    }
    //进队
    enterQueue(data) {
        this.#items[this.#count] = data
        this.#count++
    }
    //返回队头
    frontQueue() {
        return this.#items[this.#lowCount]
    }
    isEmpty() {
        return this.size === 0
    }
    size() {
        return this.#count - this.#lowCount
    }
    clear() {
        this.#items = {}
        this.#count = 0
        this.#lowCount = 0
    }
    toString() {
        let str = ""
        for (let i = this.#lowCount; i < this.#count; i++) {
            str += `${this.#items[i]} `
        }
        return str.trim()
    }
}

C.应用场景 

类似于击鼓传花,传指定次数,最终东西在谁手上谁淘汰,一直淘汰到队列里只剩一个人为最终的胜者

function game(list, num) {
    let queue = new Queue()
    for (let i = 0; i < list.length; i++) {
        queue.enterQueue(list[i])
    }
    while (queue.size() > 1) {
        for (i = 0; i < num; i++) {
            queue.enterQueue(queue.deleteQueue())
        }
        console.log(queue.deleteQueue(), '淘汰');
    }
    console.log(queue.deleteQueue());
    //最终获胜者
    return queue.deleteQueue()
}

game(['aks', 'uej', 'jsm', 'duj', 'llq'], 7)

D.双端队列

与一般的队列有所不同的情况是,可以从队头进队,队尾可以出队,简而言之就是两端都能进出队伍。

class DeQueue {
    #items = {};
    #count = 0;
    #lowCount = 0;
    removeFront() {
        if (this.isEmpty()) {
            return undefined
        }
        let res = this.#items[this.#lowCount]
        delete this.#items[this.#lowCount]
        this.#lowCount++
        return res
    }
    addBack(data) {
        this.#items[this.#count] = data
        this.#count++
    }
    //在队头添加
    addFront(data) {
        if (this.isEmpty()) {
            this.addBack()
        } else {
            if (this.#lowCount > 0) {
                this.#lowCount--
                this.#items[this.#lowCount] = data
            } else {
                for (let i = this.#count; i > 0; i--) {
                    this.#items[i] = this.#items[i - 1]
                }
                this.#items[0] = data
                this.#count++
            }
        }

    }
    //在队尾删除
    removeBack() {
        if (this.isEmpty()) {
            return
        } else {
            this.#count--
            let res = this.#items[this.#count]
            delete this.#items[this.#count]
            return res
        }
    }
    //返回队头
    peekFront() {
        return this.#items[this.#lowCount]
    }
    //返回队尾
    peekBack() {
        return this.#items.at(-1)
    }
    isEmpty() {
        return this.size === 0
    }
    size() {
        return this.#count - this.#lowCount
    }
    clear() {
        this.#items = {}
        this.#count = 0
        this.#lowCount = 0
    }
    toString() {
        let str = ""
        for (let i = this.#lowCount; i < this.#count; i++) {
            str += `${this.#items[i]} `
        }
        return str.trim()
    }
}


//回文应用
function test(str) {
    //将输入有空格的字符串转化为无空格的
    const lowStr = str.toLocaleLowerCase().split(' ').join('') 
    let dequeue = new DeQueue()
    for (let i = 0; i < lowStr.length; i++) {
        dequeue.addBack(lowStr[i])
    }
    while (dequeue.size() > 1) {
        if (dequeue.removeFront() !== dequeue.removeBack()) {
            console.log('不是回文');
            break
        } else {
            console.log('是回文结构');
        }
    }
}

test('dadadb') //不是回文

(4)>>链表


1.单链表

A.图解

        可以把next看成一个指针,其能指向表中下一个存储的数据

B.封装代码
//根据节点的需要创建相应的元素
class Node {
    constructor(element) {
        this.element = element
        this.next = null
    }
}
//单链表
class LinkList {
    constructor() {
        this.head = null
        this.count = 0
    }
    //从表尾放入新节点
    push(element) {
        const node = new Node(element)
        if (this.head === null) {
            this.head = node
        } else {
            let current = this.head
            while (current.next != null) {
                current = current.next
            }
            current.next = node
        }
        this.count++
    }

    size() {
        return this.count
    }

    isEmpty() {
        return this.size() === 0
    }

    //指定位置删除
    removeAt(index) {
        if (index >= 0 && index < this.count) {
            let current = this.head
            if (index === 0) {
                this.head = this.head.next
            } else {
                let previous
                for (let i = 0; i < index; i++) {
                    previous = current
                    current = current.next
                }
                previous.next = current.next
            }
            this.count--
            return current.element
        }
        return undefined
    }
    //同样也是指定位置删除,但用到了后面封装的getNodeAt方法
    removeAt2(index) {
        if (index >= 0 && index < this.count) {
            let current = this.head
            if (index === 0) {
                this.head = this.head.next
            } else {
                let previous = this.getNodeAt(index - 1)
                current = previous.next
                previous.next = current.next
            }
            this.count--
            return current.element
        }
        return undefined
    }
    //根据索引值找到相应的节点
    getNodeAt(index) {
        if (index >= 0 && index < this.count) {
            let node = this.head
            for (let i = 0; i < index; i++) {
                node = node.next
            }
            return node
        }
        return undefined
    }


    indexOf(element) {
        let current = this.head
        for (let i = 0; i < this.count; i++) {
            //防止其直接输入一个对象变量
            if (JSON.stringify(element) === JSON.stringify(current.element)) {
                return i
            }
            current = current.next
        }
        return -1
    }
    //指定元素删除
    remove(element) {
        let index = this.indexOf(element)
        let removeElement = this.removeAt(index)
        return removeElement
    }

    insert(element, index) {
        if (index >= 0 && index <= this.count) {
            const node = new Node(element)
            if (index === 0) {
                let current = this.head
                node.next = current
                this.head = node
                this.count++
            } else {
                let previous = this.getNodeAt(index - 1)
                let current = previous.next
                previous.next = node
                node.next = current
                this.count++
            }
            return true
        }
        return false
    }
}

2.双向链表

A.图解        

节点除了存储数据以外,还有两个指针分别指向前一个节点地址(prev)和下一个节点地址(next) 

B.封装代码
//前人栽树,后人乘凉,继承自之前的Node类
class DoubleNode extends Node {
    constructor(element) {
        super(element)
        this.prev = null
    }
}

//继承自LinkList类加方法重写
class DoubleLinkList extends LinkList {
    constructor() {
        super()
        this.tail = null
    }
    push(element) {
        const doubleNode = new DoubleNode(element)
        if (this.head === null) {
            this.head = doubleNode
            this.tail = doubleNode
        } else {
            this.tail.next = doubleNode
            doubleNode.prev = this.tail
            this.tail = doubleNode
        }
        this.count++
    }

    insert(element, index) {
        if (index >= 0 && index <= this.count) {
            const doubleNode = new DoubleNode(element)
            if (index === 0) {
                //分链表是否有元素
                if (this.head === null) {
                    this.head = doubleNode
                    this.tail = doubleNode
                } else {
                    this.head.prev = doubleNode
                    doubleNode.next = this.head
                    this.head = doubleNode
                }
            } else if (index === this.count) {
                this.tail.next = doubleLinkList
                doubleLinkList.prev = this.tail
                this.tail = doubleLinkList
            } else {
                let previous
                let current = this.head
                for (let i = 0; i < index; i++) {
                    current = current.next
                    previous = current.prev
                }
                current.prev = doubleNode
                doubleNode.next = current
                doubleNode.prev = previous
                previous.next = doubleNode
            }
            this.count++
            return true
        }
        return false
    }

    removeAt(index) {
        if (index >= 0 && index < this.count) {
            let current = this.head
            if (index === 0) {
                this.head = current.next
                if (this.count === 1) {
                    this.tail = null
                } else {
                    this.head.prev = null
                }
            } else if (index === this.count - 1) {
                current = this.tail
                this.tail = current.prev
                this.tail.next = null
            } else {
                current = this.getNodeAt(index)
                let previous = current.prev
                let future = current.next
                previous.next = future
                future.prev = previous
            }
            this.count--
            return current.element
        }
        return undefined
    }

}

3.循环链表 

A.图解

B.封装代码
//循环链表类继承自单链表类
class CirculateLinkList extends LinkList {
    constructor() {
        super()
    }
    push(element) {
        const node = new Node(element)
        let current
        if (this.head === null) {
            this.head = node
        } else {
            current = this.getNodeAt(this.size() - 1)
            current.next = node
        }
        node.next = this.head
        this.count++
    }

    insert(element, index) {
        if (index >= 0 && index <= this.count) {
            const node = new Node(element)
            let current = this.head
            if (index === 0) {
                if (this.head === null) {
                    this.head = node
                    node.next = this.head
                } else {
                    node.next = this.head
                    current = this.getNodeAt(this.size() - 1)
                    this.head = node
                    current.next = node
                }
            } else {
                if (index === this.count) {
                    current = this.getNodeAt(index - 1)
                    current.next = node
                    node.next = this.head
                } else {
                    let previous = this.getNodeAt(index - 1)
                    previous.next = node
                    node.next = previous.next
                }
            }
            this.count++
            return true
        }
        return false
    }

    removeAt(index) {
        if (index >= 0 && index < this.count) {
            let current = this.head
            if (index === 0) {
                if (this.count === 1) {
                    this.head = null
                } else {
                    let last = this.getNodeAt(this.size() - 1)
                    this.head = current.next
                    last.next = this.head
                }
            } else {
                let previous = this.getNodeAt(index - 1)
                current = previous.next
                previous.next = current.next
            }
            this.count--
            return current.element
        }
        return undefined
    }
}

(5)>>集合


Set结构,其实已经是JavaScript里封装好的,它是以值:值进行存储,且存入的值不能够重复

A.封装代码
class Set {
    items = {}
    add(element) {
        if (!this.has(element)) {
            this.items[element] = element
            return true
        }
        return false
    }
    delete(element) {
        if (this.has(element)) {
            delete this.items[element]
            return true
        }
        return false
    }
    has(element) {
        return element in this.items
    }
    clear() {
        this.items = {}
    }
    size() {
        return Object.keys(this.items).length
    }
    values() {
        return Object.values(this.items)
    }
}

const mySet = new Set()
let arr = [2, 1, 3, 3, 4, 5, 2, 1]
arr.forEach((item) => {
    mySet.add(item)
})
console.log(mySet.values());//[ 1, 2, 3, 4, 5 ]
 B.原装set使用

Set结构生成的是一个迭代器的结构,并且由于是集合,可以进行相关的并集交集差集等运算,可以进行相关的,详细的相关使用请查看下方代码

let mySet = new Set()
mySet.add(1)
mySet.add(2)
mySet.add(3)

let item = mySet.values() //生成的是一个迭代器
console.log(item); //[Set Iterator] { 1, 2, 3 }
console.log(item.next()); //{ value: 1, done: false }
console.log(item.next()); //{ value: 2, done: false }
console.log(item.next()); //{ value: 3, done: false }

// for (let i of item) {
//     console.log(i);
// } //1 2 3

// console.log([...item]);   //[ 1, 2, 3 ]


// const A = new Set([1, 2, 3, 4])
// const B = new Set([2, 3, 4, 5])
// //取并集
// const C = new Set([...A, ...B])
// console.log(C);  //Set(5) { 1, 2, 3, 4, 5 }

// //取交集
// const D = new Set([...A].filter(item => B.has(item)))
// console.log(D);  //Set(3) { 2, 3, 4 }

// //取差集
// const E = new Set([...A].filter(item => !B.has(item)))
// console.log(E);  //Set(1) { 1 }

(6)>>字典

字典和集合很相似,集合以[值,值]的形式存储元素,字 典则是以[键,值]的形式来存储元素。字典也称作映射、符号表或关联数组。

A.字典的封装

class Dictionary {
    table = {}
    //保证当存入的键是对象的时候,强制它转换为json字符串的形式
    toStrFn(item) {
        if (item === null) {
            return "null"
        } else if (item === undefined) {
            return "undefined"
        } else if (typeof item === 'string' || item instanceof String) {
            return item
        }
        return JSON.stringify(item)
    }
    hasKey(key) {
        return this.table[this.toStrFn(key)] != null
    }
    set(key, value) {
        if (key != null && value != null) {
            const tableKey = this.toStrFn(key)
            // this.table[tableKey] = value
            this.table[tableKey] = new ValuePair(key, value)

            return true
        }
        return false
    }
    get(key) {
        let result = this.table[this.toStrFn(key)]
        return result == null ? undefined : result.value
    }
    remove(key) {
        if (this.hasKey(key)) {
            delete this.table[this.toStrFn(key)]
            return true
        }
        return false
    }
    keys() {
        return this.keyValues().map(item => item.key)
    }
    values() {
        return this.keyValues().map(item => item.value)
    }
    keyValues() {
        return Object.values(this.table)
    }
    size() {
        return Object.keys(this.table).length
    }
    isEmpty() {
        return this.size() === 0
    }
    clear() {
        this.table = {}
    }
    forEach(ch) {
        const valuePair = this.keyValues()
        for (let i = 0; i < valuePair; i++) {
            ch(valuePair[i].key, valuePair[i].value)
        }
    }
}

class ValuePair {
    constructor(key, value) {
        this.key = key
        this.value = value
    }
}

B.散列表

HashMap 类,它是 Dictionary 类的一种散列表 实现方式。.散列算法的作用是尽可能快地在数据结构中找到一个值。这样在面对海量数据的时候可以加快查询的速度

class HashTable {
    table = {}
    toStrFn(item) {
        if (item === null) {
            return "null"
        } else if (item === undefined) {
            return "undefined"
        } else if (typeof item === 'string' || item instanceof String) {
            return item
        }
        return JSON.stringify(item)
    }

    // hashCode(key) {
    //     if (typeof key === 'number') {
    //         return key
    //     } else {
    //         const tableKey = this.toStrFn(key)
    //         let hash = 0
    //         for (let i = 0; i < tableKey.length; i++) {
    //             hash += tableKey.charCodeAt(i)
    //         }
    //         return hash % 35
    //     }
    // }
    //将对应字符串或对象转成的字符串的ASCII值进行转换生成相应的数值
    hashCode(key) {
        const tableKey = this.toStrFn(key)
        let hash = 5381
        for (let i = 0; i < tableKey.length; i++) {
            hash = (hash * 33) + tableKey.charCodeAt(i)
        }
        return hash % 1013
    }

    set(key, value) {
        if (key != null && value != null) {
            let position = this.hashCode(key)
            this.table[position] = new ValuePair(key, value)
        }
    }

    get(key) {
        let result = this.table[this.hashCode(key)]
        return result == null ? undefined : result.value
    }

    remove(key) {
        if (this.table[this.hashCode(key)] != null) {
            delete this.table[this.hashCode(key)]
            return true
        }
        return false
    }
}

class ValuePair {
    constructor(key, value) {
        this.key = key
        this.value = value
    }
}

3.ES6中的Map

var mymap = new Map()
mymap.set("name","kerwin")
mymap.set({a:1},"aaaaaa")

mymap.get("name")
mymap.delete("name")

 (7)>>树


树是一种分层数据的抽象模型。

 1.二叉树

         二叉树中的节点最多只能有两个子节点:一个是左侧子节点,另一个是右侧子节点。

2.二叉搜索树

        二叉搜索树(BST)是二叉树的一种,但是只允许你在左侧节点存储(比父节点)小的值, 在右侧节点存储(比父节点)大的值。

  >>关于遍历

  • 中序遍历是一种以上行顺序访问 BST 所有节点的遍历方式,也就是以从最小到最大的顺序 访问所有节点。 中序遍历的一种应用就是对树进行排序操作。

  • 先序遍历是以优先于后代节点的顺序访问每个节点的。先序遍历的一种应用是打印一个结构 化的文档。(访问根节点,遍历左子树,遍历右子树)

  • 后序遍历则是先访问节点的后代节点,再访问节点本身。后序遍历的一种应用是计算一个目 录及其子目录中所有文件所占空间的大小。(简而言之就是在树中从最末尾的那一代开始从左到右打印,一直到整个树都被遍历完成)

>>关于移除要考虑的情况

A.封装代码
class Node {
    constructor(key) {
        this.key = key
        this.left = null
        this.right = null
    }
}

class BST {
    constructor() {
        this.root = null
    }

    insert(key) {
        if (this.root == null) {
            this.root = new Node(key)
        } else {
            this.insertNode(this.root, key)
        }
    }

    insertNode(node, key) {
        if (this.compareFn(key, node.key) === -1) {
            if (node.left == null) {
                node.left = new Node(key)
            } else {
                this.insertNode(node.left, key)
            }
        } else {
            if (node.right == null) {
                node.right = new Node(key)
            } else {
                this.insertNode(node.right, key)
            }

        }
    }

    compareFn(a, b) {
        if (a === b) {
            return 0
        }
        return a < b ? -1 : 1
    }

    //中序遍历,注意递归调用的顺序
    middleMap(callback) {
        this.middleMapNode(this.root, callback)
    }

    middleMapNode(node, callback) {
        if (node != null) {
            this.middleMapNode(node.left, callback)
            callback(node.key)
            this.middleMapNode(node.right, callback)
        }
    }

    //先序遍历
    prevMap(callback) {
        this.prevMapNode(this.root, callback)
    }

    prevMapNode(node, callback) {
        if (node != null) {
            callback(node.key)
            this.prevMapNode(node.left, callback)

            this.prevMapNode(node.right, callback)
        }
    }

    //后序遍历
    behindMap(callback) {
        this.behindMapNode(this.root, callback)
    }

    behindMapNode(node, callback) {
        if (node != null) {
            this.behindMapNode(node.left, callback)
            this.behindMapNode(node.right, callback)
            callback(node.key)
        }
    }

    min() {
        return this.minNode(this.root)
    }

    minNode(node) {
        let current = node
        while (current != null && current.left != null) {
            current = current.left
        }
        return current.key
    }

    max() {
        return this.maxNode(this.root)
    }

    maxNode(node) {
        let current = node
        while (current != null && current.right != null) {
            current = current.right
        }
        return current.key
    }

    search(key) {
        return this.searchNode(this.root, key)
    }

    searchNode(node, key) {
        if (node === null) {
            return false
        }
        if (this.compareFn(key, node.key) === -1) {
            return this.searchNode(node.left, key)
        } else if (this.compareFn(key, node.key) === 1) {
            return this.searchNode(node.right, key)
        } else {
            return true
        }
    }

    remove(key) {
        this.removeNode(this.root, key)
    }

    removeNode(node, key) {
        if (node == null) {
            return null
        }
        if (this.compareFn(key, node.key) === -1) {
            node.left = this.removeNode(node.left, key)
            console.log(node);
            return node
        } else if (this.compareFn(key, node.key) === 1) {
            node.right = this.removeNode(node.right, key)
            console.log(node);
            return node

        } else {
            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
            }
            const target = this.minNode(node.right)
            node.key = target.key
            node.right = this.removeNode(node.right, target.key)
            return node
        }
    }
}

const tree = new BST()
tree.insert(6)
tree.insert(4)
tree.insert(8)
tree.insert(3)
tree.insert(5)
tree.middleMap((value) => console.log(value)) //3 4 5 6 8
tree.prevMap((value) => console.log(value))   //6 4 3 5 8
tree.behindMap((value) => console.log(value)) //3 5 4 8 6

(8)>>二叉堆

二叉堆是一种特殊的二叉树,有两种特性

  • 它是一棵完全二叉树,表示树的每一层都有左侧和右侧子节点(除了最后一层的叶节点), 并且最后一层的叶节点尽可能都是左侧子节点,这叫作结构特性。

  • 二叉堆不是最小堆就是最大堆。最小堆允许你快速导出树的最小值,最大堆允许你快速 导出树的最大值。所有的节点都大于等于(最大堆)或小于等于(最小堆)每个它的子 节点。这叫作堆特性。

1.最小堆

//把二叉堆的数据按数组的格式存储起来
class minHeap {
    heap = []
    //根据现有节点计算左子节点
    getLeftSonIndex(index) {
        return 2 * index + 1
    }
    getRightSonIndex(index) {
        return 2 * index + 2
    }
    getParentIndex(index) {
        if (index === 0) {
            return undefined
        } else {
            return Math.floor((index - 1) / 2)
        }
    }

    insert(value) {
        if (value != null) {
            this.heap.push(value)
            this.shiftUp(this.heap.length - 1)
            return true
        }
        return false
    }

    shiftUp(index) {
        let parent = this.getParentIndex(index)
        while (index > 0 && this.compareFn(this.heap[parent], this.heap[index]) === 1) {
            this.swap(this.heap, parent, index)
            index = parent
            parent = this.getParentIndex(index)
        }
    }

    compareFn(a, b) {
        if (a === b) {
            return 0
        }
        return a < b ? -1 : 1
    }

    swap(arr, a, b) {
        let temp = arr[a]
        arr[a] = arr[b]
        arr[b] = temp
    }

    size() {
        return this.heap.length
    }

    isEmpty() {
        return this.size() === 0
    }

    findMinimun() {
        return this.heap[0]
    }
    //去除根节点及后面的操作
    extractFirst() {
        if (this.isEmpty()) {
            return undefined
        }
        if (this.size() === 1) {
            return this.heap.shift()
        }
        const removedValue = this.heap[0]
        this.heap[0] = this.heap.pop()
        this.shiftDown(0)
        return removedValue
    }

    shiftDown(index) {
        let current = index
        let left = this.getLeftSonIndex(index)
        let right = this.getRightSonIndex(index)
        if (left < this.size() && this.compareFn(this.heap[current], this.heap[left]) === 1) {
            current = left
        }
        if (right < this.size() && this.compareFn(this.heap[current], this.heap[right]) === 1) {
            current = right
        }
        if (index !== current) {
            this.swap(this.heap, index, current)
            this.shiftDown(current)
        }
    }
}

2.最大堆

可以偷个懒,直接继承并随便改写一下比较两数大小的方法


class maxHeap extends minHeap {
    constructor() {
        super()
    }
    compareFn(a, b) {
        if (a === b) {
            return 0
        }
        return a > b ? -1 : 1
    }
}

三.总结

        数据结构是个神奇的东西,它充斥在代码中,却仿佛离我们那么遥远,学习数据结构不仅是在面对不同的数据时要施加不同的策略,而且可以提高我们的代码阅读能力。当然了,对于数据结构的学习依然任重而道远,各位同仁加油吧,希望可以点赞收藏加关注嘿嘿。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/386017.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Prompt Tuning:深度解读一种新的微调范式

阅读该博客&#xff0c;您将系统地掌握如下知识点&#xff1a; 什么是预训练语言模型&#xff1f; 什么是prompt&#xff1f;为什么要引入prompt&#xff1f;相比传统fine-tuning有什么优势&#xff1f; 自20年底开始&#xff0c;prompt的发展历程&#xff0c;哪些经典的代表…

Linux_进程间通信

管道 System V 共享内存 System V IPC 接口介绍 由于进程地址空间的存在&#xff0c;所以进程间有具有独立性&#xff0c;一个进程看不到另一个进程的数据。那么如果我们想让进程间通信&#xff0c;就必须先让它们先看到同一份资源。常见的进程间通信的方法有管道&#xff0c;…

“bound drug/molecule”or “unbound drug/molecule”、molecule shape、sketching是什么?

“bound drug/molecule”or “unbound drug/molecule” For clarity, the following terms will be used throughout this study: “bound drug/molecule” (or “unbound drug/molecule”) refers to the drug/molecule that is bound (or unbound) to proteins [48]. 意思就是…

力扣精选算法100道——【模板】前缀和 (二维)

目录 &#x1f388;题目解析 &#x1f388;算法原理 &#x1f388;实现代码 二维前缀和【模板】 &#x1f388;题目解析 上一题我们讲述了一维的前缀和求法。 第一行三个参数&#xff0c;n是行数3&#xff0c;m是列数4&#xff0c;q3代表查询次数 接下来就是n行m列的矩阵…

用shell脚本批量修改文件名

今天继续分享一个实用的shell脚本哈 示例&#xff1a;# touch file{1..3}.txt # ls file1.txt file2.txt file3.txt 脚本内容&#xff1a; #!/bin/bash #方法1&#xff1a;for file in $(ls *txt); domv $file bbs_${file#*_}# mv $file $(echo $file |sed -r s/.*(_.*)/b…

C++入门篇——类与对象重点解析(下篇)

1. 再谈构造函数 1.1 构造函数体赋值 在创建对象时&#xff0c;编译器通过调用构造函数&#xff0c;给对象中各个成员变量一个合适的初始值。 class Date { public: Date(int year, int month, int day) {_year year;_month month;_day day; } private:int _year;int _m…

AI大模型开发架构设计(9)——AI 编程架构刨析和业务应用实战案例

文章目录 AI 编程架构刨析和业务应用实战案例1 AI编程代码生成模型剖析编程方式的发展代码自动生成基于大模型的AI编程工具——Github Copilot以 CodeGeeX 为例-发展过程以 CodeGeeX 为例-训练过程以 CodeGeeX 为例-大规模代码数据处理以 CodeGeeX 为例-模型结构以 CodeGeeX 为…

IDEA 推荐插件

grep-console 输出日志换颜色 MybatisLogFormat 直接复制mybatis的日志成完整的SQL SequenceDiagram 生成时序图

OpenCV 人脸检测(易上手版)

在丰富多彩的计算机视觉世界中&#xff0c;人脸检测是最有趣和最广泛应用的领域之一。无论是在安全系统、用户界面控制&#xff0c;还是在社交媒体中应用过滤器&#xff0c;准确有效地检测人脸的能力都是至关重要的。今天&#xff0c;很高兴与大家分享如何在 Python 中使用 Ope…

Java实现软件学院思政案例库系统 JAVA+Vue+SpringBoot+MySQL

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统管理员2.2 普通教师 三、系统展示四、核心代码4.1 查询思政案例4.2 审核思政案例4.3 查询思政课程4.4 思政案例点赞4.5 新增思政案例评语 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的软件学…

【制作100个unity游戏之25】3D背包、库存、制作、快捷栏、存储系统、砍伐树木获取资源、随机战利品宝箱4(附带项目源码)

效果演示 文章目录 效果演示系列目录前言快捷栏操作&#xff0c;并可切换手臂绘制快捷栏UI代码控制快捷栏切换 快捷栏显示选中效果绘制选中效果UI图代码重新定位选中效果图 源码完结 系列目录 前言 欢迎来到【制作100个Unity游戏】系列&#xff01;本系列将引导您一步步学习如…

CUDA编程 - 共享内存 - shared memory - 学习记录

CUDA编程 - 共享内存 共享内存一、为什么要使用 shared memory&#xff1f;1.1、从硬件出发理解&#xff1a;1.2、从软件出发理解&#xff1a; 二、如何使用shared memory2.1、静态共享内存2.2、动态共享内存 三、实践 - 使用共享内存执行矩阵乘法总结 共享内存 一、为什么要使…

探索机器学习:定义、算法及应用领域

目录 前言1 机器学习的定义2 机器学习算法2.1 监督学习2.2 无监督学习2.3 强化学习 3 机器学习的应用3.1 智能搜索3.2 医疗诊断3.3 无人驾驶 结语 前言 机器学习&#xff0c;源自Arthur Samuel的定义&#xff0c;赋予计算机通过领域学习的能力&#xff0c;使其在不需要明确程序…

编写Makefile

现在我们将创建一个程序&#xff0c;该程序能够读取次位码文件并打印其中定义的函数名称&#xff0c;以及它们的基本块数&#xff0c;从而显示LLVM库的易用性 什么是Makefile&#xff1f; C语言中&#xff0c;我们使用visual studio开发软件时候&#xff0c;写程序开始时候都…

专业140+总分420+浙江大学842信号系统与数字电路考研经验电子信息与通信,真题,大纲,参考书。

今年考研已经结束&#xff0c;初试专业课842信号系统与数字电路140&#xff0c;总分420&#xff0c;很幸运实现了自己的目标&#xff0c;被浙大录取&#xff0c;这在高考是想都不敢想的学校&#xff0c;在考研时实现了&#xff0c;所以大家也要有信心&#xff0c;通过自己努力实…

Kubernetes(K8S)集群部署实战

目录 一、准备工作1.1、创建3台虚拟机1.1.1、下载虚拟机管理工具1.1.2、安装虚拟机管理工具1.1.3、下载虚Centos镜像1.1.4、创建台个虚拟机1.1.5、设置虚拟机网络环境 1.2、虚拟机基础配置&#xff08;3台虚拟机进行相同处理&#xff09;1.2.1、配置host1.2.2、关闭防火墙1.2.3…

【北邮鲁鹏老师计算机视觉课程笔记】08 texture 纹理表示

【北邮鲁鹏老师计算机视觉课程笔记】08 texture 纹理表示 1 纹理 规则和不规则的 2 纹理的用处 从纹理中恢复形状 3 分割与合成 4 分析纹理进行分类 通过识别纹理分析物理性质 如何区分纹理 5 寻找有效的纹理分类方法 发现模式、描述区域内模式 A对应图2 B对应图…

LeetCode、136. 只出现一次的数字【简单,位运算】

文章目录 前言LeetCode、136. 只出现一次的数字【简单&#xff0c;位运算】题目链接与分类思路异或一遍运算 资料获取 前言 博主介绍&#xff1a;✌目前全网粉丝2W&#xff0c;csdn博客专家、Java领域优质创作者&#xff0c;博客之星、阿里云平台优质作者、专注于Java后端技术…

Python实现EMV指标计算:股票技术分析的利器系列(2)

Python实现EMV指标计算&#xff1a;股票技术分析的利器系列&#xff08;2&#xff09; 介绍算法解释&#xff1a; 核心代码&#xff1a;rolling函数介绍 完整代码&#xff1a;一定要看 介绍 先看看官方介绍&#xff1a; EMV(简易波动指标&#xff09; 用法 1.EMV 由下往上穿越…

【MySQL】:分组查询、排序查询、分页查询、以及执行顺序

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; MySQL从入门到进阶 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一. 分组查询1.1 语法1.2 where与having区别1.3 注意事项:1.4 案例: 二. 排序查询…
最新文章