首页 > 其他分享 >[数据结构学习笔记4] 链表

[数据结构学习笔记4] 链表

时间:2025-01-05 10:43:57浏览次数:1  
标签:current head 笔记 next 链表 数据结构 data 节点

链表(Linked Lists)

和数组类似,链表也是用来存放一组数据。和数组不一样的是,链表存储不需要连续的内存位置,一个链表由很多节点组成,节点与节点间通过一个next 指针关联。

图示:

Node
Value / Data Next

 

链表操作:

查找一个值:

通过链表的next 指针一直往下跳直到:

1. 找到了想要的值;

2. 到达最后一个节点了。

添加节点:

1. 添加在末尾:将末尾节点的next指针指向新加节点;

2. 添加在中间(如C, D 中间):将C的next 指针指向新节点,将新节点的next指向D。

删除节点:

1. 删除的是尾部节点:将尾部前一个节点的next置空;

2. 删除的是中间节点:将删除节点的前一个节点的next指向删除节点的next,将删除节点的next置空。

删除节点会被垃圾回收清除。

 

时间复杂度

动作 最佳 平均 最差
查询 (Search) O(1) O(n) O(n)
添加/插入 (Add/Insert) O(1) O(n) O(n)
删除(Delete) O(1) O(n) O(n)

链表的变种:

1. 最常见的,也是上面讨论的,单向链表;

2. 双向链表,可以往两个方向遍历;

3. 环形链表,末尾next指向头节点;

4. 跨度链表,next指向后续节点有不同的步数,基本的是1步,可以有多层如2步,3步等。这种链表可以加快遍历。

 

代码实现,javascript

包含下面的实现:创建一个新的链表;往头部加一个节点;往尾部加一个节点;在某节点前加一个节点;在某节点后加一个节点;查看链表是否包含某个值;移除第一个节点;移除最后一个节点;移除某个特定的节点;将链表转化为数组;获得链表的长度。

class LinkedListNode {
  constructor (data, next = null) {
        this.data = data;
        this.next = next;              
    }  
}

class LinkedList {
  constructor() {
        this.head = null;
        this.tail = null;
        this.size = 0;  
    }  

addFirst(data) {
  const newNode = new LinkedListNode(data, this.head);
  this.head = newNode;
  if (!this.tail) {
        this.tail = newNode;
    }  
  this.size++;  
}

addLast(data) {
  const newNode = new LinkedListNode(data);

  if (!this.head) {
     this.head = newNode;
     this.tail = newNode;
  } else {
     this.tail.next = newNode;
     this.tail = newNode;
  }  
  this.size++;
}

addBefore(beforeData, data) {
   const newNode = new LinkedListNode(data);
   if (this.size === 0)
{
this.head = newNode;
this.size ++;
return;
}
if (this.head.data === beforeData) {
newNode.next = this.head;
this.head = newNode;
this.size ++;
return;
}
let current = this.head.next;
let prev = this.head;
while (current) {
if (current.data === beforeData) {
newNode.next = current;
prev.next = newNode;
this.size ++;
return;
}
prev = current;
current = current.next;
}
throw new Error(`Node with data '${beforeData}' not found in list.`); }

addAfter(afterData, data) {
const newNode = new LinkedListNode(data);

if (this.size === 0) {
this.head = newNode;
this.size ++;
return;
}

let current = this.head;
while (current) {
if (current.data === afterData) {
newNode.next = current.next;
current.next = newNode;
this.size ++;
return;
}
current = current.next;
}

throw new Error(`Node with data '${afterData}' not found in the list.`);
}

contains(data) {
  let current = this.head;
while (current) {
if (current.data === data)
return true;
current = current.next;
}
return false;
}

removeFirst() {
  if (!this.head) {
throw new Error('List is empty.');
}
this.head = this.head.next;
if (!this.head) {
this.tail = null;
}
this.size --;
}

removeLast() {
  if (!this.tail)
throw new Error('List is empty');

if (this.head === this.tail) {
this.head = null;
this.tail = null;
this.size --;
return;
}
let current = this.head;
let prev = null;
while (current.next) {
prev = current;
current = current.next;
}
prev.next = null;
this.tail = prev;
this.size --;
}

remove(data) {
  if (this.size === 0) {
throw new Error("List is empty.");
}

if (this.head.data === data) {
this.head = this.head.next;
this.size --;
return;
}

let current = this.head;
while (current.next) {
if (current.next.data === data) {
current.next = current.next.next;
this.size --;
return;
}
current = current.next;
}
throw new Error(`Node with data '${data}' not found in list.`);
}

toArray() {
  const arr = [];
let current = this.head;
while (current) {
arr.push(current.data);
current = current.next;
}
return arr;
}

getLength() {
  return this.size;
}

}

 测试上面的方法:

