js 创建一条通用链表

什么是「链表
科普
」?
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
什么是「顺序存储结构
科普
」?
在计算机中用一组地址连续的存储单元依次存储线性表的各个数据元素

,称作线性表的顺序存储结构。

多数高级语言的「数组」使用「顺序存储结构」,不过早期的

javascript 引擎用了「链式存储结构」。Chrome 的 V8 的数组使用了「顺序存储结构」与「链式存储结构」混合模式;大多数情况下,V8 下的数组是「顺序存储结构」,所以我们就假装 V8 的数组使用的是「顺序存储结构」吧!(-_-! 心虚)

javascript 开发需要「链表」吗?

自问自答
大多数情况下

javascript 开发关心的是「数据的逻辑结构」而非「数据的存储结构」,似乎「链表」跟 javascript 开发没什么关系。But…「链表」在一些情况下能有效提升代码的性能,特别是在H5游戏的过程中。

假设有一个业务需要高频率地向一张「线性表
科普
」插入或删除节点。通常笔者会用数组表示「线性表」,因为

javascript 的数组有一系列成熟好用的 APIs (如:unshift / push / shift / pop / splice 等)可以完成插入与删除节点的操作。但是数组(顺序存储结构)的 unshift& shift & splice 的算法时间复杂度是 O(n) ,这情况可能「链表」是更好的选择。

图解链表

先看一下最简单的单向链表:
往链表里插入一个节点:
剔除链表里的节点:
往链表里插入一条链表:
剪除链表的一段切片:
通过上面的图示,可以很清晰地了解到单链表的优势:
插入节点或链表片段的算法时间复杂度为

O(2);删除节点或链表片段的算法时间复杂度为O(1)

实现双向链表

「单向链表」效率虽然高,不过局限性比较大。所以笔者想实现的是「双向链表」。
双向链表插入节点或链表的算法时间复杂度为

O(4),删除节点或链表片段的算法时间复杂度为O(2)

双向链表的结构如下:

·

节点指针

——「前驱」与「后继」

·

链表指针

—— 「头指针」、「尾指针」和「游标指针」

用一个匿名对象作为链表上的节点,如下伪代码:

JavaScript

1

2

3

4

5

6

7

function generateNode(data) {

return {

data: data, // 数据域

next: null, // 前驱指针

prev: null // 后继指针

}

}

声明变量

HEAD, TAIL, POINTER & length 分别指代「头指针」,「尾指针」,「游标指针」和 「链表长度」,那么构建一个双向链表如下伪代码:

JavaScript

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

let HEAD, TAIL, POINTER, length = 0;

// 创建一条长度为5的双向链表

[0, 1, 2, 3, 4].forEach((data, index, arr) => {

let node = generateNode(data);

// 第一个节点

if(index === 0) {

HEAD = node;

}

else {

// 指定前驱后继指针

[node.prev, POINTER.next] = [POINTER, node];

// 最后一个节点

index === arr.length - 1 && (TAIL = node)

}

// 指向当前节点

POINTER = node;

++length;

});

// 游标指针回退到头部

POINTER = HEAD;

链表结构本身是个很简单的结构,

20行左右代码可以完成双向链表数据结构的构建。

定制 APIs

上一节虽然实现了「双向链表」的数据结构,但链表还处在很原始的状态,操作起来比较麻烦,为了方便操作链表得为链表量身定做一套

APIs。数组有一系列成熟且好用的 APIs,笔者想借鉴数组的 APIs 为链表定制以下的 APIs:

Name

Detail

Name

Detail

Name

Detail

Name

Detail

shift

参见数组

unshift

参见数组

pop

参见数组

push

参见数组

slice

参见数组

splice

参见数组

concat

参见数组

reverse

参见数组

sort

参见数组

indexOf

参见数组

length[属性]

参见数组

at

指针定位

prev

指针前移

next

指针后退

curr

当前指针

first

头节点

last

尾节点

remove

删除节点

clone

克隆链表

insertAfter

插入节点

insertBefore

插入节点

insertChainAfter

插入链表

insertChainBefore

插入链表

HEAD[属性]

头指针

TAIL[属性]

尾指针

setHead

重置头指针

setTail

重置尾指针

POINTER[属性]

游标指针(当前位置)

setPointer

设置当前指针

上表与数组同名的

APIs,表示用法与功能与数组一样。

为了突显「链表性」笔者添加了四个

insert*

insert* 的作用是向主链表指定位置插入节点或链表。APIs 不小心被笔者写多了,这里就不展开介绍它们的实现过程了。有兴趣的同学可以移步:github.com/leeenx/es6-…

循环链表

笔者以往都是用数组来模拟循环链表,如下:

JavaScript

1

2

3

4

5

6

7

8

9

10

