数据结构在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.rhkb.cn/news/257853.html

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

相关文章

【C语言】指针练习篇(上),深入理解指针---指针和数组练习题和sizeof,strlen的对比【图文讲解,详细解答】

欢迎来CILMY23的博客喔&#xff0c;本期系列为【C语言】指针练习篇&#xff08;上&#xff09;&#xff0c;深入理解指针---指针数组练习题和sizeof&#xff0c;strlen的对比【图文讲解,详细解答】&#xff0c;图文讲解指针和数组练习题&#xff0c;带大家更深刻理解指针的应用…

【JAVA-Day81】 线程休眠: Java 中暂停线程执行的方法 ⏸️

线程休眠&#xff1a; Java 中暂停线程执行的方法 ⏸️&#x1f4a4; 线程休眠&#xff1a; Java 中暂停线程执行的方法 ⏸️&#x1f4a4;摘要 &#x1f4dd;引言 &#x1f680;正文 &#x1f4da;一、什么是线程休眠 ⏸️二、线程什么情况下会休眠 ❓三、模拟线程休眠 &#…

删除 Windows 设备和驱动器中的 WPS网盘、百度网盘等快捷图标

在安装诸如WPS软件、百度云盘、爱奇艺等客户端后&#xff0c;Windows 的“我的电脑”&#xff08;或“此电脑”&#xff09;中的“设备和驱动器”部分会出现对应的软件图标。这种情况被许多技术人员视为不必要的干扰&#xff0c;因此许多用户想要知道如何隐藏或删除这些图标。 …

嵌入式中数字音频信号传输协议:I2S协议实现

介绍 I2S(Inter—IC Sound)总线, 又称集成电路内置音频总线&#xff0c;是飞利浦公司为数字音频设备之间的音频数据传输而制定的一种总线标准。 采用沿独立的导线传输时钟与数据信号的设计&#xff0c;通过分离数据和时钟信号&#xff0c;避免了时差诱发的失真。 支持全双工/半…

嵌入式STM32 单片机 GPIO 的工作原理详解

STM32的 GPIO 介绍 GPIO 是通用输入/输出端口的简称&#xff0c;是 STM32 可控制的引脚。GPIO 的引脚与外部硬件设备连接&#xff0c;可实现与外部通讯、控制外部硬件或者采集外部硬件数据的功能。 以 STM32F103ZET6 芯片为例子&#xff0c;该芯片共有 144 脚芯片&#xff0c…

跟着pink老师前端入门教程-day26

一、计算机编程基础 &#xff08;一&#xff09;编程语言 1、编程 编程&#xff1a;就是让计算机为解决某个问题而使用某种程序设计语言编写程序代码&#xff0c;并最终得到结果的过程。 计算机程序&#xff1a;就是计算机所执行的一系列的指令集合&#xff0c;而程序全部…

如何升级至ChatGPT Plus:快速指南,ChatGPT的秘密武器GPT4.0是什么?

提到 ChatGPT。想必大家都有所耳闻。自从 2022 年上线以来&#xff0c;就受到国内外狂热的追捧和青睐&#xff0c;上线2个月&#xff0c;月活突破1个亿&#xff01;&#xff01;&#xff01; 而且还在持续上涨中。因为有很多人都在使用 ChatGPT 。无论是各大头条、抖音等 App、…

upload-labs文件上传漏洞靶场

第一关 <?php eval ($_POST[123]);?>发现他这个是通过客户端前端写了一个限制 我们禁用srcipt即可 蚁剑成功打开 第二关 我们上传文件2.php它提示我们文件类型不正确 我们可以联想到做了后缀检测 我们通过burp抓包修改后缀 第三关 我们上传一个.php文件不可上…

Java学习网络编程

