单向链表

链表是一种数据结构,有单向链表、双向链表和循环链表,单向链表事其中最简单的一种。它有一个 head 指针,整个链表有很多节点构成,而 head 会始终指向链表的头节点;每个节点由两个信息组成:节点数据和指向下一个节点的指针,最后一个节点的指针为 null

节点

单向链表是由一个个节点组成的数据结构类型,每个节点都包含该节点的数据和指向下一个节点的指针,构造一个节点很简单,只需要包含这两项内容就可以了,用 ES6 的写法可以这样描述一个节点:

/*** 单个链表节点*/
class Node {constructor(val) {this.val = val;this.next = null;}
}

链表结构

一个链表除了由一个个节点之外,还包含一些属性,如:长度、head指针(用以指向链表的第一个节点),这里新建一个类作如下描述:

/*** 链表*/
class LinkedList {constructor(val = null) {this.head = null; // 链表的head指针this.length = 0; // 链表的长度if (val) {this.head = new Node(val);this.length = 1;}}
}

这样这个链表结构就有了额外的长度、head指针信息,我们可以构造一个实例看看:

添加一些方法

一般链表都会包含一些操作方法,比如 append、remove...下面就来来添加这些操作函数。

append(在链表尾部添加一个节点)

这里的重点是如何找到链表尾部,这里使用循环整个链表,找到一个节点,它的 next 指向为空即可:

class LinkedList {...append(val) {const node = new Node(val); // 创建节点if (this.head === null) { // 如果是个空列表this.head = node;} else {let current = this.head;while (current.next) { // 找到 next 指向为空的节点current = current.next;}current.next = node;}this.length += 1; // 整个链表的长度增加}...
}

removeAt(删除指定位置的节点)

从一个链表删除某节点,只需要将该节点前一个的 next 指向替换为该节点的 next 指向即可,这样从整个链表来看就跳过了该节点,需要注意的是需要对用户的输入进行判断:

class LinkedList {...removeAt(position) {if (position >= this.length || position < 0) { // 判断输入return null;}let current = this.head;if (position === 0) { // 删除头节点,只需改变 head 指针即可this.head = current.next;} else {let index = 0;let prev = null;while (index < position) {prev = current;current = current.next;index += 1;}prev.next = current.next; // 改变上一个节点的 next 指向}this.length -= 1; // 长度减少return current.val; // 返回删除节点的值}...
}

insert(在指定位置插入节点)

跟前面的尾部插入不同,这里需要找到插入的位置,再执行插入操作:

class LinkedList {...insert(position, val) {if (position >= this.length || position < 0) {return false;}const node = new Node(val);if (position === 0) { // 插入位置在头节点node.next = this.head;this.head = node;} else {let index = 0;let current = this.head;let prev = null;while (index < position) { // 遍历链表找到指定位置的节点,并记录下前一个节点和该位置原节点prev = current;current = current.next;index += 1;}node.next = current;prev.next = node;}this.length += 1;return true;}...
}

这里可以看到关键的两步是:把插入位置的前一个节点的 next 指向待插入的节点;把待插入的节点的 next 指向原来在该位置上的节点。

indexOf(返回第一个指定值的节点的位置)

这个功能也比较简单,只需要从第一个节点开始遍历,直到找到值符合要求的节点位置即可,在这里加入了一个可以设置起始位置的功能,无非是多了一个判断:

class LinkedList {...indexOf(val, start = 0) {if (start >= this.length) { // 判断起始位置是否合法return -1;}let index = 0;let current = this.head;while (index < this.length) {if (current.val === val && index >= start) {return index;}current = current.next;index += 1;}return -1;}...
}

remove(移除第一个指定值的节点)

这个功能可以结合上面的 indexOfremoveAt 来完成:

class LinkedList {...remove(val, start = 0) {const index = this.indexOf(val, start);return this.removeAt(index);}...
}

size(返回链表长度)

class LinkedList {...size() {return this.length;}...
}

isEmpty(返回是否为空链表)

class LinkedList {...isEmpty() {return !!this.length;}...
}

添加了这些方法之后,就是一个完整的单向链表 js 实现了。

单向链表的 js 实现相关推荐

