JS实现单向链表、双向链表、循环链表
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
双向链表提供了两种迭代列表的方法:从头到尾,或则反过来。在单链表中,如果我们在迭代列表中错过了要找的元素,就需要回到列表的起点,重新开始迭代,这是双向列表的优点。
双向链表与单向链表的实现类似,需要同时控制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实现单向链表、双向链表、循环链表的更多相关文章
- 原生JS实现单向链表
1.前言 用JS实现一个简单的单向链表,并完成相关的功能 2.功能说明 push(value):从链表尾部添加一个新的节点 insertAfer(value,item):向链表中的item节点之后插入 ...
- 单链表、循环链表的JS实现
数据结构系列前言: 数据结构作为程序员的基本知识,需要我们每个人牢牢掌握.近期我也展开了对数据结构的二次学习,来弥补当年挖的坑...... 当时上课的时候也就是跟着听课,没有亲自实现任何一种数据结 ...
- 《Java数据结构》链表结构(单向链表,双向链表)
单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始:链表是使用指针进行构造的列表:又称为结点列表,因为链表是由一个个结点组装起来的:其中每个结点都有指 ...
- Python 单向链表、双向链表
用面向对象实现Linkedlist链表 单向链表实现append.iternodes 双向链表实现append.pop.insert.remove.iternodes 单向链表与双向链表 单向链表: ...
- Python链表的实现与使用(单向链表与双向链表)
参考[易百教程]用Python实现链表及其功能 """ python链表的基本操作:节点.链表.增删改查 """ import sys cl ...
- 玩转C线性表和单向链表之Linux双向链表优化
前言: 这次介绍基本数据结构的线性表和链表,并用C语言进行编写:建议最开始学数据结构时,用C语言:像栈和队列都可以用这两种数据结构来实现. 一.线性表基本介绍 1 概念: 线性表也就是关系户中最简单的 ...
- 用Python写单向链表和双向链表
链表是一种数据结构,链表在循环遍历的时候效率不高,但是在插入和删除时优势比较大. 链表由一个个节点组成. 单向链表的节点分为两个部分:存储的对象和对下一个节点的引用.注意是指向下一个节点. 而双向链表 ...
- Java-链表(单向链表、双向链表)
Java-链表 1.什么是链表? 2.链表的特点是什么? 3.链表的实现原理? 4.如何自己写出一个链表? 1.什么是链表? 链表是一种物理存储单元上非连续.非顺序的存储结构,数据元素的逻辑顺序是通过 ...
- MySQL记录之间是单向链表还是双向链表?
前言 本文的观点是基于MySQL使用Innodb存储引擎的情况下进行的! 很多渠道说:MySQL数据按照主键大小依次排列,记录之间是双向链表连起来.如果说我告诉你这种说法很大程度上是错的,你肯定说我在 ...
随机推荐
- sqlserver2012——EXISTS关键字
1.返回TRUE或者FALSE 如果exists查询存在,则能查询出来 select a.* From 成绩信息 a ’) 2.判断用户登录 ) ) ' set @pwd='xxxxxxx' if e ...
- MVC动态生成的表单:表单元素比较多 你就这样写
MVC动态生成的表单:表单元素比较多 你就这样写: public ActionResult ShoudaanActionResult(FormCollection from,T_UserM user) ...
- ue4-C++中加载一个蓝图类(二)-C++中绑定Blueprint武器
editor中编辑好一个武器蓝图资源后,c++中create出这个武器,然后attach到一个人物身上. 思路: 写个c++基类,蓝图继承后编辑成武器或其他装备,然后c++用一个TSubclassO ...
- [Xcode 实际操作]六、媒体与动画-(17)使用MediaPlayer框架播放视频
目录:[Swift]Xcode实际操作 本文将演示视频的播放功能. 在项目名称上点击鼠标右键,弹出右键菜单, 选择[Add Files to "DemoApp"],往项目中导入文件 ...
- [LOJ3054] 「HNOI2019」鱼
[LOJ3054] 「HNOI2019」鱼 链接 链接 题解 首先想 \(O(n^3)\) 的暴力,不难发现枚举 \(A\) 和 \(D\) 后, \((B,C)\) 和 \((E,F)\) 两组点互 ...
- [洛谷P4315] 月下”毛景“树
题目链接: 点我 题目分析: 树剖.将边权下放到下方点上(为什么要选深度更深的点?一个父亲可能对应多个儿子,但一个儿子只有一个父亲,即可以保证每个点只保存一条边权)成为经典点权+树剖裸题 注意链计算时 ...
- Python 开发基础-字符串类型讲解(字符串方法)-2
s = 'Hello World!'print(s.index('W',0,9))#返回某个字母的索引值,本例返回6.没有该字母会报错,和FIND比较像,find不会报错,没找到会返回-1print( ...
- storm maven-shade-plugin
storm-core pom <plugin> <groupId>org.apache.maven.plugins</groupId> <artifact ...
- 最长回文子串--轻松理解Manacher算法
最长回文子串这个问题的Manacher算法,看了很多博客,好不容易理解了,做一下记录. 这个算法的核心就是:将已经查询过的子字符串的最右端下标保存下来,在计算下标为i的回文字符串时,不需要从左右相邻的 ...
- python 6 循环
循环 要计算1+2+3,我们可以直接写表达式: >>> 1 + 2 + 3 6 要计算1+2+3+...+10,勉强也能写出来. 但是,要计算1+2+3+...+10000,直接写表 ...