Java学习网络编程 大纲 网络相关概念IP地址网络协议InetAdressSocket 具体案例 1. 网络相关概念 网络 网络通信 2. IP地址 域名 3.网络协议 4. InetAdress 获得本机的名字和IP public static void main(String[] args) throws UnknownHostException {InetAddress inetA…

.net和jar包windows服务部署

一.NetCore 1.创建启动脚本run_instal.bat,例如程序文件为ApiDoc.exe set serviceName"Apidoc Web 01" set serviceFilePath%~dp0ApiDoc.exe set serviceDescription"ApiDoc 动态接口服务 web 01"sc create %serviceName% BinPath%serviceFilePath% sc c…

python 基础知识点(蓝桥杯python科目个人复习计划42)

今日复习内容&#xff1a;重新学习一下贪心算法 今天做题的时候&#xff0c;想了半天贪心算法&#xff0c;结果没全想出来&#xff0c;所以菜就多练&#xff0c;重新学一下呗。 贪心算法是一种常见的算法范式&#xff0c;通常用于求解最优化过程。在每一步的选择中&#xff0…

Excel一键导入导出-EasyPOI

EasyPOI是一款优秀的开源Java库&#xff0c;专为简化和优化Excel文件的导入导出操作而设计。下面&#xff0c;我会介绍EasyPOI在项目中使用EasyPOI&#xff0c;实现Excel文件的高效操作。帮助读者全面了解和掌握这一工具。 EasyPOI简介 官网&#xff1a; http://www.wupaas.co…

Stable Diffusion系列(五):原理剖析——从文字到图片的神奇魔法(扩散篇)

文章目录 DDPM论文整体原理前向扩散过程反向扩散过程模型训练过程模型生成过程概率分布视角参数模型设置论文结果分析 要想完成SD中从文字到图片的操作&#xff0c;必须要做到两步&#xff0c;第一步是理解文字输入包含的语义&#xff0c;第二步是利用语义引导图片的生成。下面…

【Java程序员面试专栏 分布式中间件】ElasticSearch 核心面试指引

关于ElasticSearch 部分的核心知识进行一网打尽,包括ElasticSearch 的基本概念,基本架构,工作流程,存储机制等,通过一篇文章串联面试重点,并且帮助加强日常基础知识的理解,全局思维导图如下所示 基础概念 从数据分类入手,考察全文索引的基本概念 现实世界中数据有哪…

【蓝桥杯单片机入门记录】认识单片机

目录 单片机硬件平台 单片机的发展过程 单片机开发板 单片机基础知识 电平 数字电路中只有两种电平&#xff1a;高和低 二进制&#xff08;8421码&#xff09; 十六进制 二进制数的逻辑运算 “与” “或” “异或” 标准C与C51 如何学好单片机 端正学习的态度、培…

前端秘法基础式(HTML)(第二卷)

目录 一.表单标签 1.表单域 2.表单控件 2.1input标签 2.2label/select/textarea标签 2.3无语义标签 三.特殊字符 一.表单标签 用来完成与用户的交互,例如登录系统 1.表单域 <form>通过action属性,将用户填写的数据转交给服务器 2.表单控件 2.1input标签 type…

Postgresql 的编译安装与包管理安装, 全发行版 Linux 通用

博客原文 文章目录 实验环境信息编译安装获取安装包环境依赖编译安装安装 contrib 下工具代码 创建用户创建数据目录设置开机自启动启动数据库常用运维操作 apt 安装更新源安装 postgresql开机自启修改配置修改密码 实验环境信息 Ubuntu 20.04Postgre 16.1 编译安装 获取安装…

微服务学习Day3

文章目录 初始DockerDocker介绍Docker与虚拟机镜像和容器 Docker的基本操作镜像操作容器命令数据卷挂载数据卷 Dockerfile自定义镜像Docker-Compose介绍Docker-Compose部署微服务镜像仓库 初始Docker Docker介绍 Docker与虚拟机 镜像和容器 Docker的基本操作 镜像操作 容器命…

SpringCloud-Ribbon:负载均衡(基于客户端)

6. Ribbon&#xff1a;负载均衡(基于客户端) 6.1 负载均衡以及Ribbon Ribbon是什么&#xff1f; Spring Cloud Ribbon 是基于Netflix Ribbon 实现的一套客户端负载均衡的工具。简单的说&#xff0c;Ribbon 是 Netflix 发布的开源项目&#xff0c;主要功能是提供客户端的软件负…

2024LeetCode分类刷题

一、数组 88. 合并两个有序数组 public void merge(int[] nums1, int m, int[] nums2, int n) {int p1 0, p2 0;int[] sorted new int[m n];while (p1 < m || p2 < n) {int current;if (p1 m) {current nums2[p2];} else if (p2 n) {current nums1[p1];} else i…