第一种
/**
* 链表节点类
*/
class Node {
constructor(ele) {
this.ele = ele;
this.next = null;
}
}
/**
* 链表类
*/
class NodeList {
constructor(ele) {
this.head = new Node(ele); //初始化链表的头节点
}
findPreNode(item) {
let currentNode = this.head;
while (currentNode && currentNode.next && currentNode.next.ele !== item) {
if (currentNode.next) {
currentNode = currentNode.next;
} else {
currentNode = null;
} }
return currentNode;
}
findNode(item) {
let currentNode = this.head; while (currentNode && currentNode.ele !== item) {
if (currentNode.next) {
currentNode = currentNode.next;
} else {
currentNode = null;
}
} return currentNode;
}
findLastNode() {
let currentNode = this.head;
while (currentNode.next) {
currentNode = currentNode.next;
}
return currentNode;
}
append(newItem, preItem) {
let newNode = new Node(newItem);
if (preItem) { // 判读是否是插入到指定节点后面,如果不是则插入到最后一个节点。
let currentNode = this.findNode(preItem);
newNode.next = currentNode.next;
currentNode.next = newNode;
} else {
let lastNode = this.findLastNode();
lastNode.next = newNode;
}
}
remove(item) {
let preNode = this.findPreNode(item); // 找到前一节点,将前一节点的next指向该节点的next
if (preNode.next != null) {
preNode.next = preNode.next.next;
}
}
toString() {
let currentNode = this.head; let strList = [];
while (currentNode.next) {
strList.push(JSON.stringify(currentNode.ele));
currentNode = currentNode.next;
}
strList.push(JSON.stringify(currentNode.ele)); return strList.join(' ==> ')
}
/* 逆置分析

单链表分为带头节点和不带头节点两种,逆置思路有两种,第一种是采用头插法重新建立新的单链表,该方法直接遍历链表,每次将当前结点添加到新链表的头部;第二种是通过该表*next指针,定义三个指针*pre, *p, *r,分别表示三个连续结点,将p->next指向pre,但       同时p的后继节点会断开,所以需要用r保存其后继节点。

*/

// 头插法
reverse () {
let p = null;
let current = this.head;
while (current !== null) {
const temp = current.next;
current.next = p;
p = current;
current = temp;
}
return p;
} // 1 -> 2 -> 3 -> 4
// r
// 修改*next指针
reverse2 () {
let pre = null;
let p = null;
let r = null;
r = this.head;
while (r !== null) {
if (p === null) {
p = r;
r = r.next;
p.next = null;
continue;
}
pre = p;
p = r;
r = r.next;
p.next = pre;
}
return p;
}
}
let A = { name: 'A', age: 10 },
B = { name: 'B', age: 20 },
C = { name: 'C', age: 30 },
D = { name: 'D', age: 40 },
E = { name: 'E', age: 50 }; let nList = new NodeList(A); nList.append(C);
nList.append(B);
nList.append(D);
nList.append(E, A);
console.log(" " + nList);
nList.remove(C);
console.log(" now " + nList)

 
origin: {"name":"A","age":10} ==> {"name":"E","age":50} ==> {"name":"C","age":30} ==> {"name":"B","age":20} ==> {"name":"D","age":40}
now: {"name":"A","age":10} ==> {"name":"E","age":50} ==> {"name":"B","age":20} ==> {"name":"D","age":40}
第二种
/**
* 链表节点类
*/
class Node {
constructor (ele) {
this.ele = ele;
this.next = null;
}
}
/**
* 链表类
*/
class NodeList {
constructor (ele) {
this.head = null; // 初始化链表的头节点
this.lenght = 0;
}
/**
* 尾部插入数据
* @param {*} ele
*/
append (ele) {
let newNode = new Node(ele);
let currentNode;
if (this.head === null) {
this.head = newNode;
} else {
currentNode = this.head;
while (currentNode.next) {
currentNode = currentNode.next;
}
currentNode.next = newNode;
}
this.lenght++;
}/**
* 项链表某个位置插入元素
* @param {*} position
* @param {*} ele
*/
insert (position, ele) {
if (position >= 0 && position <= this.lenght) {
let newNode = new Node(ele);
let currentNode = this.head;
let pre;
let index = 0;
if (position === 0) {
newNode.next = currentNode;
this.head = newNode;
} else {
while (index < position) {
pre = currentNode;
currentNode = currentNode.next;
index++;
}
newNode.next = currentNode;
pre.next = newNode;
}
this.lenght++;
} else {
return new Error('位置超出范围');
}
}
removeAt (position) {
if (position >= 0 && position < this.lenght) {
let currentNode = this.head;
let pre;
let index = 0;
if (position === 0) {
this.head = currentNode.next;
} else {
while (index < position) { // 1,2,3
pre = currentNode;
currentNode = currentNode.next;
index++;
}
pre.next = currentNode.next;
}
this.lenght--;
} else {
return new Error('删除位置有误');
}
}
find (ele) {
let currentNode = this.head;
let index = 0;
while (currentNode) {
if (JSON.stringify(currentNode.ele) === JSON.stringify(ele)) {
return index;
} else {
index++;
currentNode = currentNode.next;
}
}
return -1;
}
// 判断链表是否为空
isEmpty () {
return this.length === 0;
}
size () {
return this.length;
}
// 返回头
getHead () {
return this.head;
}
toString () {
let current = this.head;
let str = '';
while (current) {
str += JSON.stringify(current.ele) + ' => ';
current = current.next;
}
return str;
}
}
let A = { name: 'A', age: 10 }; let B = { name: 'B', age: 20 }; let C = { name: 'C', age: 30 }; let D = { name: 'D', age: 40 }; let E = { name: 'E', age: 50 }; let nList = new NodeList(); nList.append(A);
nList.append(C);
nList.append(B);
nList.append(D);
nList.append(E);
// console.log(JSON.stringify(nList, null, 2));
console.log(' origin: ' + nList);
nList.removeAt(2);
console.log(' now: ' + nList);