Array.prototype.next = function() {

var cur = this[0];

this.push(this.shift());

return cur;

}

var arr = [1, 2, 3, 4, 5];

var count = 0;

while(count++<20) {

console.log(arr.next());

}

有了

Chain 类后,可以直接这样写:

JavaScript

1

2

3

4

5

6

let circle = new Chain([1, 2, 3, 4, 5]);

// 链表头咬尾

circle.TAIL.next = circle.HEAD;

for(let i = 0; i < 20; ++i) {

console.log(chain.next());

}

想要学习前端开发的同学,可以加群:

543627393 学习哦!

js 创建一条通用链表相关推荐

  1. 用Backbone.js创建一个联系人管理系统(一)

    原文 Build a Contacts Manager Using Backbone.js: Part 1 在这个教程里我们将会使用Backbone.js,Underscore.js,JQuery创建 ...

  2. 使用 iosOverlay.js 创建 iOS 风格的提示和通知

    iosOverlay.js 用于在 Web 项目中实现 iOS 风格的通知和提示效果.为了防止图标加载的时候闪烁,你需要预加载的图像资源.不兼容 CSS 动画的浏览器需要 jQuery 支持.浏览器兼 ...

  3. node.js 创建服务器_Node.js HTTP软件包–创建HTTP服务器

    node.js 创建服务器 An HTTP server caters to client requests and sends appropriate response. For example, ...

  4. uni-app(Vue.js)创建运行微信小程序

    uni-app(Vue.js)创建运行微信小程序 1.全局安装 npm install -g @vue/cli 需要安装node,官方网站,否则提示npm不可用 2.创建uni-app 新建文件夹,选 ...

  5. JQuery Easyui/TopJUI 用JS创建数据表格并实现增删改查功能

    JQuery Easyui/TopJUI 用JS创建数据表格并实现增删改查功能 JQuery Easyui/TopJUI 用JS创建数据表格并实现增删改查功能 html <table id=&q ...

  6. 如何用 CSS + HTML + JS 创建桌面应用

    05月 31 Node 如何用 CSS + HTML + JS 创建桌面应用 | https://h.lishaoy.net/nwjsElectronjs.html || 最近研究了一下基于 Chro ...

  7. 使用three.js创建楼层布局图

    最近大半年一直在做三维部分的工作,之前做三维楼层都是外部加载使用建模工具创建的模型,但是渲染不够灵活.无法绑定房间信息,所以决定来使用three.js来创建楼层布局. 在线地址 CSDN下载地址htt ...

  8. c js html页面进度条,js实现进度条的方法

    本文实例讲述了js实现进度条的方法.分享给大家供大家参考.具体实现方法如下: 1.setTimeout和clearTimeout 进度条 .container{ width:450px; border ...

  9. 推断两条单链表是否相交

    算法中常常会推断两条单链表是否相交,尽管算法简单,但也值得说一下. 代码中有详尽凝视. Show you the code ! #undef UNICODE#include <iostream& ...

最新文章

  1. Microbiome:利用Nanopore高通量测序技术解析污水处理体系可移动抗性基因组(一作解读)
  2. java 二维码生成和解析
  3. 第八篇:Docker镜像结构原理
  4. python从入门到精通书-Python从入门到精通
  5. OSPF路由聚合实验(详细)
  6. 漫谈WinCE输入法的编写(四)
  7. php配置mysql集群_mysql的集群配置
  8. 处理数字_1_计算某列的最小/大值
  9. c语言编译成功,[C/CPP系列知识] 那些程序C语言可以编译通过但C++无法编译成功 Write a C program that won’t compile in C++...
  10. SSH开发中 使用超链接到action 其excute方法会被执行两次 actual row count: 0; expected: 1...
  11. Kali中firefox浏览器设置中文
  12. WebDriver高级应用实例(3)
  13. 重写(覆盖)重载与多态
  14. 11.2.3 退出Vim编辑器
  15. FFmpeg之yuv旋转(十九)
  16. Java进程中的堆和栈_对于JVM,你就只知道堆和栈吗?
  17. 网络设备自动化运维工具——ansible入门笔记
  18. 学历-GBT 4658-2006
  19. MAC 使用brew安装java11并与java8共存
  20. virtualbox虚拟机安装及镜像安装

热门文章

  1. c语言模拟实现oc引用计数
  2. UIView旋转角度
  3. android高级编程-android高级应用
  4. PL/SQL三种集合类型的比较
  5. 高并发大流量专题---8、动态语言的并发处理
  6. RabbitMQ 实战(四)消费者 ack 以及 生产者 confirms
  7. python写一个通讯录step by step V3.0
  8. C语言 带比较器的归并排序
  9. ubuntu 14.04 vim install youcompleteme
  10. [转] WINCC教学视频