JS 数据结构 链表

JavaScript链表数据结构精讲与实现 本文还有配套的精品资源,点击获取 简介:本文档"vocabulary_note"深入探讨了JavaScript中链表这一重要数据结构的概念和操作。通过介绍链表的基本组成、类型以及如何在JavaScript中模拟实现链表,包括节点插入、删除、查找和遍历等操作,强调了链表在内存管理和优化编程效率方面的优势。本笔记为学习者提供了对链表及数据结构基础知识的实用理解,有助于编程实践中... 阅读详情

链表和数组

数组:

要存储多个元素,数组(或列表)可能是最常用的数据结构。

我们之前说过, 几乎每一种编程语言都有默认实现数组结构, 这种数据结构非常方便,提供了一个便利的[]语法来访问它的元素。

但是数组也有很多缺点:

数组的创建通常需要申请一段连续的内存空间(一整块的内存), 并且大小是固定的(大多数编程语言数组都是固定的), 所以当当前数组不能满足容量需求时, 需要扩容. (一般情况下是申请一个更大的数组, 比如2倍. 然后将原数组中的元素复制过去)

而且在数组开头或中间位置插入数据的成本很高, 需要进行大量元素的位移.(尽管我们已经学过的JavaScript的Array类方法可以帮我们做这些事,但背后的原理依然是这样)。

链表

要存储多个元素, 另外一个选择就是使用链表.

但不同于数组, 链表中的元素在内存中不必是连续的空间.

链表的每个元素由一个存储元素本身的节点和一个指向下一个元素的引用(有些语言称为指针或者链接)组成.

相对于数组, 链表有一些优点:

内存空间不是比是连续的. 可以充分利用计算机的内存. 实现灵活的内存动态管理.

链表不必在创建时就确定大小, 并且大小可以无限的延伸下去.

链表在插入和删除数据时, 时间复杂度可以达到O(1). 相对数组效率高很多.

相对于数组, 链表有一些缺点:

链表访问任何一个位置的元素时, 都需要从头开始访问.(无法跳过第一个元素访问任何一个元素).

无法通过下标直接访问元素, 需要从头一个个访问, 直到找到对应的问题.

什么是链表?

其实上面我们已经简单的提过了链表的结构, 我们这里更加详细的分析一下.

链表类似于火车: 有一个火车头, 火车头会连接一个节点, 节点上有乘客, 并且这个节点会连接下一个节点, 以此类推.

链表的火车结构:

链表的数据结构:

 链表常见操作

我们先来认识一下, 链表中应该有哪些常见的操作

append(element):向列表尾部添加一个新的项

insert(position, element):向列表的特定位置插入一个新的项。

remove(element):从列表中移除一项。

indexOf(element):返回元素在列表中的索引。如果列表中没有该元素则返回-1。

removeAt(position):从列表的特定位置移除一项。

isEmpty():如果链表中不包含任何元素,返回true,如果链表长度大于0则返回false。

size():返回链表包含的元素个数。与数组的length属性类似。

toString():由于列表项使用了Node类,就需要重写继承自JavaScript对象默认的toString方法,让其只输出元素的值。

方法解读:

整体你会发现操作方法和数组非常类似, 因为链表本身就是一种可以代替数组的结构.

但是某些方法实现起来有些麻烦, 所以我们一个个来慢慢实现它们

链表操作

尾部追加数据

向链表尾部追加数据可能有两种情况:

链表本身为空, 新添加的数据时唯一的节点.

链表不为空, 需要向其他节点后面追加节点.

append方法实现

// 链表尾部追加元素方法
LinkedList.prototype.append = function (element) {
    // 1.根据新元素创建节点
    var newNode = new Node(element)

    // 2.判断原来链表是否为空
    if (this.head === null) { // 链表尾空
        this.head = newNode
    } else { // 链表不为空
        // 2.1.定义变量, 保存当前找到的节点
        var current = this.head
        while (current.next) {
            current = current.next
        }

        // 2.2.找到最后一项, 将其next赋值为node
        current.next = newNode
    }

    // 3.链表长度增加1
    this.length++
}

 toString方法

// 链表的toString方法
LinkedList.prototype.toString = function () {
    // 1.定义两个变量
    var current = this.head
    var listString = ""

    // 2.循环获取链表中所有的元素
    while (current) {
        listString += "," + current.element
        current = current.next
    }

    // 3.返回最终结果
    return listString.slice(1)
}

 任意位置插入

