js数据结构与算法--单链表的实现与应用思考
链表是动态的数据结构,它的每个元素由一个存储元素本身的节点和一个指向下一个元素的引用(也称指针或链接)组成。

现实中,有一些链表的例子。
第一个就是寻宝的游戏。你有一条线索,这条线索是指向寻找下一条线索的地点的指针。你顺着这条链接去下一个地点,得到另一条指向下一处的线索。得到列表中间的线索的唯一办法,就是从起点(第一条线索)顺着列表寻找。
第二个例子是火车。一列火车是由一些车厢组成的。每节车厢都是相互连接。你很容易分离一节车皮,改变它的位置,添加或移除它。每节车厢都是列表的元素,车厢间的连接就是指针。
链表的实现
链表有多种不同的类型,单链表,双向链表,循环链表等。
我们先实现单链表。单链表是一种链式存取的数据结构。
linkednode.js文件,里面包含了链表中节点的项
/**
* 链表节点,链表中的项,链表中的节点
*/
export class Node {
constructor(element, next = null) {
this.element = element // 链表中节点的值
this.next = next // 指向列表中下一个节点项的指针
}
}
linkedlist.js文件,链表各种方法的实现
import { Node } from './linkednode'
/**
* 链表类
*/
export default class LinkedList {
constructor() {
this.length = 0 // 存储链表中列表项的数量
this.head = null // 存储链表中第一个节点的引用
}
/**
* 向列表尾部添加一个新的项
* @param {*} element 需要添加至链表中的节点项
*/
append(element) {
let node = new Node(element) // 将新项创建为符合链表结构的列表项
if (this.head === null) {
// 链表中的元素为空
this.head = node
} else {
let current = this.head // 将第一个节点的引用赋值给当前项
// 循环列表,直到找到最后一项
while (current.next) {
current = current.next
}
// 找到最后一项,将其next赋为node,建立链接
current.next = node
}
this.length++ // 更新链表的长度
}
/**
* 向列表的特定位置插入一个新的项
* @param {*} position 插入链表中的位置
* @param {*} element 需要添加的节点
*/
insert(position, element) {
let node = new Node(element)
// 检查越界
if (position > -1 && position <= this.length) {
let current = this.head
let previous
let index = 0
// 在第一个位子添加
if (position === 0) {
node.next = current
this.head = node
} else {
// 需要找到特定的位子,将想要插入的元素放在previous节点和current节点之间
while (index++ < position) {
// previous 将是对想要插入新元素的位置之前一个元素的引用
previous = current
// current 对想要插入新元素的位置之后一个元素的引用
current = current.next
}
node.next = current
previous.next = node
}
this.length++
return true
} else {
return false
}
}
/**
* 移除指定位置的节点元素,并返回移除的项
* 如果超出了链表的范围,则返回null
* @param {Int32Array} position 链表中的位置
*/
removeAt(position) {
// 检查越界
if (position > -1 && position < this.length) {
let current = this.head
let previous // 先前一个节点
let index = 0 // 当前节点的位子
// 移除第一项
if (position === 0) {
this.head = current.next
} else {
while (index++ < position) {
previous = current
current = current.next
}
// 将previous 与 current 的下一项链接起来:跳过current,从而移除它
// 当前元素会丢弃在计算机内存中,等待GC清除
previous.next = current.next
}
this.length-- // 链表元素数量减1
return current.element // 返回移除的项
} else {
return null // 如果超出了链表的范围,则返回null
}
}
/**
* 从列表中移除一项
* 先找出元素的索引项,再根据索引移除元素
* @param {*} element 列表中的元素
*/
remove(element) {
let index = this.indexOf(element)
return this.removeAt(index)
}
/**
* 返回元素在列表中的索引。如果列表中没有该元素则返回-1
* @param {*} element 元素
*/
indexOf(element) {
let current = this.head
let index = 0 // 计算位置数
while (current) {
if (element === current.element) {
return index
}
index++
current = current.next
}
return -1
}
/**
* 判断是否为空链表
* 空链表返回true,非空(链表长度大于0)返回false
*/
isEmpty() {
return this.size() === 0
}
/**
* 返回链表包含的元素个数。与数组的length属性类似
*/
size() {
return this.length
}
/**
* 获取链表的表头节点
* head变量是LinkedList类的私有变量。
* 但是,我们需要实现在类的外部循环访问列表。
* 此时,就需要提供获取类的第一个元素的方法
*/
getHead() {
return this.head
}
/**
* 由于列表项使用了Node类,需要重写toString方法,让其只输出元素的值。
*/
toString() {
let current = this.head
let string = ''
while (current) {
string += current.element + (current.next ? '-->' : '')
current = current.next
}
return string
}
}
链表的应用思考
我们先比较下JavaScript中链表与数组的区别:
链表中的元素是不连续的,而数组中的元素是连续的。
链表添加或移除元素的时候不需要移动其他元素,而数组需要。
链表需要指针,而数组不需要。
链表需要从表头开始迭代列表直到找到所需要的元素。数组则可以直接访问任何位置的任何元素。
两者都具有动态性。关于数组动态性。数组在js中是一个可以修改的对象,添加移除元素,它会动态的变化,但是成本很高,需要移动元素。在大多数语言中(比如C和Java),数组的大小是固定的,想添加元素就要创建一个全新的数组,不能简单地往其中添加所需的元素。
要存储多个元素,数组可能是最常用的数据结构。但是,如果要存储数据,并且会有移除或者添加大量数据时候,链表比数组更实用。
js数据结构与算法--单链表的实现与应用思考的更多相关文章
- JS数据结构与算法--单向链表
链表结构:链表中每个元素由一个存储元素本身的节点和一个指向下一元素的引用组成.如下所示(手画的,比较丑,懒得用工具画了,嘻嘻) 1.append方法,向链表末尾插入一个节点 2.insert(posi ...
- JS数据结构与算法-概述
JS数据结构与算法概述 数据结构: 计算机存储, 组织数据的方式, 就像锅碗瓢盆 算法: 一系列解决问题的清晰指令, 就像食谱 两者关系: 程序 = 数据结构 + 算法 邂逅数据结构与算法 什么是数据 ...
- JS数据结构与算法——栈
JS数据结构与算法--栈 1.栈结构概念 栈(Stack)是一种先进后出(LIFO Last in First out)的线性表,先进栈的将会比后进栈的先出栈. 栈的限制是仅允许在一端进行插入和删除运 ...
- 数据结构:DHUOJ 单链表ADT模板应用算法设计:长整数加法运算(使用单链表存储计算结果)
单链表ADT模板应用算法设计:长整数加法运算(使用单链表存储计算结果) 时间限制: 1S类别: DS:线性表->线性表应用 题目描述: 输入范例: -5345646757684654765867 ...
- 数据结构&算法-单链表
1.引言 工作一年了,感觉越来越懒散,把很多基础性的东西都慢慢遗忘了,最近想趁着还没忘完,回顾一下,整理了点笔记,分享一下. 如有错的地方,欢迎大家怒喷. 2.学习 我们就从最简单的链表开始吧. 链表 ...
- Java数据结构和算法之链表
三.链表 链结点 在链表中,每个数据项都被包含在‘点“中,一个点是某个类的对象,这个类可认叫做LINK.因为一个链表中有许多类似的链结点,所以有必要用一个不同于链表的类来表达链结点.每个LINK对象中 ...
- Java数据结构和算法(四)--链表
日常开发中,数组和集合使用的很多,而数组的无序插入和删除效率都是偏低的,这点在学习ArrayList源码的时候就知道了,因为需要把要 插入索引后面的所以元素全部后移一位. 而本文会详细讲解链表,可以解 ...
- 数据结构——Java实现单链表
一.分析 单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素.链表中的数据是以结点来表示的,每个结点由元素和指针构成.在Java中,我们可以将单链表定义成一个类,单链表的基 ...
- js数据结构与算法--双向链表的实现
双向链表也叫双链表,是链表的一种,它的每个数据节点中都有两个指针,分别指向直接后继和直接前驱.所以,双向链表中的任意一个节点开始,都可以很方便的访问它的前驱节点和后继节点. 双向链表的实现 linke ...
随机推荐
- python模拟蒙特·卡罗法计算圆周率
蒙特·卡罗方法是一种通过概率来得到问题近似解的方法,在很多领域都有重要的应用,其中就包括圆周率近似值的计问题. 假设有一块边长为2的正方形木板,上面画一个单位圆,然后随意往木板上扔飞镖,落点坐标(x, ...
- apue——无缓冲读写操作
stdrw.c文件 #include "apue.h" #define BUFFSIZE 4096 #include <stdio.h> int main(int ar ...
- Springboot-async(异步)初识
通过@Async注解实现一个简单的异步任务处理 首先,假设一个全自动化的工厂车间每天需要开启四台互不影响的机器开关来完成生产量,于是车间主任A委派“同步甲”和“异步乙”轮 流完成每天打开机器开关的任务 ...
- 【Unity编辑器】UnityEditor多重弹出窗体与编辑器窗口层级管理
一.简介 最近马三为公司开发了一款触发器编辑器,对于这个编辑器策划所要求的质量很高,是模仿暴雪的那个触发器编辑器来做的,而且之后这款编辑器要作为公司内部的一个通用工具链使用.其实,在这款触发器编辑器之 ...
- ES6.3.2 副本失败处理
ES6.3.2 副本失败处理 副本的失败处理对理解ES的数据副本模型很有帮助.在ES6.3.2 index操作源码流程的总结中提到:ES的写操作会先写主分片,然后主分片再将操作同步到副本分片.本文给出 ...
- PHP中的数组
一.数组的基础 php数组的分类 按照下标的不同,php分为关联数组与索引数组: 索引数组:下标从零依次增长(以前那种) 关联数组:下标为字符串格式,每个下标字符串与数组的值一一关联对应(有点儿像对象 ...
- thinkphp5+vue+iview商城 公众号+小程序更新版本
thinkphp5+vue+iview商城加分销 源码下载地址:http://github.crmeb.net/u/crmeb 演示站后台:http://demo25.crmeb.net 账号:dem ...
- 整理c盘文件
清理大文件时,发现以下目录文件过大,删除后可以正常启动java程序,此目录应该是安装jdk时的缓存文件,可以删除 C:\Users\xxxx\AppData\LocalLow\Oracle\Java\ ...
- 004 使用scrapy框架爬虫
0. 建立housePro的scrapy爬虫框架 # 1. 在终端输入,建立housePro项目scrapy startproject housePro# 2. 进入houseProcd houseP ...
- 普通用户授予select any table 权限
基于应用的需要,让普通用户有访问sys表的权限,于是就想到了select any table 的权限,可是当授权以后发现还是不能访问sys的表,经过查一系列资料,发现select any table不 ...