https://cloud.tencent.com/developer/article/1114246

链表存储有序的元素的集合,但是和数组不同的是,链表中的元素在内存中的存储并不是连续的。每一个链表元素都包含了一个存储元素本身的节点一个指向下一个元素的引用。看起来就像这样:

  相对于传统的数组,链表的一个好处就是增删的时候无需移动其它元素,只要更改指针的指向就可以了。但是缺点就是如果想要访问链表中的元素,需要从头开始循环迭代到你想要的元素。

function LinkedList() {

    // Node辅助类,表示要加入列表的项,element是即将添加到列表的值,next是指向列表中下一个节点项的指针
let Node = function (element) {
this.element = element
this.next = null
} let length = 0
let head = null // 向链表尾部追加元素
this.append = function (element) {
let node = new Node(element)
let current
if (head === null) { // 列表中第一个节点
head = node
} else {
current = head
while (current.next) {
current = current.next // 找到最后一项,是null
}
current.next = node // 给最后一项赋值
}
length++ // 更新列表的长度
} // 从链表中移除指定位置元素
this.removeAt = function (position) {
if (position > -1 && position < length) { // 值没有越界
let current = head
let previous, index = 0
if (position === 0) { // 移除第一项
head = current.next
} else {
while (index++ < position) {
previous = current
current = current.next
}
previous.next = current.next // 将previous与current的下一项连接起来,跳过current,从而移除
}
length-- // 更新列表的长度
return current.element
} else {
return null
}
} // 在链表任意位置插入一个元素
this.insert = function (position, element) {
if (position >= 0 && position <= length) { // 检查越界值
let node = new Node(element),
current = head,
previous,
index = 0
if (position === 0) { // 在第一个位置添加
node.next = current
head = node
} else {
while (index++ < position) {
previous = current
current = current.next
}
node.next = current // 在previous与current的下一项之间插入node
previous.next = node
}
length++
return true
} else {
return false
}
} // 把链表内的值转换成一个字符串
this.toString = function () {
let current = head,
string = ''
while (current) {
string += current.element + ' '
current = current.next
}
return string
} // 在链表中查找元素并返回索引值
this.indexOf = function (element) {
let current = head,
index = 0
while (current) {
if (element === current.element) {
return index
}
index++
current = current.next
}
return -1
} // 从链表中移除指定元素
this.remove = function (element) {
let index = this.indexOf(element)
return this.removeAt(index)
} this.isEmpty = function () {
return length === 0
} this.size = function () {
return length
} this.getHead = function () {
return head
}
}
let list = new LinkedList()
list.append(1)
list.append(2)
console.log(list.toString()) // 1 2
list.insert(0, 'hello')
list.insert(1, 'world')
console.log(list.toString()) // hello world 1 2
list.remove(1)
list.remove(2)
console.log(list.toString()) // hello world
单链表有一个变种 - 循环链表,最后一个元素指向下一个元素的指针,不是引用null,而是指向第一个元素,只需要修改下最后的next指向为head即可。
 
双向链表与单链表的区别在于,在单链表中,一个节点只有链向下一个节点的链接,而在双向链表中,链接是双向的:一个链向下一个元素,另一个链向前一个元素。
  双向链表提供了两种迭代列表的方法:从头到尾,或则反过来。在单链表中,如果我们在迭代列表中错过了要找的元素,就需要回到列表的起点,重新开始迭代,这是双向列表的优点。
  双向链表与单向链表的实现类似,需要同时控制next、prev两个指针,同时需要增加尾引用tail。
function DoubleLinkedList() {

        // Node辅助类,表示要加入列表的项,element是即将添加到列表的值,next是指向列表中下一个节点项的指针
let Node = function (element) {
this.element = element
this.prev = null // 新增一个向前的指针
this.next = null
} let length = 0
let head = null
let tail = null // 新增一个尾引用 // 向链表尾部追加元素
this.append = function (element) {
let node = new Node(element) let current
if (head === null) { // 列表中第一个节点
head = node // head与tail是同一个元素
tail = node
} else {
current = head
while (current.next) {
current = current.next // 找到最后一项,是null
}
current.next = node // 给最后一项赋值
node.prev = current
tail = node // 修改尾引用
}
length++ // 更新列表的长度
} // 从链表中移除指定位置元素
this.removeAt = function (position) {
if (position > -1 && position < length) { // 值没有越界
let current = head
let previous,
index = 0
if (position === 0) { // 移除第一项
head = current.next
if (length === 1) { // 只有一项
tail = null
} else {
head.prev = null
}
} else if (position === length - 1) { // 移除最后一项
current = tail
tail = current.prev
tail.next = null
}
else {
while (index++ < position) {
previous = current
current = current.next
}
previous.next = current.next // 将previous与current的下一项连接起来,跳过current,从而移除
current.next.prev = previous
}
length-- // 更新列表的长度
return current.element
} else {
return null
}
} // 在链表任意位置插入一个元素
this.insert = function (position, element) {
if (position >= 0 && position <= length) { // 检查越界值
let node = new Node(element),
current = head,
previous,
index = 0
if (position === 0) { // 在第一个位置添加
if (!head) {
head = node
tail = node
}else {
node.next = current
current.prev = node
head = node
}
node.next = current
head = node
} else if (position === length) {
current = tail
current.next = node
node.prev = current
tail = node
} else {
while (index++ < position) {
previous = current
current = current.next
}
node.next = current // 在previous与current的下一项之间插入node
previous.next = node current.prev = node
node.prev = previous
}
length++
return true
} else {
return false
}
} // 把链表内的值转换成一个字符串
this.toString = function () {
let current = head,
string = ''
while (current) {
string += current.element + ' '
current = current.next
}
return string
} // 在链表中查找元素并返回索引值
this.indexOf = function (element) {
let current = head,
index = 0
while (current) {
if (element === current.element) {
return index
}
index++
current = current.next
}
return -1
} // 从链表中移除指定元素
this.remove = function (element) {
let index = this.indexOf(element)
return this.removeAt(index)
} this.isEmpty = function () {
return length === 0
} this.size = function () {
return length
} this.getHead = function () {
return head
}
}
let list = new DoubleLinkedList()
list.append(1)
list.append(2)
console.log(list.toString()) // 1 2
list.insert(0, 'hello')
list.insert(1, 'world')
console.log(list.toString()) // hello world 1 2
list.remove(1)
list.remove(2)
console.log(list.toString()) // hello world
 