// 根据下标删除元素
LinkedList.prototype.insert = function (position, element) {
    // 1.检测越界问题: 越界插入失败
    if (position < 0 || position > this.length) return false

    // 2.找到正确的位置, 并且插入数据
    var newNode = new Node(element)
    var current = this.head
    var previous = null
    index = 0

    // 3.判断是否列表是否在第一个位置插入
    if (position == 0) {
        newNode.next = current
        this.head = newNode
    } else {
        while (index++ < position) {
            previous = current
            current = current.next
        }
        
        newNode.next = current
        previous.next = newNode
    }
    
    // 4.length+1
    this.length++
    
    return true
}

 位置移除数据

移除数据有两种常见的方式:

根据位置移除对应的数据

根据数据, 先找到对应的位置, 再移除数据

// 根据位置移除节点
LinkedList.prototype.removeAt = function (position) {
    // 1.检测越界问题: 越界移除失败, 返回null
    if (position < 0 || position >= this.length) return null

    // 2.定义变量, 保存信息
    var current = this.head
    var previous = null
    var index = 0
    
    // 3.判断是否是移除第一项
    if (position === 0) {
        this.head = current.next
    } else {
        while (index++ < position) {
            previous = current
            current = current.next
        }
        
        previous.next = current.next
    }
    
    // 4.length-1
    this.length--
    
    // 5.返回移除的数据
    return current.element
}

 获取元素位置

// 根据元素获取链表中的位置
LinkedList.prototype.indexOf = function (element) {
    // 1.定义变量, 保存信息
    var current = this.head
    index = 0
    
    // 2.找到元素所在的位置
    while (current) {
        if (current.element === element) {
            return index
        }
        index++
        current = current.next
    }
    
    // 3.来到这个位置, 说明没有找到, 则返回-1
    return -1
}

 根据元素删除

// 根据元素删除信息
LinkedList.prototype.remove = function (element) {
    var index = this.indexOf(element)
    return this.removeAt(index)
}

 其他方法实现

isEmpty方法

// 判断链表是否为空
LinkedList.prototype.isEmpty = function () {
    return this.length == 0
}

 size方法

// 获取链表的长度
LinkedList.prototype.size = function () {
    return this.length
}

 

// 封装链表的构造函数
function LinkedList() {
    // 封装一个Node类, 用于保存每个节点信息
    function Node(element) {
        this.element = element
        this.next = null
    }

    // 链表中的属性
    this.length = 0
    this.head = null

    // 链表尾部追加元素方法
    LinkedList.prototype.append = function (element) {
        // 1.根据新元素创建节点
        var newNode = new Node(element)

        // 2.判断原来链表是否为空
        if (this.head === null) { // 链表尾空
            this.head = newNode
        } else { // 链表不为空
            // 2.1.定义变量, 保存当前找到的节点
            var current = this.head
            while (current.next) {
                current = current.next
            }

            // 2.2.找到最后一项, 将其next赋值为node
            current.next = newNode
        }

        // 3.链表长度增加1
        this.length++
    }

    // 链表的toString方法
    LinkedList.prototype.toString = function () {
        // 1.定义两个变量
        var current = this.head
        var listString = ""

        // 2.循环获取链表中所有的元素
        while (current) {
            listString += "," + current.element
            current = current.next
        }

        // 3.返回最终结果
        return listString.slice(1)
    }

    // 根据下标删除元素
    LinkedList.prototype.insert = function (position, element) {
        // 1.检测越界问题: 越界插入失败
        if (position < 0 || position > this.length) return false

        // 2.定义变量, 保存信息
        var newNode = new Node(element)
        var current = this.head
        var previous = null
        index = 0

        // 3.判断是否列表是否在第一个位置插入
        if (position == 0) {
            newNode.next = current
            this.head = newNode
        } else {
            while (index++ < position) {
                previous = current
                current = current.next
            }

            newNode.next = current
            previous.next = newNode
        }

        // 4.length+1
        this.length++

        return true
    }

    // 根据位置移除节点
    LinkedList.prototype.removeAt = function (position) {
        // 1.检测越界问题: 越界移除失败, 返回null
        if (position < 0 || position >= this.length) return null

        // 2.定义变量, 保存信息
        var current = this.head
        var previous = null
        var index = 0

        // 3.判断是否是移除第一项
        if (position === 0) {
            this.head = current.next
        } else {
            while (index++ < position) {
                previous = current
                current = current.next
            }

            previous.next = current.next
        }

        // 4.length-1
        this.length--

        // 5.返回移除的数据
        return current.element
    }

    // 根据元素获取链表中的位置
    LinkedList.prototype.indexOf = function (element) {
        // 1.定义变量, 保存信息
        var current = this.head
        index = 0

        // 2.找到元素所在的位置
        while (current) {
            if (current.element === element) {
                return index
            }
            index++
            current = current.next
        }

        // 3.来到这个位置, 说明没有找到, 则返回-1
        return -1
    }

    // 根据元素删除信息
    LinkedList.prototype.remove = function (element) {
        var index = this.indexOf(element)
        return this.removeAt(index)
    }

    // 判断链表是否为空
    LinkedList.prototype.isEmpty = function () {
        return this.length == 0
    }

    // 获取链表的长度
    LinkedList.prototype.size = function () {
        return this.length
    }

    // 获取第一个节点
    LinkedList.prototype.getFirst = function () {
        return this.head.element
    }
}

