当前位置: 首页 > news >正文

前端 用js封装部分数据结构

文章目录

    • Stack
    • 队列
    • 链表
    • Set
      • set 用来数组去重
      • set用来取两个数组的并集
      • set用来取两个数组的交集
      • set用来取两个数组的差集
    • 字典

Stack

栈,先进后出,后进先出。用数组来进行模拟,通过push存入,通过pop取出。

class Stack {// 带#表示这是一个私有变量,不能在外部对其进行直接修改#items = []push(val) {this.#items.push(val);}pop() {return this.#items.pop();}getLength() {return this.#items.length;}clear() {this.#items = [];}peek() {return this.#items.at(-1) || this.#items[this.#items.length - 1];}isEmpty() {return this.#items.length === 0;}
}const stack1 = new Stack();
stack1.push(1);
stack1.push(2);
console.log(stack1);
stack1.push(4);
console.log(stack1);
console.log(stack1.pop());// 用辗转相除法,将一个十进制转化为任意进制的数 2到十六进制(一般为)function tansformTenToNumber(targetNumber,base) {let num = targetNumber;const stack = new Stack();let result = '';const stringMap='0123456789ABCDEF';while(num > 0) {stack.push(stringMap[num % base]);num = Math.floor(num / base);}while(stack.getLength() !== 0) {result = result + stack.pop()}return result
}console.log(tansformTenToNumber(50,2)) // 110010
console.log(tansformTenToNumber(1501,16)) // 5DD

队列

为什么用对象来封装队列而不用数组呢,因为当数组shift的时候,会造成一定的性能问题。
当你将数组第一个移动,实际上,整个数组所有的子元素都会跟着移动。

class Queue {
// 带#表示这是一个私有变量,不能在外部对其进行直接修改#items = {};#min = 0;#max = 0;push(val) {this.#items[this.#max] = valthis.#max++}shift() {// 如果已经为空,就没有东西可以取if(this.isEmpty()) {return undefined}// 取出数字最小的,先进先出麻let result = this.#items[this.#min]this.#min++return result}clear() {this.#items = {}this.#max = 0;this.#min = 0;}size() {return this.#max - this.#min}isEmpty() {return this.size() === 0}
}const queue = new Queue()queue.push('deng')
queue.push('xi')
queue.push('yang')
queue.push('xi')console.log(queue.size()) // 4
console.log(queue.isEmpty()) // false
console.log(queue.shift()) // deng
console.log(queue.shift()) // xi
console.log(queue.shift()) // yang
console.log(queue.shift()) // xi
console.log(queue.shift()) // undefined
console.log(queue.isEmpty()) // truequeue.push('deng')
queue.push('xi')console.log(queue.shift()) //deng
console.log(queue.clear())
console.log(queue.isEmpty()) // true
queue.push('yang')
queue.push('xi')
console.log(queue.size()) // 2// 击鼓传花
// 参与者按照一定顺序,一次被选中,当鼓声停止时,被选中的人淘汰,
// 直到场上剩下最后一人为止。// 接受两个参数,第一个参数,参与人的数组, 
// 第二个参数,鼓声每次敲击多少下,敲击多少次后,必须淘汰拿花的人
function passingFlower(list, num) {const queue = new Queue()// 先将list 全部放入队列中for(let i =0,len=list.length;i < len; i++) {queue.push(list[i])}// 当只剩一个人的时候停止循环while(queue.size() > 1) {for(let j=0, len=num; j < len; j++) {// 每一次循环,都要将队列最前面的人放到最后面去let result = queue.shift()queue.push(result)}// 当循环结束,淘汰掉一个人,直接从队列最前面拿掉,不放入队列最后queue.shift()}// 将最后一人作为获胜者返回return queue.shift()
}const winner = passingFlower(['d','e','n','g','x','i'], 7)console.log(winner) // n

链表

为了解决队列里面,移动一个,后面的所有元素都会跟着移动的问题,出现了新的数据结构,链表。链表是不定长度的数据,但与数组相比,不利于数据的搜索。

