数据结构在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 = decNumberlet 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] = datathis.#count++}//返回队头frontQueue() {return this.#items[this.#lowCount]}isEmpty() {return this.size === 0}size() {return this.#count - this.#lowCount}clear() {this.#items = {}this.#count = 0this.#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] = datathis.#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] = datathis.#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 = 0this.#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 = elementthis.next = null}
}
//单链表
class LinkList {constructor() {this.head = nullthis.count = 0}//从表尾放入新节点push(element) {const node = new Node(element)if (this.head === null) {this.head = node} else {let current = this.headwhile (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.headif (index === 0) {this.head = this.head.next} else {let previousfor (let i = 0; i < index; i++) {previous = currentcurrent = 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.headif (index === 0) {this.head = this.head.next} else {let previous = this.getNodeAt(index - 1)current = previous.nextprevious.next = current.next}this.count--return current.element}return undefined}//根据索引值找到相应的节点getNodeAt(index) {if (index >= 0 && index < this.count) {let node = this.headfor (let i = 0; i < index; i++) {node = node.next}return node}return undefined}indexOf(element) {let current = this.headfor (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.headnode.next = currentthis.head = nodethis.count++} else {let previous = this.getNodeAt(index - 1)let current = previous.nextprevious.next = nodenode.next = currentthis.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 = doubleNodethis.tail = doubleNode} else {this.tail.next = doubleNodedoubleNode.prev = this.tailthis.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 = doubleNodethis.tail = doubleNode} else {this.head.prev = doubleNodedoubleNode.next = this.headthis.head = doubleNode}} else if (index === this.count) {this.tail.next = doubleLinkListdoubleLinkList.prev = this.tailthis.tail = doubleLinkList} else {let previouslet current = this.headfor (let i = 0; i < index; i++) {current = current.nextprevious = current.prev}current.prev = doubleNodedoubleNode.next = currentdoubleNode.prev = previousprevious.next = doubleNode}this.count++return true}return false}removeAt(index) {if (index >= 0 && index < this.count) {let current = this.headif (index === 0) {this.head = current.nextif (this.count === 1) {this.tail = null} else {this.head.prev = null}} else if (index === this.count - 1) {current = this.tailthis.tail = current.prevthis.tail.next = null} else {current = this.getNodeAt(index)let previous = current.prevlet future = current.nextprevious.next = futurefuture.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 currentif (this.head === null) {this.head = node} else {current = this.getNodeAt(this.size() - 1)current.next = node}node.next = this.headthis.count++}insert(element, index) {if (index >= 0 && index <= this.count) {const node = new Node(element)let current = this.headif (index === 0) {if (this.head === null) {this.head = nodenode.next = this.head} else {node.next = this.headcurrent = this.getNodeAt(this.size() - 1)this.head = nodecurrent.next = node}} else {if (index === this.count) {current = this.getNodeAt(index - 1)current.next = nodenode.next = this.head} else {let previous = this.getNodeAt(index - 1)previous.next = nodenode.next = previous.next}}this.count++return true}return false}removeAt(index) {if (index >= 0 && index < this.count) {let current = this.headif (index === 0) {if (this.count === 1) {this.head = null} else {let last = this.getNodeAt(this.size() - 1)this.head = current.nextlast.next = this.head}} else {let previous = this.getNodeAt(index - 1)current = previous.nextprevious.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] = elementreturn 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] = valuethis.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 = keythis.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 = 5381for (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 = keythis.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 = keythis.left = nullthis.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 = nodewhile (current != null && current.left != null) {current = current.left}return current.key}max() {return this.maxNode(this.root)}maxNode(node) {let current = nodewhile (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 = nullreturn node}if (node.left == null) {node = node.rightreturn node} else if (node.right == null) {node = node.leftreturn node}const target = this.minNode(node.right)node.key = target.keynode.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 = parentparent = 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 = indexlet 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.hqwc.cn/news/470279.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

奔跑吧小恐龙(Java)

前言 Google浏览器内含了一个小彩蛋当没有网络连接时&#xff0c;浏览器会弹出一个小恐龙&#xff0c;当我们点击它时游戏就会开始进行&#xff0c;大家也可以玩一下试试&#xff0c;网址&#xff1a;恐龙快跑 - 霸王龙游戏. (ur1.fun) 今天我们也可以用Java来简单的实现一下这…

Python-web自动化-Playwright的学习

Python-web自动化-Playwright的学习 1. 安装playwright2. 界面等待3. 自动化代码助手4. 定位元素1. css selector定位2. xpath定位3. get_by_XXX定位 5. 操作元素1. 单选框、复选框2. select下拉框3. 网页操作4. 框架页 frame5. 窗口切换6. 截屏 1. 安装playwright pip命令 pi…

垃圾分类|城市垃圾分类管理系统|基于Springboot的城市垃圾分类管理系统设计与实现(源码+数据库+文档)

城市垃圾分类管理系统目录 目录 基于Springboot的城市垃圾分类管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、垃圾列表 2、公告信息管理 3、公告类型管理 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 …

(06)Hive——正则表达式

Hive版本&#xff1a;hive-3.1.2 一、Hive的正则表达式概述 正则表达式是一种用于匹配和操作文本的强大工具&#xff0c;它是由一系列字符和特殊字符组成的模式&#xff0c;用于描述要匹配的文本模式。 Hive的正则表达式灵活使用解决HQL开发过程中的很多问题&#xff0c;本篇文…

代码随想录算法训练营第十七天|Leetcode110 平衡二叉树、Leetcode257 二叉树的所有路径、Leetcode404 左叶子之和

代码随想录算法训练营第十七天|Leetcode110 平衡二叉树、Leetcode257 二叉树的所有路径、Leetcode404 左叶子之和 ● Leetcode110 平衡二叉树● 解题思路● 代码实现 ● Leetcode257 二叉树的所有路径● 解题思路● 代码实现 ● Leetcode404 左叶子之和● 解题思路● 代码实现 …

esp8266-01s WIFI模块使用(一)- AT指令

时间记录&#xff1a;2024/2/15 一、注意事项 &#xff08;1&#xff09;使用英文双引号表示字符串数据 &#xff08;2&#xff09;默认波特率115200 &#xff08;3&#xff09;AT指令以“\r\n”结尾 &#xff08;4&#xff09;3.3V电源接口先连接单片机的3.3V&#xff0c;如…

7 大 Android 数据恢复软件,可轻松找回丢失的数据

每年&#xff0c;由于各种原因&#xff0c;数百万人从他们的 Android 设备中丢失数据。它可能像意外删除文件一样简单&#xff0c;也可能像系统崩溃一样复杂。在这种情况下&#xff0c;拥有高效的数据恢复工具可以证明是救命稻草。Mac 用户尤其需要找到与其系统兼容的软件。好消…

AtCoder Beginner Contest 335 (Sponsored by Mynavi) --- F - Hop Sugoroku -- 题解

目录 F - Hop Sugoroku 题目大意&#xff1a; 思路解析&#xff1a; 代码实现&#xff1a; F - Hop Sugoroku 题目大意&#xff1a; 思路解析&#xff1a; 容易想到这是一个dp题&#xff0c;然后初始转移方程为&#xff1a; 如果当a[i] 较大时&#xff0c;时间复杂度为 O(N…

ElasticSearch分词器和相关性详解

目录 ES分词器详解 基本概念 分词发生时期 分词器的组成 切词器&#xff1a;Tokenizer 词项过滤器&#xff1a;Token Filter 停用词 同义词 字符过滤器&#xff1a;Character Filter HTML 标签过滤器&#xff1a;HTML Strip Character Filter 字符映射过滤器&#x…

17.JS中的object、map和weakMap

1.object和map的区别 2.weakMap和map的区别 &#xff08;1&#xff09;Map本质上就是键值对的集合&#xff0c;但是普通的Object中的键值对中的键只能是字符串。而ES6提供的Map数据结构类似于对象&#xff0c;但是它的键不限制范围&#xff0c;可以是任意类型&#xff0c;是一…

使用bpmn-js 配置颜色

本篇文章介绍如何使用bpmn-js给图例配置颜色。该示例展示了如何向BPMN图添加颜色的多种不同方法。 通过层叠设置颜色 这种方式比较简单&#xff0c;直接通过设置图片的CSS层叠样式就可实现。 .highlight-overlay {background-color: green; /* color elements as green */opa…

【算法设计与分析】反转链表 ||

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;算法分析与设计 ⛺️稳中求进&#xff0c;晒太阳 题目 给你单链表的头指针 head 和两个整数 left 和 right &#xff0c;其中 left < right 。请你反转从位置 left 到位置 right 的链表…