【TypeScript】常见数据结构与算法(二):链表

文章目录

    • 链表结构(LinkedList)
      • 链表以及数组的缺点
        • 数组
        • 链表的优势
      • 什么是链表?
      • 封装链表相关方法
      • 源码
        • 链表常见面试题
          • 237-删除链表中的节点
          • 206 - 反转链表
      • 数组和链表的复杂度对比

链表结构(LinkedList)

链表以及数组的缺点

  • 链表和数组一样,可以用于存储一系列的元素,但是链表和数组的实现机制完全不同。
  • 这一章中,我们就来学习一下另外一种非常常见的用于存储数据的线性结构:链表。
数组
  • 要存储多个元素,数组(或称为链表)可能是最常用的数据结构。
  • 我们之前说过,几乎每一种编程语言都有默认实现数组结构。

但是数组也有很多缺点

  • 数组的创建通常需要申请一段连续的内存空间(一整块的内存),并且大小是固定的(大多数编程语言数组都是固定的),所以当当前数组不能满足容量需求时,需要扩容。(一般情况下是申请一个更大的数组,比如2倍。然后将原数组中的元素复制过去
  • 而且在数组开头或中间位置插入数据的成本很高,需要进行大量元素的位移。
  • 尽管JavaScript的Array底层可以帮我们做这些事,但背后的原理依然是这样。
链表的优势

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

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

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

相对于数组,链表的优势:

  • 内存空间不是必须连续的。

    √可以充分利用计算机的内存,实现灵活的内存动态管理。

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

  • 链表在插入和删除数据时,时间复杂度可以达到O(1)

    √相对数组效率高很多

相对数组,链表的缺点:

  • 链表访问任何一个位置的元素时,都要从头开始访问。(无法跳过第一个元素访问任何一个元素)。
  • 无法通过下标直接访问元素,需要从头一个个访问,直到找到对应元素。

什么是链表?

  • 其实上面我们已经简单的提过了链表的结构,我们这里更加详细的分析一下。
  • 链表类似于火车:有一个火车头,火车头会连接一个节点,节点上有乘客(类似于数据),并且这个节点会连接下一个节点,以此类推。

image.png

image.png

封装链表相关方法

我们先来认识一下,链表中应该有哪些常见的操作
append(element):向链表尾部添加一个新的项
insert(position,element):向链表的特定位置插入一个新的项。
image.png
get(position):获取对应位置的元素
image.png
indexOf(element):返回元素在链表中的索引。如果链表中没有该元素则返回-1。
update(position,element):修改某个位置的元素
removeAt(position):从链表的特定位置移除一项。
image.png
remove(element):从链表中移除一项。
isEmpty():如果链表中不包含任何元素,返回true,如果链表长度大于0则返回false。
size():返回链表包含的元素个数。与数组的length属性类似。

源码

// 1.创建Node节点类
class Node<T> {value: T;next: Node<T> | null = null;constructor(value: T) {this.value = value;}
}// 2.创建LinkedList的类
class LinkedList<T> {private head: Node<T> | null = null;private size: number = 0;get length() {return this.size;}// 封装私有方法// 根绝positon获取当前的节点(不是节点的value,而是获取节点)private getNode(position: number): Node<T> | null {let index = 0;let current = this.head;while (index++ < position && current) {current = current.next;}return current;}// 追加节点append(value: T) {// 1.根据value新建一个Node节点const newNode = new Node(value);// 2.if (!this.head) {this.head = newNode;} else {let current = this.head;while (current.next) {current = current.next;}// current肯定指向最后一个节点current.next = newNode;}// 3.size++this.size++;}// 遍历链表的方法traverse() {const values: T[] = [];let current = this.head;while (current) {values.push(current.value);current = current.next;}console.log(values.join(" -> "));}//链表插入元素的方法insert(value: T, position: number): boolean {// 1.越界判断if (position < 0 || position > this.size) return false;// 2.根据value创建新的节点const newNode = new Node(value);/* 3.判断* 是否插入头部* 否则就找到需要插入的位置,然后记录前一个节点和当前节点,在前一个节点的next等于newNode,newNode的next等于后一个节点*/if (position === 0) {newNode.next = this.head;this.head = newNode;} else {const previous = this.getNode(position - 1);newNode.next = previous!.next;previous!.next = newNode;}this.size++;return true;}//链表插入元素的方法removeAt(position: number): T | null {// 1.越界判断if (position < 0 || position >= this.size) return null;let current = this.head;if (position === 0) {this.head = current?.next ?? null;} else {const previous = this.getNode(position - 1);previous!.next = previous?.next?.next ?? null;}this.size--;return current?.value ?? null;}// 获取方法get(position: number): T | null {if (position < 0 || position >= this.size) return null;return this.getNode(position)?.value ?? null;}// 更新方法update(value: T, position: number): boolean {if (position < 0 || position >= this.size) return false;const currentNode = this.getNode(position);currentNode!.value = value;return true;}// 根据值获取该值位置索引indexOf(value: T): number {let current = this.head;let index = 0;while (current) {if (current.value === value) {return index;}index++;current = current.next;}return -1;}// 删除方法,根据value删除remove(value: T): T | null {const index = this.indexOf(value);return this.removeAt(index);}// 判断单链表是否为空的方法isEmpty() {return this.size === 0;}
}export {};
链表常见面试题
237-删除链表中的节点
  • https://leetcode.cn/problems/delete-node-in-a-linked-list/

image.png
解题

// Definition for singly-linked list.
class ListNode {val: number;next: ListNode | null;constructor(val?: number, next?: ListNode | null) {this.val = val === undefined ? 0 : val;this.next = next === undefined ? null : next;}
}/**Do not return anything, modify it in-place instead.*/
function deleteNode(node: ListNode | null): void {node!.val = node!.next!.valnode!.next = node!.next!.next
}
206 - 反转链表
  • https://leetcode.cn/problems/reverse-linked-list/

image.png

  • 用栈结构解决
function reverseList(head: ListNode | null): ListNode | null {if(head === null) return nullif(head.next === null) return headconst stack:ListNode[] = []let current:ListNode | null = headwhile(current) {stack.push(current)current = current.next}const newHead:ListNode = stack.pop()!let newHeadCurrent = newHeadwhile(stack.length) {const node = stack.pop()!newHeadCurrent.next = nodenewHeadCurrent = newHeadCurrent.next}newHeadCurrent.next = nullreturn newHead
};
  • 用非递归解题
function reverseList(head: ListNode | null): ListNode | null {if (head === null || head.next === null) return head;let newHead: ListNode | null = null;// 1.next = 2, 2.next = 3, 3.next = 4while (head) {// 让current指向下一个节点// 目的:保留下个节点的引用,可以拿到,并且不会销毁(current = 2)const current= head.next;// 改变head当前指向的节点,指向newHead// 这里反转链表对于第一节点来说,指向newHead就是null(1.next = null)head.next = newHead;// 让newhead指向head节点// 这里开始准备反转新的节点,目的是下一次遍历时,可以让下一个节点指向第一个节点(newHead = 1)newHead = head;// 让head指向下个节点也就是current(head = 2)head = current;}return newHead;
}

image.png

  • 用递归方案解题
function reverseList(head: ListNode | null): ListNode | null {// 递归停止条件,当递归到最后一个节点时停止if (head === null || head.next === null) return head;// 一直递归循环直到符合head === null 时停止递归// 那么拿到的就是链表倒数第二个节点const newHead = reverseList(head.next ?? null)// 反转链表,让最后一个节点指向head开始正式反转head.next.next = head// 让倒数第二个节点的next指向nullhead.next = null// 最后递归完了就是反转后的链表了return newHead
}

数组和链表的复杂度对比

接下来,我们使用大O表示法来对比一下数组和链表的时间复杂度:

image.png

  • 数组是一种连续的存储结构,通过下标可以直接访问数组中的任意元素。

  • 时间复杂度:对于数组,随机访问时间复杂度为o(1),插入和删除操作时间复杂度为o(n)。

  • 空间复杂度:数组需要连续的存储空间,空间复杂度为o(n)。

  • 链表是一种链式存储结构,通过指针链接起来的节点组成,访问链表中元素需要从头结点开始遍历。

  • 时间复杂度:对于链表,随机访问时间复杂度为o(n),插入和删除操作时间复杂度为o(1)。

  • 空间复杂度:链表需要为每个节点分配存储空间,空间复杂度为O(n)。

  • 在实际开发中,选择使用数组还是链表需要根据具体应用场景来决定。

  • 如果数据量不大,且需要频繁随机访问元素,使用数组可能会更好。

  • 如果数据量大,或者需要频繁插入和删除元素,使用链表可能会更好。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/167541.shtml

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

相关文章

Interactive Visual Data Analysis

Words&Contents Home | Interactive Visual Data Analysis Book Outline 这本书对视觉、互动和分析方法进行了系统而全面的概述&#xff0c;作为数据可视化方面比较好的读物&#xff1b; 目录 Words&Contents Book Outline &#xff08;一&#xff09;Introduct…

AIGC 3D即将爆发,混合显示成为产业数字化的生产力平台

2023年&#xff0c;大语言模型与生成式AI浪潮席卷全球&#xff0c;以文字和2D图像生成为代表的AIGC正在全面刷新产业数字化。而容易为市场所忽略的是&#xff0c;3D图像生成正在成为下一个AIGC风口&#xff0c;AIGC 3D宇宙即将爆发。所谓AIGC 3D宇宙&#xff0c;即由文本生成3D…

VBA_MF系列技术资料1-227

MF系列VBA技术资料 为了让广大学员在VBA编程中有切实可行的思路及有效的提高自己的编程技巧&#xff0c;我参考大量的资料&#xff0c;并结合自己的经验总结了这份MF系列VBA技术综合资料&#xff0c;而且开放源码&#xff08;MF04除外&#xff09;&#xff0c;其中MF01-04属于定…

安装compiler version 5

这个compiler version5 在我的资源里面可以免费下载&#xff1b; 另外这个东西还需要安装&#xff0c;安装教程在这里&#xff1a;Keil最新版保姆教程&#xff08;解决缺少V5编译器问题&#xff09; - 哔哩哔哩 (bilibili.com) 看吧安装好了year

【C语言】qsort的秘密

一&#xff0c;本文目标 qsort函数可以对任意类型数据甚至是结构体内部的数据按照你想要的规则排序&#xff0c;它的功能很强大&#xff0c;可是为什么呢&#xff1f; 我将通过模拟实现qsort函数来让你对这整个过程有一个清晰的深刻的理解。 二&#xff0c;qsort函数原型 v…

leetcode刷题详解一

算法题常用API std::accumulate 函数原型&#xff1a; template< class InputIt, class T > T accumulate( InputIt first, InputIt last, T init );一般求和的&#xff0c;代码如下&#xff1a; int sum accumulate(vec.begin() , vec.end() , 0);详细用法参考 lo…

【python海洋专题四十七】风速的风羽图

【python海洋专题四十七】风速的风羽图 图片 往期推荐 图片 【python海洋专题一】查看数据nc文件的属性并输出属性到txt文件 【python海洋专题二】读取水深nc文件并水深地形图 【python海洋专题三】图像修饰之画布和坐标轴 【Python海洋专题四】之水深地图图像修饰 【Pyth…

记一次linux操作系统实验

前言 最近完成了一个需要修改和编译linux内核源码的操作系统实验&#xff0c;个人感觉这个实验还是比较有意思的。这次实验总共耗时4天&#xff0c;从对linux实现零基础&#xff0c;通过查阅资料和不断尝试&#xff0c;直到完成实验目标&#xff0c;在这过程中确实也收获颇丰&…

【黑马甄选离线数仓day04_维度域开发】

1. 维度主题表数据导出 1.1 PostgreSQL介绍 PostgreSQL 是一个功能强大的开源对象关系数据库系统&#xff0c;它使用和扩展了 SQL 语言&#xff0c;并结合了许多安全存储和扩展最复杂数据工作负载的功能。 官方网址&#xff1a;PostgreSQL: The worlds most advanced open s…

Springboot将多个图片导出成zip压缩包

Springboot将多个图片导出成zip压缩包 将多个图片导出成zip压缩包 /*** 判断时间差是否超过6小时* param startTime 开始时间* param endTime 结束时间* return*/public static boolean isWithin6Hours(String startTime, String endTime) {// 定义日期时间格式DateTimeFormatt…

【数据结构】—搜索二叉树(C++实现,超详细!)

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;消えてしまいそうです—真夜中 1:15━━━━━━️&#x1f49f;──────── 4:18 &#x1f504; ◀️ ⏸ ▶️…

函数计算的新征程:使用 Laf 构建 AI 知识库

Laf 已成功上架 Sealos 模板市场&#xff0c;可通过 Laf 应用模板来一键部署&#xff01; 这意味着 Laf 在私有化部署上的扩展性得到了极大的提升。 Sealos 作为一个功能强大的云操作系统&#xff0c;能够秒级创建多种高可用数据库&#xff0c;如 MySQL、PostgreSQL、MongoDB …

js实现获取原生form表单的数据序列化表单以及将数组转化为一个对象obj,将数组中的内容作为对象的key转化为对象,对应的值转换为对象对应的值

1.需求场景 哈喽 大家好啊&#xff0c;今天遇到一个场景&#xff0c; js实现获取原生form表单的数据序列化表单以及将数组转化为一个对象obj&#xff0c;将数组中的内容作为对象的key转化为对象&#xff0c;对应的值转换为对象对应的值 数组对象中某个属性的值&#xff0c;转…

元宇宙现已开放!

在 2023 年 11 月 3 日 The Sandbox 首个全球创作者日上&#xff0c;The Sandbox 联合创始人 Arthur Madrid 和 Sebastien Borget 宣布元宇宙已开放&#xff0c;已创作完整体验的 LAND 持有者可以自行将体验发布至 The Sandbox 地图上。 精选速览 LAND 持有者&#xff1a;如果…

在JVM中 判定哪些对象是垃圾?

目录 垃圾的条件 1、引用计数法 2、可达性分析 3、强引用 4、软引用 5、弱引用 6、虚引用 判断垃圾的条件 在Java虚拟机&#xff08;JVM&#xff09;中&#xff0c;垃圾收集器负责管理内存&#xff0c;其中的垃圾收集算法用于确定哪些对象是垃圾&#xff0c;可以被回收…

VBA即用型代码手册之工作薄的关闭保存及创建

我给VBA下的定义&#xff1a;VBA是个人小型自动化处理的有效工具。可以大大提高自己的劳动效率&#xff0c;而且可以提高数据的准确性。我这里专注VBA,将我多年的经验汇集在VBA系列九套教程中。 作为我的学员要利用我的积木编程思想&#xff0c;积木编程最重要的是积木如何搭建…

[Latex] Riemann 问题中的激波,接触间断,膨胀波的 Tikz 绘图

Latex 代码 \begin{figure}\begin{subfigure}[b]{0.32\textwidth}\centering\resizebox{\linewidth}{!}{\begin{tikzpicture}\coordinate (o) at (0,0);\coordinate (Si) at (2.5,2.5);\coordinate (x) at (1,0);\draw[->] (0,0) -- (3,0) node[right] {$x$};\draw[->] …

ArkTS-自定义组件学习

文章目录 创建自定义组件页面和自定义组件生命周期自定义组件和页面的区别页面生命周期(即被Entry修饰的组件)组件生命周期(即被Component修饰的组件) Builder装饰器&#xff1a;自定义构建函数按引用传递参数按值传递参数 BuilderParam装饰器&#xff1a;引用Builder函数 这个…

生物动力葡萄酒和有机葡萄酒一样吗?

农业维持了数十万年的文明&#xff0c;但当人类以错误的方式过多干预&#xff0c;过于专注于制造和操纵产品时&#xff0c;农业往往会失败。如果我们的目标是获得最高质量的收成&#xff0c;并长期坚持我们的做法&#xff0c;我们就必须与土地打交道。 当我们开始寻找生物动力…

应用内测分发平台如何上传应用包体?

●您可免费将您的应用&#xff08;支持苹果.ios安卓.apk文件&#xff09;上传至咕噜分发平台&#xff0c;我们将免费为应用生成下载信息&#xff0c;但咕噜分发将会对应用的下载次数进行收费&#xff08;每个账号都享有免费赠送的下载点数以及参加活动的赠送点数&#xff09;&a…