链表及链表的常见操作和用js封装一个链表
最近在学数据结构和算法,正好将学习的东西记录下来,我是跟着一个b站博主学习的,是使用js来进行讲解的,待会也会在文章后面附上视频链接地址,大家想学习的可以去看看
本文主要讲解单向链表,双向链表后续也会更新
一、什么是链表

二、链表的的常见操作

三、链表的封装
1、append方法
// 封装 append 追加方法
LinkedList.prototype.append = function() {// 1、创建新的节点var newNode = new Node(data)// 2、判断添加的是否为第一个节点if (this.length == 0) { // 2.1 是第一个节点this.head = newNode} else { // 2.2 不是第一个节点// 找到最后一个节点var current = this.headwhile (current.next) { // 判断下一个节点是否为 null ,如果为 null 就跳出循环,如果不为 null ,就继续往后寻找,一直找到最后的节点current = current.next}// 最后节点的next指向新的节点current.next = newNode}this.length += 1
}
2、toString 方法
// 封装 toString 字符串方法
LinkedList.prototype.toString = function() {// 1、定义变量指向头结点var current = this.headvar listString = "" // 定义变量存储字符串// 2、循环获取每一个节点while (current) {listString += current.data + " "current = current.next // 将头结点指向下一个节点}// 返回字符串return listString
}
3、insert 方法
// 封装 insert 插入方法
LinkedList.prototype.insert = function(position, data) { // position 为插入的位置,data 为插入的值// 1、对 position 进行越界判断if (position < 0 || position > this.length) return false// 2、根据 data 创建 newNodevar newNode = new Node(data)// 3、判断插入的位置是否是第一个if (position == 0) {newNode.next = this.head // 先将新节点的 next 指向当前头节点,因为当前头节点指向下一个节点this.head = newNode // 再将头结点指向新节点} else {var index = 0 // 定义一个索引值var current = this.head // 定义一个当前的值为头节点var previous = null // 定义一个比当前节点靠前的一个节点while (index++ < position) { // 判断索引值与插入的位置进行比较,如果小于要插入的位置,就依次找到当前值与前一个值previous = currentcurrent = current.next}newNode.next = current // 将新节点的 next 指向当前的值previous.next = newNode // 将前一个值的 next 指向新的节点}// 4、更新长度 length+1this.length += 1return true
}
4、get 方法
// 4、封装 get 获取方法
LinkedList.prototype.get = function(position) {// 1、越界判断if(position < 0 || position >= this.length) return null// 2、获取对应的 data var current = this.head // 定义当前值为头节点var index = 0 // 定义索引值为0while(index++ < position){ // 循环找到需要的 position 对应位置的值current = current.next}return current.next
}
5、indexOf 方法
// 5、封装 indexOf 返回指定数据的下标值方法
LinkedList.prototype.indexOf = function(data) {// 1、定义变量var current = this.headvar index = 0// 2、开始查找while (current) { // 判断current是否为null,如果为null才退出循环if (current.data == data) { // 判断当前current的值是否为要查找的值,如果是,直接返回对应下标,如果不是,继续往后找return index}current = current.nextindex += 1}// 3、找到最后没有找到,返回 -1return -1
}
6、update 方法
// 6、封装 update 更新指定位置数据的方法
LinkedList.prototype.update = function(position, newData) {// 1、越界判断if (position < 0 || position >= this.length) return false// 2、查找正确的节点var current = this.headvar index = 0while (index++ < position) {current = current.next}// 3、将 position 位置的 node 的 data 修改成 newDatacurrent.data = newDatareturn true
}
7、removeAt 方法
// 7、封装 removeAt 删除指定位置的节点方法
LinkedList.prototype.removeAt = function(position) {// 1、越界判断if (position < 0 || position >= this.length) return null// 2、判断是否删除的是第一个节点var current = this.headif (position == 0) {this.head = this.head.next // 如果删除的是第一个节点,直接将头节点指向下一个节点} else {var index = 0var previous = nullwhile (index++ < position) {previous = currentcurrent = current.next}// 找到要删除的节点,然后将这个节点的前一个节点的 next 指向这个节点的下个节点previous.next = current.next}// 3、length-1this.length -= 1return current.data // 删除节点一般会返回要删除的这个值
}
8、remove 方法
// 8、封装 remove 删除指定数据的节点的方法
LinkedList.prototype.remove = function(data) {// 1、获取 data 在列表中的位置var position = this.indexOf(data)// 2、根据位置信息,删除节点return this.removeAt(position)
}
9、isEmpty方法
// 9、封装 isEmpty 判断链表是否为空方法
LinkedList.prototype.isEmpty = function() {return this.length == 0
}
10、size方法
// 10、封装 size 返回链表长度方法
LinkedList.prototype.size = function() {return this.length
}
完整代码加测试代码
// 封装链表类
function LinkedList() {// 封装内部的类:节点类function Node(data) {this.data = datathis.next = null}// 封装属性this.head = null// 封装链表的长度this.length = 0// 1、封装 append 追加方法LinkedList.prototype.append = function(data) {// 1、创建新的节点var newNode = new Node(data)// 2、判断添加的是否为第一个节点if (this.length == 0) { // 2.1 是第一个节点this.head = newNode} else { // 2.2 不是第一个节点// 找到最后一个节点var current = this.headwhile (current.next) { // 判断下一个节点是否为 null ,如果为 null 就跳出循环,如果不为 null ,就继续往后寻找,一直找到最后的节点current = current.next}// 最后节点的next指向新的节点current.next = newNode}this.length += 1}// 2、封装 toString 字符串方法LinkedList.prototype.toString = function() {// 1、定义变量指向头结点var current = this.headvar listString = "" // 定义变量存储字符串// 2、循环获取每一个节点while (current) {listString += current.data + " "current = current.next // 将头结点指向下一个节点}// 返回字符串return listString}// 3、封装 insert 插入方法LinkedList.prototype.insert = function(position, data) { // position 为插入的位置,data 为插入的值// 1、对 position 进行越界判断if (position < 0 || position > this.length) return false// 2、根据 data 创建 newNodevar newNode = new Node(data)// 3、判断插入的位置是否是第一个if (position == 0) {newNode.next = this.head // 先将新节点的 next 指向当前头节点,因为当前头节点指向下一个节点this.head = newNode // 再将头结点指向新节点} else {var index = 0 // 定义一个索引值var current = this.head // 定义一个当前的值为头节点var previous = null // 定义一个比当前节点靠前的一个节点while (index++ < position) { // 判断索引值与插入的位置进行比较,如果小于要插入的位置,就依次找到当前值与前一个值previous = currentcurrent = current.next}newNode.next = current // 将新节点的 next 指向当前的值previous.next = newNode // 将前一个值的 next 指向新的节点}// 4、更新长度 length+1this.length += 1return true}// 4、封装 get 获取方法LinkedList.prototype.get = function(position) {// 1、越界判断if (position < 0 || position >= this.length) return null// 2、获取对应的 data var current = this.head // 定义当前值为头节点var index = 0 // 定义索引值为0while (index++ < position) { // 循环找到需要的 position 对应位置的值current = current.next}return current.data}// 5、封装 indexOf 返回指定数据的下标值方法LinkedList.prototype.indexOf = function(data) {// 1、定义变量var current = this.headvar index = 0// 2、开始查找while (current) { // 判断current是否为null,如果为null才退出循环if (current.data == data) { // 判断当前current的值是否为要查找的值,如果是,直接返回对应下标,如果不是,继续往后找return index}current = current.nextindex += 1}// 3、找到最后没有找到,返回 -1return -1}// 6、封装 update 更新指定位置数据的方法LinkedList.prototype.update = function(position, newData) {// 1、越界判断if (position < 0 || position >= this.length) return false// 2、查找正确的节点var current = this.headvar index = 0while (index++ < position) {current = current.next}// 3、将 position 位置的 node 的 data 修改成 newDatacurrent.data = newDatareturn true}// 7、封装 removeAt 删除指定位置的节点方法LinkedList.prototype.removeAt = function(position) {// 1、越界判断if (position < 0 || position >= this.length) return null// 2、判断是否删除的是第一个节点var current = this.headif (position == 0) {this.head = this.head.next // 如果删除的是第一个节点,直接将头节点指向下一个节点} else {var index = 0var previous = nullwhile (index++ < position) {previous = currentcurrent = current.next}// 找到要删除的节点,然后将这个节点的前一个节点的 next 指向这个节点的下个节点previous.next = current.next}// 3、length-1this.length -= 1return current.data // 删除节点一般会返回要删除的这个值}// 8、封装 remove 删除指定数据的节点的方法LinkedList.prototype.remove = function(data) {// 1、获取 data 在列表中的位置var position = this.indexOf(data)// 2、根据位置信息,删除节点return this.removeAt(position)}// 9、封装 isEmpty 判断链表是否为空方法LinkedList.prototype.isEmpty = function() {return this.length == 0}// 10、封装 size 返回链表长度方法LinkedList.prototype.size = function() {return this.length}}// 测试代码
// 1、创建LinkedList
var list = new LinkedList()// 2、测试append方法
list.append('abc')
list.append('tng')
console.log(list.toString());// 3、测试insert方法
list.insert(1, '12')
list.insert(2, '333')
console.log(list.toString());// 4、测试get方法
console.log(list.get(0));
console.log(list.get(1));
console.log(list.get(2));
console.log(list.get(3));// 5、测试indexOf方法
console.log(list.indexOf('333'));// 6、测试update方法
list.update(0, '999')
list.update(1, '888')
console.log(list.toString());// 7、测试removeAt方法
list.removeAt(0)
console.log(list.removeAt(1));
console.log(list.toString());// 8、测试remove方法
list.remove('tng')
console.log(list.toString());// 9、测试isEmpty方法
list.isEmpty()
console.log(list.isEmpty());// 10、测试size方法
list.size()
console.log(list.size());
下面附上b站视频链接,需要学习的可以去看看(JavaScript算法与数据结构)
相关文章:
链表及链表的常见操作和用js封装一个链表
最近在学数据结构和算法,正好将学习的东西记录下来,我是跟着一个b站博主学习的,是使用js来进行讲解的,待会也会在文章后面附上视频链接地址,大家想学习的可以去看看 本文主要讲解单向链表,双向链表后续也会…...
源码安装工具checkinstall使用
每当从源码包编译程序时,安装过程很愉快,但当你想删除时,就很费脑筋了,你可能要去找你当时编译的目录执行make unistall,当然更可能的是,你早就把源码包给删除了,对于强迫症来说,这显…...
离散数学集合论
集合论 主要内容 集合基本概念 属于、包含幂集、空集文氏图等 集合的基本运算 并、交、补、差等 集合恒等式 集合运算的算律,恒等式的证明方法 集合的基本概念 集合的定义 集合没有明确的数学定义 理解:由离散个体构成的整体称为集合,…...
TypeScript 基础
类型注解 类型注解:约束变量的类型 示例代码: let age:number 18 说明:代码中的 :number 就是类型注解 解释:约定了类型,就只能给变量赋值该类型的值,否则,就会报错 错误演示:…...
MySQL InnoDB引擎 和 Oracle SGA
MySQL InnoDB引擎和Oracle SGA有以下异同: 异同点: 两者都是用来管理数据存储和访问的。 它们都可以通过调整参数来优化性能。 它们都支持事务处理和ACID属性。 它们都可以通过备份和恢复来保护数据。 异点: MySQL InnoDB引擎是一种存储…...
JAVA开发与运维(web生产环境部署)
web生产环境部署,往往是分布式,和开发环境或者测试环境我们一般使用单机不同。 一、部署内容 1、后端服务 2、后台管理系统vue 3、小程序 二、所需要服务器 5台前端服务器 8台后端服务 三、所需要的第三方组件 redismysqlclbOSSCDNWAFRocketMQ…...
普通人,自学编程,5个必备步骤
天给大家分享个干货哈 普通人自学编程 想学成找到一份工作甚至进大厂 非常有效且必备的5个步骤 文章最后 还给大家提供了一些免费的学习资料 记得提前收藏起来 相信很多人在最开始学编程的时候 上来就是去网上找一套视频 或者买一本书直接开干 这种简单粗暴的方法其实是不对的 …...
kubernetes安全框架RBAC
目录 一、Kubernetes 安全概述 二、鉴权、授权和准入控制 2.1 鉴权(Authentication) 2.2 授权(Authorization) 2.3 准入控制 三、基于角色的权限访问控制: RBAC 四、案例:为指定用户授权访问不同命名空间权限 一、Kubernetes 安全概述 K8S安全控…...
【大数据面试题大全】大数据真实面试题(持续更新)
【大数据面试题大全】大数据真实面试题(持续更新) 1)Java1.1.Java 中的集合1.2.Java 中的多线程如何实现1.3.Java 中的 JavaBean 怎么进行去重1.4.Java 中 和 equals 有什么区别1.5.Java 中的任务定时调度器 2)SQL2.1.SQL 中的聚…...
Linux [常见指令 (1)]
Linux常见指令 ⑴ 1. 操作系统1.1什么事操作系统1.2选择指令的原因 2.使用工具3.Linux的指令操作3.1mkdir指令描述:用法:例子 mkdir 目录名例子 mkdir -p 目录1/ 目录2/ 目录3 3.2 touch指令描述:用法:例子 touch 文件 3.2pwd指令描述:用法:例子 pwd 3.4cd指令描述:用法:例子 c…...
进程控制下篇
进程控制下篇 1.进程创建 1.1认识fork / vfork 在linux中fork函数时非常重要的函数,它从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程 #include<unistd.h> int main() {pid_t i fork;return 0; }当前进程调用fork,…...
PS学习笔记(零基础PS学习教程)
很多新手学习PS不知从何下手,做设计的第一阶段肯定是打牢基础,把工具用熟练;本期特别为大家整理了PS入门的学习笔记,把每个工具的用法整理了下来,在使用过程中有哪里不清楚的可以翻看来看看~ 一、ps的工作界面的介绍 …...
如何构建数据血缘系统
1、明确需求,确定边界 在进行血缘系统构建之前,需要进行需求调研,明确血缘系统的主要功能,从而确定血缘系统的最细节点粒度,实体边界范围。 例如节点粒度是否需要精确到字段级,或是表级。一般来说&#x…...
IPsec中IKE与ISAKMP过程分析(主模式-消息3)
IPsec中IKE与ISAKMP过程分析(主模式-消息1)_搞搞搞高傲的博客-CSDN博客 IPsec中IKE与ISAKMP过程分析(主模式-消息2)_搞搞搞高傲的博客-CSDN博客 阶段目标过程消息IKE第一阶段建立一个ISAKMP SA实现通信双发的身份鉴别和密钥交换&…...
深度学习技巧应用10-PyTorch框架中早停法类的构建与运用
大家好,我是微学AI,今天给大家介绍一下深度学习技巧应用10-PyTorch框架中早停法类的构建与运用,文章将介绍深度学习训练过程中的一个重要技巧—早停法,以及如何在PyTorch框架中实现早停法。文章将从早停法原理和实践出发,结合实际案例剖析早停法的优缺点及在PyTorch中的应…...
Linux文件系统权限
目录标题 文件权限文件和目录的一般权限文件的权限针对三类对象进行定义文件和目录中,r、w、x的作用 设置文件和目录的一般权限修改文件或目录的权限—chmod(change mode)命令权限值的表示方法—使用3位八进制数表示权限值的表示方法—使用字符串表示修改文件或目录…...
ctfshow之_萌新web1至web7
一、访问在线靶场ctfshow ctf.showhttps://ctf.show/challenges如下图所示,进入_萌新赛的web1问题: 如上图所示,页面代码提示id1000时,可以查询到flag,进行如下尝试: 如下图所示,传入参数id1时…...
HPDA的资料
HPDA,英文全称为High Performance Data Analysis,直译为高性能数据分析。 适用场景 机器学习大数据分析 技术挑战 大量的元数据操作数据的同步随机读写高IOPOS的小IO请求高带宽的文件请求 技术关键字 存算分离移动计算大I/O直通,小I/O聚…...
项目管理软件可以用来做什么?这篇文章说清楚了
项目管理软件是用来干嘛的,就得看对项目的理解。项目是为创造独特的产品、服务或成果而进行的临时性工作。建造一座大楼可以是一个项目,进行一次旅游活动、日常办公活动、期末考试复习等也都可以看成一个项目。 项目管理不善会导致项目超时、超支、返工、…...
ETL工具 - Kettle 转换算子介绍
一、Kettle 转换算子 上篇文章对 Kettle 中的输入输出算子进行了介绍,本篇文章继续对转换算子进行讲解。 下面是上篇文章的地址: ETL工具 - Kettle 输入输出算子介绍 转换是ETL里面的T(Transform),主要做数据转换&am…...
管 Vibe Coding 项目,就像管公共厕所
本文整理自"AI炼金术"播客对徐文浩的访谈,探讨 AI 辅助编程(Vibe Coding)在组织落地后面临的治理挑战和应对策略。从"屎山三年一遇"到"屎山月月有"传统软件开发中,一个系统的"屎山化"通常…...
开关电源EMC设计:从原理到实践的关键技术
1. 开关电源EMC设计基础 开关电源因其高效率和小型化优势,在现代电子设备中广泛应用。然而,高频开关动作带来的电磁干扰(EMI)问题不容忽视。作为一名电源工程师,我经常需要面对各种EMC挑战。记得有一次,我们团队设计的工业电源模块…...
Rails控制台集成AI助手:ask_chatgpt Gem的实践指南
1. 项目概述:在Rails控制台里装一个AI助手 如果你是一个Ruby on Rails开发者,并且每天都在跟Rails控制台( rails console )打交道,那你肯定有过这样的时刻:盯着一段复杂的ActiveRecord查询,或…...
终极开源硬件控制方案:5分钟实现OMEN游戏本深度性能调优
终极开源硬件控制方案:5分钟实现OMEN游戏本深度性能调优 【免费下载链接】OmenSuperHub 使用 WMI BIOS控制性能和风扇速度,自动解除DB功耗限制。 项目地址: https://gitcode.com/gh_mirrors/om/OmenSuperHub OmenSuperHub是一款专为惠普OMEN游戏本…...
抖音图片怎么去水印?2026实测去水印方法全整理,免费工具一并推荐
抖音图片怎么去水印?2026实测去水印方法全整理,免费工具一并推荐 每次在抖音刷到一张好看的图,长按保存下来却发现角落盖着一行"昵称抖音"水印,这种体验相信不少人都经历过。水印不影响欣赏还好,但如果想把图…...
基于Helm与Kubernetes的以太坊节点自动化部署与运维实战
1. 项目概述:当以太坊遇见Kubernetes如果你和我一样,在区块链基础设施领域摸爬滚打多年,从早期手动编译客户端、配置systemd服务,到后来用Docker Compose编排节点,每一步都伴随着大量的重复劳动和运维痛点。当节点数量…...
Python 爬虫高级实战:爬虫接口限流自适应调节
前言 网络目标站点普遍具备严格的接口访问限流、频率校验、IP 频次风控、接口令牌校验等防护机制,常规固定延时、固定并发的爬虫模式极易触发封禁、接口 429 限流、会话失效、IP 拉黑等问题。人工配置延时、手动调整并发阈值的传统方式,无法适配站点动态…...
Cognize-Agent™空间智能体,98.5%故障预警准确率,终结非计划停机
Cognize-Agent™空间智能体,98.5%故障预警准确率,终结非计划停机工业制造领域,设备非计划停机始终是制约生产效率、拉高运维成本的核心痛点。传统设备运维依赖定期检修、事后抢修,依赖人工巡检与单一数据监测,无法提前…...
从CuteCom到代码:手把手教你用I.MX6ULL实现串口双向通信(附完整工程源码)
从CuteCom到代码:手把手教你用I.MX6ULL实现串口双向通信(附完整工程源码) 在嵌入式开发中,串口通信是最基础也最常用的调试手段之一。无论是简单的数据收发,还是复杂的协议交互,串口都能提供稳定可靠的通信…...
用o1-preview构建端到端水质分类系统
1. 项目概述:用 o1-preview 构建端到端水质分类系统的真实复现手记 我做机器学习项目快十年了,从最早手动调参、写 Makefile 编译模型,到后来用 MLflow 跟踪实验、用 Flask 封装 API,再到如今用 Docker 打包上云——整个流程早已刻…...