// 链表中的单个节点
class LinkElement {constructor(value) {this.value = value;this.next = null;}setNext(next) {this.next = next;}getNext() {return this.next;}
}
// 链表
class LinkList {constructor() {this.count = 0;this.head = null;}// 追加链表到里面,放置到最后一个push(val) {let link = new LinkElement(val);if (this.head === null) {// 让头指向第一个节点this.head = link;} else {let current = this.head;// 如果不为空,就要一直找到链表的最后一个,然后让最后一个的next指向新的节点while (current.getNext() !== null) {current = current.getNext();}current.setNext(link);}// 计算加一this.count++;}// 删除制定位置removeAt(index) {// 如果是空的,就直接返回if (index < 0 || index >= this.count) {return undefined;}let current = this.head;if (index === 0) {// 如果是0,就让head指向第二个节点this.head = current.getNext();} else {// 找到 index的上一个link节点let previous = this.findAt(index - 1);// current 就是 index 就是要删除的节点current = previous.getNext();// 让 index - 1 的节点的next指向 index + 1 的节点,这样就把 index 的节点删除了previous.setNext(current.getNext());}// 计算减一this.count--;// 将删除的节点返回return current;}// 找到指定位置的节点findAt(index) {if (index < 0 || index >= this.count) {return undefined;}let current = this.head;for (let i = 0; i < index; i++) {// 当循环到最后,current 是 index - 1,再getNext 就是 indexcurrent = current.getNext();}return current;}// 根据val值,找第一个节点的索引值indexOf(val) {let current = this.head;// 如果没找到返回 -1let result = -1;for (let i = 0; i < this.count; i++) {if (current.value === val) {result = i;}// 不断的往下一个链表找current = current.getNext();}return result;}// 删除指定val值的节点removeVal(val) {// 找到对应值的indexlet currentIndex = this.indexOf(val);if (currentIndex === -1) {return undefined;} else {// 如果有就利用removeAt删除return this.removeAt(currentIndex);}}// 链表的插入,在指定位置插入元素,第一个参数是你要插入元素的值,第二参数是你要插入链表的位置insert(val, index) {const link = new LinkElement(val);// 判断index 是否合理if (index < 0 || index > this.count) {return false;}// 如果是0,就让head指向新的节点if (index === 0) {let current = this.head;// 让新的节点的next指向第一个节点link.setNext(current);// 然后让指针指向新的第一个节点this.head = link;} else {// 找到index - 1 的节点let previous = this.findAt(index - 1);// 让新的节点的next指向 index 的节点link.setNext(previous.getNext());// 让 index - 1 的节点的next指向新的节点previous.setNext(link);}// 将count + 1this.count++;}size() {return this.count;}isEmpty() {return this.size() === 0;}getHead() {return this.head;}
}const linkList = new LinkList();linkList.push(1);
linkList.push(2);
linkList.push(3);
linkList.push(4);
linkList.insert(0, 0);
console.log(linkList.indexOf(1));linkList.removeAt(1);
console.log(linkList);linkList.removeVal(2);
console.log(linkList);

Set

set用对象来封装,key和value保存一致。这样就能确保Set里面的内容不会被重复保存。如果要想确保万无一失,可以用symboal模拟set,这样可以在set里面保存任意内容。

class MySet {#object = {};delete(value) {// 删除之前先判断该值是否存在if (this.has(value)) {delete this.#object[value];return true;}return false;}add(value) {// 添加之前也得先判断是否已经存在了,不能重复添加if (!this.has(value)) {this.#object[value] = value;return true;}return false;}has(value) {return this.#object.hasOwnProperty(value);}clear() {this.#object = {};}size() {return Object.values(this.#object).length;}values() {return Object.values(this.#object);}
}const set = new MySet();
set.add(1);
set.add(2);console.log(set.values()); // [1, 2]set.delete(2);console.log(set.values()); // [1]
console.log(set.size()); // 1console.log(set.has(1)); // trueset.clear();
console.log(set.values()); // []

set 用来数组去重

const arr1 = [1,2,3,4,4,5]
const arr2 = [3,4,5,6]const result = Array.from(new Set(arr1))
console.log(result) // [ 1, 2, 3, 4, 5 ]

set用来取两个数组的并集