JS实现单向链表、双向链表、循环链表的更多相关文章

  1. 原生JS实现单向链表

    1.前言 用JS实现一个简单的单向链表,并完成相关的功能 2.功能说明 push(value):从链表尾部添加一个新的节点 insertAfer(value,item):向链表中的item节点之后插入 ...

  2. 单链表、循环链表的JS实现

    数据结构系列前言: 数据结构作为程序员的基本知识,需要我们每个人牢牢掌握.近期我也展开了对数据结构的二次学习,来弥补当年挖的坑......   当时上课的时候也就是跟着听课,没有亲自实现任何一种数据结 ...

  3. 《Java数据结构》链表结构(单向链表,双向链表)

    单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始:链表是使用指针进行构造的列表:又称为结点列表,因为链表是由一个个结点组装起来的:其中每个结点都有指 ...

  4. Python 单向链表、双向链表

    用面向对象实现Linkedlist链表 单向链表实现append.iternodes 双向链表实现append.pop.insert.remove.iternodes 单向链表与双向链表 单向链表: ...

  5. Python链表的实现与使用(单向链表与双向链表)

    参考[易百教程]用Python实现链表及其功能 """ python链表的基本操作:节点.链表.增删改查 """ import sys cl ...

  6. 玩转C线性表和单向链表之Linux双向链表优化

    前言: 这次介绍基本数据结构的线性表和链表,并用C语言进行编写:建议最开始学数据结构时,用C语言:像栈和队列都可以用这两种数据结构来实现. 一.线性表基本介绍 1 概念: 线性表也就是关系户中最简单的 ...

  7. 用Python写单向链表和双向链表

    链表是一种数据结构,链表在循环遍历的时候效率不高,但是在插入和删除时优势比较大. 链表由一个个节点组成. 单向链表的节点分为两个部分:存储的对象和对下一个节点的引用.注意是指向下一个节点. 而双向链表 ...

  8. Java-链表(单向链表、双向链表)

    Java-链表 1.什么是链表? 2.链表的特点是什么? 3.链表的实现原理? 4.如何自己写出一个链表? 1.什么是链表? 链表是一种物理存储单元上非连续.非顺序的存储结构,数据元素的逻辑顺序是通过 ...

  9. MySQL记录之间是单向链表还是双向链表?

    前言 本文的观点是基于MySQL使用Innodb存储引擎的情况下进行的! 很多渠道说:MySQL数据按照主键大小依次排列,记录之间是双向链表连起来.如果说我告诉你这种说法很大程度上是错的,你肯定说我在 ...

随机推荐

  1. 教妹学 Java:晦涩难懂的泛型

    00.故事的起源 “二哥,要不我上大学的时候也学习编程吧?”有一天,三妹突发奇想地问我. “你确定要做一名程序媛吗?” “我觉得女生做程序员,有着天大的优势,尤其是我这种长相甜美的.”三妹开始认真了起 ...

  2. QxOrm 1.2.9 下载 以及编译方法 简介.

    QxOrm 是一个基于QT开发的数据库方面的ORM库,功能很强大,是QT C++数据开发方面的好工具. 目前已经更新1.3.1 .但 不幸的是 它的官网http://www.qxorm.com/ 莫名 ...

  3. Mujin Programming Challenge 2017A - Robot Racing【思维题】

    题意: 给你n个人的位置,每个人能往后跳一格或两格到无人的位置,跳到0位置,这个人消失,n个人消失组成一个排列,问有多少种排列. 思路: 额,搞了一整场这个A...代码也巨挫了. 处理成1,3,5,7 ...

  4. 删除childNodes获取的文本节点

    function del_ff(elem) { var elem_child = elem.childNodes; for (var i = 0; i < elem_child.length; ...

  5. html解决的兼容问题

    手机版不缩放 <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum ...

  6. AGC001 E - BBQ Hard【dp+组合数学】

    首先直接按要求列出式子是\( \sum_{i=1}^{n}\sum_{j=i+1}^{n}C_{a_i+a_j+b_i+b_j}^{a_i+a_j} \) 这样显然过不了,因为ab的数据范围比较小,所 ...

  7. 洛谷P3572 [POI2014]PTA-Little Bird

    P3572 [POI2014]PTA-Little Bird 题目描述 In the Byteotian Line Forest there are nn trees in a row. On top ...

  8. 第九组 通信3班 063 OSPFv2与OSPFv3综合实验

    实验目的 1. 掌握 OSPFv3(v2) 的配置方法 2. 掌握在帧中继环境下 OSPFv3 (v2)的配置方法 3. 掌握 OSPFv3(v2) NSSA 的配置方法 4. 掌握外部路由汇总的配置 ...

  9. 前端CSS(1)

    前端基础CSS(1)   一.css的引入方式 现在的互联网前端分三层: HTML:超文本标记语言.从语义的角度描述页面结构. CSS:层叠样式表.从审美的角度负责页面样式. JS:JavaScrip ...

  10. Table行合并操作

    此方法不可取,但几天心血 保留,已有新想法,稍后会出一个完善的Table行列合并方法 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Tran ...