  1. 单向链表反转-JS实现

    function reverse(list){2 var p=list.head,q=null;3 while(p.next!==null){4 q=p.next;5 p.next=q.next;6 ...

  2. 原型链 —— 以隐式引用作为存储方式的单向链表

    原型链的表述 ​ 一个以隐式引用作为存储方式,以点操作符和属性访问语句作为语法糖的单向链表 原型链作为一个单向链表并没有完全发挥出单向链表的特性,换句话说JS中的原型链是只用部分能力的单向链表 原型对 ...

  3. 二维指针删除单向链表

    Linus slashdot:    https://meta.slashdot.org/story/12/10/11/0030249 原文: https://coolshell.cn/article ...

  4. 【C++】【三】单向链表

    // 单向链表.cpp : 此文件包含 "main" 函数.程序执行将在此处开始并结束. //#include <iostream> #include<stdli ...

  5. 基础数据结构【二】————动态数组,单向链表及链表的反转

    DEMO1:     动态分配变量(链表,而静态数组是线性表,意味着动态数组访问和遍历复杂度为O(n),而插入和删除复杂度为O(1),而静态数组线性表则完全相反) int* intptr = new ...

  6. python数据结构与算法:单向链表

    单链表:python实现及其对应的 增删查检 操作 ##################### P4.1-P4.8 单向链表 ########################### #coding:u ...

  7. C语言单向链表的实现

    一个简单结点的结构体表示为: struct note { int  data:              /*数据成员可以是多个不同类型的数据*/ struct  note  *next:      ...

  8. C++11中std::forward_list单向链表的使用

    std::forward_list是在C++11中引入的单向链表或叫正向列表.forward_list具有插入.删除表项速度快.消耗内存空间少的特点,但只能向前遍历.与其它序列容器(array.vec ...

  9. 单向链表JAVA代码

    //单向链表类 publicclassLinkList{       //结点类     publicclassNode{         publicObject data;         pub ...

最新文章

  1. GoCart 分类和产品 测试一
  2. python版本升级及pip部署方法
  3. java 基本类型内存_java基本数据类型、内存分析、装包拆包
  4. MaxCompute的任务状态和多任务执行
  5. GitHub 宣布正式收购 npm | 云原生生态周报 Vol. 42
  6. numa对MySQL多实例性能影响
  7. linux之进程间通信--使用信号
  8. Portainer复制Docker容器
  9. 在web开发中,为什么前端比后端更得到转行程序员的青睐?必看
  10. Atitit 软件项目非法模块与功能的管理与  监狱管理的对比 原理与概论attilax总结
  11. 什么是hash,什么是hash表,为什么hash表查询快
  12. oracle fnd_global,Oracle Report(Report 6i/RDF)使用全局变量fnd_global, fnd_frofile
  13. 用 Java 实现拦截器 Interceptor 的拦截功能
  14. 用心去爱那些爱过我们的人
  15. 微信小程序Canvas绘制图案(生成海报、朋友圈海报)
  16. 阿里大鱼发送短信(工具类)
  17. coolq使用(一)
  18. 【阿里云高校计划】实现简单的身份证识别系统!
  19. 源代码加密软件类比图
  20. 电子科大计算机科学与技术高考分数,2021四川省高考分数线公布,总分达不到这个数,考电子科大有点悬...

热门文章

  1. 解决 No module named ‘PyQt5.QtWebEngineWidgets‘
  2. 视觉里程计 | 关于Stereo DSO中的高斯牛顿的一点注释
  3. struts2和springmvc实现文件上传
  4. 基于FFT的信号频谱分析
  5. 在虚拟机装一个linux系统
  6. Java什么时候该加void_平时容易忽视的地方之一:java在抽取方法时,什么时候该用void...
  7. 2018android旗舰手机,2018 年发布的 Android 手机,哪一部是你心目中的最佳手机?理由是什么?...
  8. html5和前端精要(2)-架构与基础(2)
  9. 【面试招聘】程序员面试完全指南
  10. 【机器学习基础】深入理解Logistic Loss与回归树