Tesseract OCR识别不准?手把手教你用PyAutoGUI提升自动点击脚本的准确率 本文针对Tesseract OCR在屏幕自动化中识别不准的问题,提供了一套完整的优化方案。通过PyAutoGUI精准截图、结合PIL和OpenCV进行图像预处理(如灰度化、对比度增强、自适应二值化),并调优Tesseract参数(如PSM模式、白名单),显著提升文本识别准确率。文章还介绍了结合模板匹配、构建容错循环等进阶技巧,帮助开发者打造高可靠性的自动点击脚本。 阅读详情

相关推荐

DCN交换机通过boot模式升级

LIC导入成功后,输入enable进入特权模式,把网线接到通讯网口上,配置好对应interface vlan地址,在enable模式用 copy tftp://x.x.x.x/xxxxxx_nos.img nos.img待提示write ok时,reload设备完成升级。交换机启动后,在显示以下信息时输入“Ctrl+B”,一定得是手动按“Ctrl+B”进入的boot模式才能正常升级。升级交换机成功,在BootROM模式下,执行命令run或reboot,回到CLI配置界面。# 交换机通过boot模式升级。

m0_72501865的博客 947

数组和链表的区别及JS转换

链表结构其实是内存内部的一种存储方式,链表则是把一系列节点串联起来,每个节点上至少包含两个部分:数据域与指针域。数据:保存数据;指针:指向下一个节点的引用;链表中的每个节点,通过指针域的值,形成一个线性结构。

qq_54083224的博客 768

智能网联汽车云控系统核心解析:车云数据交互协议设计与实践

本文深入解析了智能网联汽车云控系统的核心——车云数据交互协议的设计与实践。文章围绕“说什么”、“怎么说”及异常处理三大核心问题,详细阐述了二进制与结构体数据类型定义、TCP/UDP双通道传输机制、通用报文格式以及典型交互流程(如GLOSA车速引导),并分享了时间同步、坐标系定义等关键实战经验与避坑指南,为构建高效、可靠、安全的车云“神经系统”提供专业指导。

alice7model的博客 121

JS链表系列

什么是链表,链表是一种通过指针串联在一起的线性结构,每一个节由两部分组成,一个是数据域,一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思)链接的入口节点称为链表头节点也就是head。.........

qq_48701993的博客 2259

OpenClaw 多代理协同工作模式配置指南

OpenClaw 采用。

形上得其象,形下合于数;阴阳自济,玄理自明。 1万+

蓝桥杯 stm32 PWM 测量频率

参考 数据手册:比赛 的板子 上面有两个信号发生器,如下图。通过 扭动 可变电阻 (R40, R39), 来实现 PWM 频率的改变。PA15PB4。PA15,PB4分别使用TIM2_CH1TIM3_CH1来对频率进行捕获。

wuyiyu_的博客 2931

js数据结构(数组和链表) -- 算法图解方式讲解

数据结构,数组,链表

qq_24832277的博客 1356

【OpenFOAM】-olaFlow-算例4- irreg45degTank

不规则波浪模拟

ou_no的博客 2117

JS 数据结构:链表