const arr1 = [1,2,3,4,4,5]
const arr2 = [3,4,5,6]// 并集 将两个数组重复的内容,全部去重
const union = Array.from(new Set([...arr1, ...arr2]))

set用来取两个数组的交集

const arr1 = [1,2,3,4,4,5]
const arr2 = [3,4,5,6]
const set2 = new Set(arr2)
// 交集 将两个数组重复的内容,全部保留
const intersection = arr1.filter(item => set2.has(item))

set用来取两个数组的差集

const arr1 = [1,2,3,4,4,5]
const set1 = new Set(arr1)
const arr2 = [3,4,5,6]
const set2 = new Set(arr2)
// 差集 取出arr1对arr2的差集 // 1 2
const intersection = arr1.filter(item => !set2.has(item))
// 差集 取出arr2对arr1的差集 // 6
const intersection2 = arr2.filter(item => !set1.has(item))

字典

class NewMap {#obj = {};keyToString(key) {let KeyStr = "";switch (key) {case null:KeyStr = "null";break;case undefined:KeyStr = "undefined";default:KeyStr = JSON.stringify(key);break;}return KeyStr}// 社区比较受欢迎的计算hashcode方式之一hashCode(key) {let mapKey = this.keyToString(key) || '';let hash = 5381;for(let i=0,len=mapKey.length; i<len; i++) {hash = (hash * 33) + mapKey.charCodeAt(i);}return hash % 1013}set(key, value) {// 通过hashcode来保存keythis.#obj[this.hashCode(key)] = {key,value,};}remove(key) {if(this.#obj[this.hashCode(key)]) {delete this.#obj[this.hashCode(key)]return true}return false}has(key) {return this.get(key) !== undefined}get(key) {if(this.#obj[this.hashCode(key)]) {return this.#obj[this.hashCode(key)].value}}keyValues() {return Object.entries(this.#obj)}size() {return this.keyValues().length}
}const map1 = new NewMap()map1.set(null,null)
map1.set(undefined,undefined)
map1.set({a:1},{a:1})
console.log(map1.keyValues())
console.log(map1.has({a:1})) // trueconsole.log(map1.get({a:1})) // {a:1}console.log(map1.size()) // 3

相关文章:

前端 用js封装部分数据结构

文章目录 Stack队列链表Setset 用来数组去重set用来取两个数组的并集set用来取两个数组的交集set用来取两个数组的差集 字典 Stack 栈&#xff0c;先进后出&#xff0c;后进先出。用数组来进行模拟&#xff0c;通过push存入&#xff0c;通过pop取出。 class Stack {// 带#表示…...

cocoscreator-doc-TS:目录

cocoscreator-doc-TS-脚本开发-访问节点和组件-CSDN博客 cocoscreator-doc-TS-常用节点和组件接口-CSDN博客 cocoscreator-doc-TS-脚本开发-创建和销毁节点-CSDN博客 cocoscreator-doc-TS-脚本开发-加载和切换场景-CSDN博客 cocoscreator-doc-TS-脚本开发-获取和设置资源-CS…...

理解Java集合的基本用法—Collection:List、Set 和 Queue,Map

本博文部分参考 博客 &#xff0c;强烈推荐这篇博客&#xff0c;写得超级全面&#xff01;&#xff01;&#xff01; 图片来源 Java 集合框架 主要包括两种类型的容器&#xff0c;一种是集合&#xff08;Collection&#xff09;&#xff0c;存储一个元素集合&#xff08;单列…...

IOC容器实现分层解耦

文章开始之前&#xff0c;先引入软件开发的两个名词&#xff1a;耦合和内聚。耦合是指&#xff1a;衡量软件中各个层&#xff08;三层架构&#xff09;/各个模块的依赖关联程度&#xff1b;内聚是指&#xff1a;软件中各个功能模块内部的功能联系。三层架构中Controller、Servi…...

Flutter 共性元素动画

在 Flutter 中&#xff0c;共性元素动画&#xff08;Shared Element Transitions&#xff09;用于在页面导航或组件切换时创建视觉上更流畅和连贯的动画效果。这种动画可以使用户感受到两个界面之间的“物理联系”&#xff0c;比如图片从缩略图到全屏的扩大效果。 前置知识点整…...