origin: {"name":"A","age":10} => {"name":"C","age":30} => {"name":"B","age":20} => {"name":"D","age":40} => {"name":"E","age":50} =>
now: {"name":"A","age":10} => {"name":"C","age":30} => {"name":"D","age":40} => {"name":"E","age":50} =>

参照:https://blog.csdn.net/qq_40941722/article/details/94381637

es6 实现单链表的更多相关文章

  1. 时间复杂度分别为 O(n)和 O(1)的删除单链表结点的方法

    有一个单链表,提供了头指针和一个结点指针,设计一个函数,在 O(1)时间内删除该结点指针指向的结点. 众所周知,链表无法随机存储,只能从头到尾去遍历整个链表,遇到目标节点之后删除之,这是最常规的思路和 ...

  2. 单链表的C++实现(采用模板类)

    采用模板类实现的好处是,不用拘泥于特定的数据类型.就像活字印刷术,制定好模板,就可以批量印刷,比手抄要强多少倍! 此处不具体介绍泛型编程,还是着重叙述链表的定义和相关操作.  链表结构定义 定义单链表 ...

  3. Java实现单链表的各种操作

    Java实现单链表的各种操作 主要内容:1.单链表的基本操作 2.删除重复数据 3.找到倒数第k个元素   4.实现链表的反转   5.从尾到头输出链表 6.找到中间节点 7.检测链表是否有环 8.在 ...

  4. [LeetCode] Linked List Cycle II 单链表中的环之二

    Given a linked list, return the node where the cycle begins. If there is no cycle, return null. Foll ...

  5. c++单链表基本功能

    head_LinkNode.h /*单链表类的头文件*/#include<assert.h>#include"compare.h"typedef int status; ...

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

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

  7. C代码实现非循环单链表

    C代码实现非循环单链表, 直接上代码. # include <stdio.h> # include <stdlib.h> # include <malloc.h> ...

  8. 分离的思想结合单链表实现级联组件:CascadeView

    本文介绍自己最近做省市级联的类似的级联功能的实现思路,为了尽可能地做到职责分离跟表现与行为分离,这个功能拆分成了2个组件并用到了单链表来实现关键的级联逻辑,下一段有演示效果的gif图.虽然这是个很常见 ...

  9. 数据结构:单链表结构字符串(python版)添加了三个新功能

    #!/urs/bin/env python # -*- coding:utf-8 -*- #异常类 class stringTypeError(TypeError): pass #节点类 class ...

随机推荐

  1. 车型识别API调用与批量分类车辆图片

    版权声明:本文为博主原创文章,转载 请注明出处 https://blog.csdn.net/sc2079/article/details/82189824 9月9日更:博客资源下载:链接: https ...

  2. HandlerMethodArgumentResolver完美解决 springmvc注入参数多传报错

    作为一个后端开发,能友好兼容前端参数传入错误等问题,在前端发布不小心多传一个参数导致系统错误的问题,一个广告系统是零容忍的,所以为了不犯错误,后端接收参数必须摒弃spring 的自动注入@Reques ...

  3. 关于SendMessage和PostMessage的理解的例子

    对于SendMessage 和 PostMessage 平时口头的解释是 SendMessage 发送消息后等待返回, PostMessage 发送消息后立即返回 . 但是这样解释还是不具体,什么叫等 ...

  4. R的数据结构--向量

    向量:用于存储数值型.字符型或逻辑型数据的一维数组,只可以包含一种数据 向量的创建与运算 创建向量 # 创建简单向量 l <- c(2, 2, 1, 3, 8) # [1] 2 2 1 3 8 ...

  5. Solving Docker permission denied while trying to connect to the Docker daemon socket

    The error message tells you that your current user can’t access the docker engine, because you’re la ...

  6. 外观模式(Facade)---结构型模式

    1 基础知识 定义:提供了一个统一的接口(外观类),用来访问子系统中的一群接口.特征:定义了一个高层接口让子系统更容易使用,减少了外部与子系统内多个模块的耦合. 本质:封装交互,简化调用. 优点:简化 ...

  7. one(type,[data],fn) 为每一个匹配元素的特定事件(像click)绑定一个一次性的事件处理函数。

    one(type,[data],fn) 概述 为每一个匹配元素的特定事件(像click)绑定一个一次性的事件处理函数. 在每个对象上,这个事件处理函数只会被执行一次.其他规则与bind()函数相同.这 ...

  8. could not load file or assembly "System.Web.Mvc...

    1.一般出现这个错误是因为Web.Config里面的版本号跟project用到的dll版本对应不上 更改webconfig <add assembly="System.Web.Mvc, ...

  9. no suitable method found to override

    no suitable method found to override http://bbs.csdn.net/topics/200001058 

  10. 【转载】BERT:用于语义理解的深度双向预训练转换器(Transformer)

    BERT:用于语义理解的深度双向预训练转换器(Transformer)   鉴于最近BERT在人工智能领域特别火,但相关中文资料却很少,因此将BERT论文理论部分(1-3节)翻译成中文以方便大家后续研 ...