本文介绍了什么是链表以及他的优缺点,并分别介绍了单链表、双向链表和循环链表之间的细微差别和各自的特点,一些有明显差异的操作都分别给出了图和代码,更易于理解和实践。

weixin_46015333的博客 4443

Open3D(C++) 点云构建三维Delaunay三角剖分

C++版本的Open3D实现从点云构建三维Delaunay,可视化效果。

点云侠的博客 2247

ISO 21434汽车网络安全标准深度解读系列(十):标准实施总结与展望

ISO21434标准深度解读系列总结篇系统回顾了汽车网络安全标准的核心内容与实施要点。文章梳理了10篇系列文章的结构体系,提炼出标准的三大核心价值:系统性方法(全生命周期覆盖、多层次管理)、风险导向理念(威胁驱动、动态管理)和供应链协同机制。总结了实施经验中的关键要素,包括高层承诺、专业团队建设,并提出了分阶段实施路径建议。同时分析了当前面临的技术挑战(系统复杂性、新兴技术)和管理挑战(文化转变、资源投入)。最后展望了AI应用、零信任架构等技术发展趋势,以及标准未来的演进方向,为企业实施提供战略与执行层面的

VehSwHwDeveloper的博客 559

JavaScript基础之链式赋值的坑

链式赋值要慎用

parade岁月的博客 1496

【Claude Code 源码解析教程】总体大纲

本教程旨在深入解析 Anthropic Claude Code 项目的源码架构和实现细节。Claude Code 是一个基于 TypeScript + Bun 构建的 AI 编程助手 CLI 工具,代号 "Tengu",具有复杂的多模块架构和丰富的功能特性。本教程基于Claude Code 的源码分析来生成,将帮助您全面掌握 Claude Code 的源码架构和实现细节,为开发类似 AI 编程助手工具奠定坚实基础。

rengang66的博客 387

js(JavaScript)数据结构之链表(Linked List)

链表(Linked List)是一种常见的数据结构,它由一系列节点组成,每个节点都包含了数据和指向下一个节点的指针。

星辰迷上大海的博客 2873

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

JavaScript数据结构——链表

前言 嘿,掘友们!今天我们来了解并实现数据结构 —— 链表。 本文主要内容 单向链表 双向链表 循环链表 链表 要存储多个元素,数组可能是最常用的数据结构。但是这种数据结构有一个缺点,数组的大小是固定的,从数组的起点或中间插入或移除的成本很高,因为需要移动元素。 链表存储有序的元素集合,不同于数组的是,链表中的元素在内存中并不是连续放置的。每个元素由一个存储元素本身的节点和一个指向下一个元素的引用(指针或链接)组成。下图是一个链表的结构。 相比数组,链表的一个好处在于,添加或移除元素的时候不需要移动其

郊眠寺 1483

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

JavaScript数据结构与算法学习总结--链表

数据结构与算法这个内容很多人一听都会觉得头大,我在最开始接触到的时候也是云里雾里。因为大一刚学编程的时候,一直连入门都如不进去,导致后来学习数据结构和算法也提不起兴趣。直到开始接触Web前端,学习了JavaScript这门脚本语言,便想学习一些基于JS的数据结构与算法知识,并且记录下来。于是便有了这篇博客~     数据结构分为线性结构与非线性结构,我觉得线性结构相对于非线性结构更好理解一些。而

qq_28581549的博客 1171

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

js数据结构之链表

在经过为期10天左右的苦逼的数据结构的学习,终于在今天用js实现了单链表。学习的时候是用c语言学的,奈何c语言一般,实现起来特别难。不过它的主要思想还是可以理解的。今天看着别人的博客,自己也跟着他们去实现。我这个的话是没有头节点而是头指针,代码里面也有注释,之后希望还可以去实现树结构,再次分享,请多多指教! //创建结点 function Node(element) { ...

qq_43817972的博客 192

javascript数据结构-链表

1. 链表数据结构 链表存储有序的元素集合,但不同于数组,链表中的元素在内存中并不算连续放置的。每个元素由一个存储元素本身的节点和一个指向下一个元素的引用(也称指针或链接)组成。下图展示一个链表结构: 相对于传统的数组,链表的一个好处在于,添加或移除元素的时候不需要移动其他元素。然而,链表需要使用指针,因此实现链表时需要额外注意。在数组中,我们可以直接访问任何位置的任何元素,而想要访问链表中间的一个元素,则需要从起点(表头)开始迭代链表直到找到所需的元素。 可以用火车来说明链表。每节车厢都是链表的元素,车