let letters = new LinkedList();

letters.addLast("A");
letters.addLast("B");
letters.addLast("C");
letters.addLast("D");
letters.addLast("E");

console.log(letters.toArray()); // [‘A’, 'B', 'C', 'D', 'E']

letters.addFirst("AA");
letters.addLast("Z");

letters.remove("C");
letters.removeFirst();
letters.removeLast();

letters.addAfter("D", "Q");

 

标签:current,head,笔记,next,链表,数据结构,data,节点
From: https://www.cnblogs.com/Eagle6970/p/18652418

相关文章

  • 数据结构(排序算法)
    插入排序插入排序(InsertionSort)是一种简单直观的排序算法,其原理可以简述如下:1.分已排序区间和未排序区间:将数组分为已排序区间和未排序区间。初始时,已排序区间只包含数组的第一个元素,而未排序区间包含除第一个元素之外的所有元素。2.依次将未排序区间中的元素插入到已......
  • 数据结构理论篇(期末突击)
    找往期文章包括但不限于本期文章中不懂的知识点:个人主页:我要学编程(ಥ_ಥ)-CSDN博客所属专栏: 学校课程突击下面均是为了应付学校考试所用,如果有涉及部分知识点下面未说明,可以去我的数据结构专栏看看或者自行在网上查阅资料。 以下所有知识均是阅读大话数据结构所得。如......
  • 弹性波动力学笔记(九) 应力张量的摩尔圆描述
    3.10Mohr'scircleforstresstensorHerewewillshowthatoncetheprincipalvaluesoftensorhavebeenfound,thenormalandshearstressvectorcanbedeterminedgraphicallyusingasimplegeometricalconstructionbasedonthreecircleswithradi......
  • DIY笔记本散热器
    前言  我用的笔记本是R9000P2021H,用了快三年才发现笔记本发热量有点高,GPU3070倒是还好不用担心过热的问题,主要是这个CPU5800H非常积热。最近也是清完灰、涂硅脂、换完风扇了,双烤测试了下功耗能到200W但是CPU有大概70°C往上的样子,考虑到这是冬季测试下的结果,这个成绩还是有......
  • 二分 + 倍增 做题笔记
    一些关于二分和倍增的题,大体按照题目难度排序。1.CF1951HThanosSnap简要题意给定一个长为\(2^n\)的序列\(a_0,a_1,\cdots,a_{2^n-1}\),对所有\(t\in[1,n]\)求解如下问题:A和B两人在序列\(a\)上博弈,一共进行\(t\)轮操作。每轮操作的流程如下:A可以选......
  • 《任何一种能够作为科学出现的未来形而上学导论》读书笔记1
    《任何一种能够作为科学出现的未来形而上学导论》其实算是《纯粹理性批判》的导读,众说周知康德的书不是一般的难以理解,所以《纯粹理性批判》出版的时候很多人是看不懂康德的思想的,甚至对其有所误解,所以康德又写了这本“导论”,并写下“如果有谁对于我作为导论而放在一切未来形而上......
  • Win32汇编学习笔记04.重定位与汇编引擎
    Win32汇编学习笔记04.重定位与汇编引擎-C/C++基础-断点社区-专业的老牌游戏安全技术交流社区-BpSend.net重定位**重定位:**也称为代码自重定位,代码自己去计算自己使用的各种资源再新进程中的地址,相应代码被称为被重新定位过后的代码。示例目标:向指定进程扫雷注入一段机器......
  • 安卓笔记3——kotlin不写必忘的标准方法
    标准函数with接受2个参数,一个提供默认调用的对象,另一个是lambda当反复调用同一个对象时,方便省略最后一行作为函数返回值valresult=with(StringBuilder()){append("xxx")append("xxx")append("xxx")}run与with类似,但是只接受一个lambda参数,内部的默认......
  • 160链表相交
    哈希肯定是能解的,就想着有没有其他方法。最开始的思路是翻转链表,然后再来找相交结点,但是题目要求不能改链表结构。官方题解的第二种方法确实巧妙,如果有相交结点的话最多通过两次遍历就一定能找到,因此。在分析中,其实我们也可以把两个不相交的链表看做相交,但是相交结点为nullptr代......
  • linux kill 命令笔记
    在Linux中,kill命令用于向进程发送信号,具体信号的行为取决于信号类型。以下是kill、kill-15和kill-SIGTERM的区别:1.kill默认情况下,kill命令发送的是SIGTERM信号,信号编号为15。如果不指定信号类型,kill默认行为等同于kill-15或kill-SIGTERM。示例:kill<p......