K8s内存溢出问题剖析:排查与解决方案

文章目录 一、背景二、排查方案&#xff1a;1. 可能是数据量超出了限制的大小&#xff0c;检查数据目录大小2. 查看是否是内存溢出2.1 排查数据量&#xff08;查看数据目录大小是否超过limit限制&#xff09;2.2 查看pod详情发现问题 三、解决过程 一、背景 做redis压测过程中…...

乌班图单机(不访问外网)部署docker和服务的方法

面向对象:Ubuntu不能访问外网的机子,部署mysql、redis、jdk8、minio 过程: 1、安装docker(照着图去这里找对应的下载下来https://download.docker.com/linux/static/stable/),将7个docker官网下载的文件下载下来后,传上去服务器随便一个文件夹或者常用的opt或者/usr/lo…...

使用 pycharm 新建使用 conda 虚拟 python 环境的工程

1. conda 常见命令复习&#xff1a; conda env list // 查看 conda 环境列表 conda activate xxxenv // 进入指定 conda 环境2. 环境展示&#xff1a; 2.1. 我的物理环境的 Python 版本为 3.10.9&#xff1a; 2.2. 我的 conda 虚拟环境 env_yolov9_python_3_8 中的 pyth…...

Docker的save和export命令的区别,load和import的区别 笔记241124

Docker的save和export命令的区别,load和import的区别 解说1: Docker的save和export命令&#xff0c;以及load和import命令&#xff0c;在功能和使用场景上存在显著的区别。以下是对这两组命令的详细对比和解释&#xff1a; Docker save和export命令的区别 使用方式和目的&am…...

通俗理解人工智能、机器学习和深度学习的关系

最近几年人工智能成为极其热门的概念和话题&#xff0c;可以说彻底出圈了。但人工智能的概念在1955年就提出来了&#xff0c;可以说非常古老。我在上小学的时候《科学》课本上就有人工智能的概念介绍&#xff0c;至今还有印象&#xff0c;但那些年AI正处于“寒冬”&#xff0c;…...

使用 pycharm 新建不使用 python 虚拟环境( venv、conda )的工程

有时候我们发现一个好玩的 demo&#xff0c;想赶快在电脑上 pip install 一下跑起来&#xff0c;发现因为 python 的 venv、conda 环境还挺费劲的&#xff0c;因为随着时间的发展&#xff0c;之前记得很清楚的 venv、conda 的用法&#xff0c;不经常使用&#xff0c;半天跑不起…...

【大数据学习 | Spark-SQL】SparkSQL读写数据

我们使用sparksql进行编程&#xff0c;编程的过程我们需要创建dataframe对象&#xff0c;这个对象的创建方式我们是先创建RDD然后再转换rdd变成为DataFrame对象。 但是sparksql给大家提供了多种便捷读取数据的方式。 //原始读取数据方式 sc.textFile().toRDD sqlSc.createDat…...

AI赋能公共服务转型升级 | 第十届中国行业互联网大会暨腾讯云TVP行业大使三周年庆典公共服务专场圆满举办!

引言 党的二十大报告把“基本公共服务实现均等化”作为 2035 年我国发展的总体目标之一&#xff0c;强调要“健全基本公共服务体系&#xff0c;提高公共服务水平”。AI 作为新质生产力的核心驱动力之一&#xff0c;正在公共服务领域发挥着越来越重要的作用。 2024 年 10 月 2…...

关于按天切割Tomcat的catalina.out日志文件的配置

1、catalina.out 是 Tomcat 的标准输出和标准错误日志&#xff0c;通常输出到 Tomcat 安装目录下的 logs 文件夹中。这个日志文件会记录 Tomcat 启动、停止以及运行过程中产生的所有日志信息。 2、在Apache Tomcat中&#xff0c;日志文件catalina.out默认情况下不会自动按天切割…...

【人工智能】深入解析GPT、BERT与Transformer模型|从原理到应用的完整教程

在当今人工智能迅猛发展的时代&#xff0c;自然语言处理&#xff08;NLP&#xff09;领域涌现出许多强大的模型&#xff0c;其中GPT、BERT与Transformer无疑是最受关注的三大巨头。这些模型不仅在学术界引起了广泛讨论&#xff0c;也在工业界得到了广泛应用。那么&#xff0c;G…...

彻底理解如何保证ElasticSearch和数据库数据一致性问题

一.业务场景举例 需求&#xff1a; 一个卖房业务&#xff0c;双十一前一天&#xff0c;维护楼盘的运营人员突然接到合作开发商的通知&#xff0c;需要上线一批热门的楼盘列表&#xff0c;上传完成后&#xff0c;C端小程序支持按楼盘的名称、户型、面积等产品属性全模糊搜索热门…...

2024-2025热门留学趋势

在信息爆炸的时代&#xff0c;留学已成为许多人规划未来、拓宽视野的重要途径。随着全球教育格局的不断变化&#xff0c;留学领域也涌现出一系列新热点和趋势。本文将为您解读2024年最热门的留学话题&#xff0c;并提供实用的准备策略&#xff0c;助您在留学之路上一帆风顺。 热…...

寻找视频特效素材的优质网站推荐 轻松提升作品魅力

在短视频、影视和广告制作中&#xff0c;视频特效素材已成为提升作品专业感的关键元素。炫酷的光效、震撼的爆炸、动感的粒子效果和流畅的转场特效&#xff0c;都能让作品更具吸引力。那么&#xff0c;视频特效素材去哪里找呢&#xff1f;今天&#xff0c;小编为大家精心挑选了…...

【英特尔IA-32架构软件开发者开发手册第3卷:系统编程指南】2001年版翻译,2-36

文件下载与邀请翻译者 学习英特尔开发手册&#xff0c;最好手里这个手册文件。原版是PDF文件。点击下方链接了解下载方法。 讲解下载英特尔开发手册的文章 翻译英特尔开发手册&#xff0c;会是一件耗时费力的工作。如果有愿意和我一起来做这件事的&#xff0c;那么&#xff…...

信息安全实验--密码学实验工具:CrypTool

1. CrypTool介绍&#x1f4ad; CrypTool 1的开源教育工具&#xff0c;用于密码学研究。通过CrypTool 1&#xff0c;可以实现加密和解密操作&#xff0c;数字签名。CrypTool1和2有很多区别的。 2. CrpyTool下载&#x1f527; 在做信息安全实验--密码学相关实验时&#xff0c;发…...

Qt Widget类解析与代码注释

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码&#xff0c;写上注释 当然可以&#xff01;这段代码是 Qt …...

Python实现prophet 理论及参数优化

文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候&#xff0c;写过一篇简单实现&#xff0c;后期随着对该模型的深入研究&#xff0c;本次记录涉及到prophet 的公式以及参数调优&#xff0c;从公式可以更直观…...

相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...

聊一聊接口测试的意义有哪些?

目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开&#xff0c;首…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题

分区配置 (ptab.json) img 属性介绍&#xff1a; img 属性指定分区存放的 image 名称&#xff0c;指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件&#xff0c;则以 proj_name:binary_name 格式指定文件名&#xff0c; proj_name 为工程 名&…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

免费PDF转图片工具

免费PDF转图片工具 一款简单易用的PDF转图片工具&#xff0c;可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件&#xff0c;也不需要在线上传文件&#xff0c;保护您的隐私。 工具截图 主要特点 &#x1f680; 快速转换&#xff1a;本地转换&#xff0c;无需等待上…...

Redis:现代应用开发的高效内存数据存储利器

一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发&#xff0c;其初衷是为了满足他自己的一个项目需求&#xff0c;即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源&#xff0c;Redis凭借其简单易用、…...

DeepSeek源码深度解析 × 华为仓颉语言编程精粹——从MoE架构到全场景开发生态

前言 在人工智能技术飞速发展的今天&#xff0c;深度学习与大模型技术已成为推动行业变革的核心驱动力&#xff0c;而高效、灵活的开发工具与编程语言则为技术创新提供了重要支撑。本书以两大前沿技术领域为核心&#xff0c;系统性地呈现了两部深度技术著作的精华&#xff1a;…...