Y 814

【JS数据结构】单向链表

一. 认识链表 1.数组 1.1 数组的优点 1.2 数组的缺点 2.链表 2.1 相对于数组, 链表有一些优点 2.2 相对于数组, 链表有一些缺点 3.什么是链表 3.1 链表的火车结构 3.2 链表的数据结构 3.3 给火车加上数据后的结构 二. 链表封装 1.创建链表类 1.1 创建一个链表类 1.2 代码解析 2.链表常见操作 2.1append(element)尾部追加数据 2.2 toString()转成字符串 2.3 insert(position

早睡早起长头发的博客 1225

JavaScript数据结构之链表

链表 存储多个元素,最常用的就是使用数组,但是,在很多编程语言中,数组的长度是固定的,当数组被数据填满时,想要再加入元素就会很困难。在数组中,添加和删除元素也比较麻烦,因为需要将数组中的其他元素进行向前或者向后平移。 虽然JavaScript使用 split() 方法不需要再访问数组中的其他元素,不存在上述的问题,但是js把数组实现成了对象,与其他语言(比如 C++ 和 Java) 的数组相比,效...

qq_42880714的博客 390

JavaScript 数据结构(五):链表

链表是线性表的一种,所谓的线性表包含顺序线性表和链表,顺序线性表是用数组实现的,在内存中有顺序排列,通过改变数组大小实现。而链表不是用顺序实现的,其使用指针实现,在内存中不连续。意思就是说,链表将一系列不连续的内存联系起来,将那种碎片内存进行合理的利用,解决空间问题。

Amecai的学习博客 759

在JavaScript中的数据结构(链表)

链表是多个元素组成的列表,元素存储不连续,用next指针连接到一起,JS中没有链表,但是可以用Object模拟链表。

肥晨开发的学习之路 1888

JavaScript数据结构——链表数据结构

链表存储有序的元素集合,但不同于数组,链表中的元素在内存中并不是连续放置的。每个元素由一个存储元素本身的节点和指向下一个元素的引用(也称指针或链接)组成。 创建链表,并实现一些方法: push(element): 向链表尾部添加一个新元素。 insert(element, position): 向链表的特定位置添加一个新元素。 getElementAt(index): 返回链表中特定位置的元素。如果链表中不存在这样的元素则返回undefined。 remove(element): 从链表中移除一个

Jyao_In的博客 515

【必学系列】JavaScript中的数据结构—链表

作者:Hanpeng_Chen 公众号:前端极客技术 文章首发个人博客:[JavaScript中的数据结构—链表 | 代码视界](http://www.chenhanpeng.com/javascript-linked-list/ 前) 前言 数据结构与算法在前端开发工程师的日常工作中也许不常用,但在这对前端工程师要求日益提高的时代,如果对数据结构、算法思维、代码效率等知识拥有足够的储备,那么我们将拥有更强的竞争力。 话不多说,我们接下来学习一种数据结构:链表(Linked list)。 链表 数组对于.

HanpengChen的博客 610

js实现链表的数据结构

// Js实现链表------------------一定要画图!!!!!!! class Node { constructor(element) { // 节点的数据 this.element = element; // 节点的指针 this.next = null } } class LinkedList { constructor() { // 链表的头部首先为空 this.h.

qq_15506981的博客 318

JavaScript数据结构与算法 — 单向链表

链表存储的是有序的元素集合,但不同于数组,链表中的元素在内存中并不是连续放置的。每个元素由一个存储元素本身的节点和一个指向下一个元素的引用(也称为指针或链接)组成。相对于传统的数组,链表的一个好处在于,添加或者移除元素的时候不需要移动其他元素。然而,链表需要使用指针,因此实现链表时需要额外注意。在数组中,我们可以直接访问任何位置的任何元素,而要向访问链表中间的一个元素,则需要从起点(表头)开始迭代链表直到找到所需的元素。(学习JavaScript数据结构与算法(第三版))记录学习,当个笔记。

qq_47538417的博客 610
上一篇: JS 数据结构之队列结构
下一篇: JS 数据结构双向链表
Ax3_28
博客等级 码龄4年 60粉丝 52原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值