链表与约瑟夫环 - JavaScript版

2023-11-14

前言

在很多编程语言中,数组需要预先给定一个长度,添加新的元素很难;而且添加、删除等操作也比较烦,需要循环操作。

JavaScript提供了push()splice()等函数来解决这类问题。
注意:在js中数组是对象(Object):
数组

js没有内置链表:因为 JavaScript 的数组长度是动态的,所以就没有了链表的必要,而且数组可以满足链表几乎所有的操作。而且现在各种对 JavaScript 的实现中,对数组的优化也是很完善的,数组的性能不一定比链表差。
而且需要随机访问元素时,还是数组更方便。

但是,链表作为一种十分基础的数据结构,还是需要学习一下的。这里只是借助js讲解链表的实现。

百度百科上面的解释:

链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。

如果没了解过链表,这应该很难理解。

首先,链表类型有:

  • 单向链表
  • 双向链表
  • 循环链表

这里分开介绍,并使用js代码实现 链表。
(这里使用 function ListNode(val){} 的方式实现类,你也可以使用 class,可以参考其他文章;)

单向链表

单向链表由一系列结点组成,单向链表起始点会有一个特殊节点,叫做头节点;
除了头节点外的节点都包含一个值和下一个节点的引用(链);
链表尾部指向为null

单向链表结构图

利用链表,添加和删除都比较容易:
添加

删除

代码实现

  1. Node类,用于表示节点;

val保存节点上的数据
next保存指向下一个节点的链接

function Node(val){
    this.val = val;
    this.next = null;
}

Node类即为单向链表的基本形式

  1. LinkedList 类 提供对链表进行操作的方法
function LinkedList(){
    this.head = new Node("head");
    this.find = NodeFind;
    this.insert = NodeInsert;
    this.remove = NodeRemove;
    this.display = NodeDisplay;
}

类中方法实现:

function NodeFind(item){ // 查找值为item的Node
    var currNode = this.head;
    while(currNode.val !== item){
    if(currNode.next == null) return 0; // 后续进行约瑟夫环的计算时要用
        currNode = currNode.next;
    }
    return currNode;
}
function NodeInsert(newElement,item){ // 插入数值
    var newNode = new Node(newElement),
        current = this.find(item);
    newNode.next = current.next;
    current.next = newNode;
}
function NodeDisplay(){
    var currNode = this.head;
    while(!(currNode.next === null)){
        console.log(currNode.next.val);
        currNode = currNode.next;
    }
}
function NodeRemove(item){
    // 从head开始,找到前一个node
    var prevNode = this.head;
    while(prevNode.next.val !== item){
        prevNode = prevNode.next;
    }
    // 删除
    prevNode.next = prevNode.next.next;
}

使用new LinkedList()方法可以创建带有方法的Node链表。
this.insert()可以插入数值。

测试代码:

var test = new LinkedList();
test.insert("a","head");
test.insert("b","a");
test.insert("c","b");
test.insert("d","c");
test.remove('d');

test.display();

双向链表

单向链表并不能从最后的节点遍历到最前面的节点。

给单向链表中每个节点加上一个属性,指向前一个节点。

image.png

增加 this.previous 连接前一个节点

function Node2(val){
    this.val = val;
    this.next = null;
    this.previous = null;
}

具体链表方法 读者可自己实现。

循环链表

最后一个结点的指针域指向头结点,整个链表形成一个环。
只需要在构造函数中加入 this.head.next = this.head 即可

约瑟夫环 问题

传说在公元 1 世纪的犹太战争中,犹太历史学家弗拉维奥·约瑟夫斯和他的 40 个同胞被罗马士兵包围。犹太士兵决定宁可自杀也不做俘虏,于是商量出了一个自杀方案。他们围成一个圈,从一个人开始,数到第三个人时将第三个人杀死,然后再数,直到杀光所有人。约瑟夫和另外一个人决定不参加这个疯狂的游戏,他们快速地计算出了两个位置,站在那里得以幸存。请问哪两个位置?写一段程序将 n 个人围成一个圈,并且第 m 个人会被杀掉,计算一圈人中哪两个人会存活。

数组方法

/**
 * @param len 人数
 * @param start  开始位置
 * @param interval 间隔
 * @return {string} 幸存者位置信息
 */
function JosephCircle(len=50,start=1,interval=3){
    if(len<start){
        return "error,length must bigger than start!";
    }
    let people = Array(len).fill(1); // 用1表示活着
    let position = start-1, // 数到的位置
        count = 0,n = len;
    while(n>1){
        count += people[position];
        if(count === interval){
            count = 0;
            people[position] = 0;
            n --;
        }
        if(position === len-1){
            position = 0;
        }else{
            ++position;
        }
    }
    return "幸存者位置为:"+(people.indexOf(1)+1);
}

测试:

console.log(JosephCircle(50,3));

链表方法

/**
 * @param len 人数
 * @param start  开始位置
 * @param interval 间隔
 * @return {string} 幸存者位置信息
 */
function JosephRing2(len=40,start=1,interval=3){
    if(len<1 || start <1 || interval<2 || start>len){
        return "数据有误!";
    }
    let people = new LinkedList();
    people.insert(1,"head");
    for(let i = 2;i<=len;i++){
        people.insert(i,i-1);
    }
    let n = len,count = 0,i=start;
    while(n>1){
        count += people.find(i)? 1:0;
        if(count === interval){
            count = 0;
            people.remove(i);
            n -- ;
        }
        if(i === len){
            i = people.head.next.val;
        }else{
            i++;
        }
    }
    return "幸存者位置为:"+people.head.next.val;
}

测试:

console.log(JosephRing2(40,1,3));

两种方法时间效率比较

// 数组
let now1 = new Date();
console.log(JosephRing(40,1,3));
let now2 = new Date();
console.log(now2-now1 + "ms");
// 链表
let now3 = new Date();
console.log(JosephRing2(40,1,3));
let now4 = new Date();
console.log(now4-now3 + "ms");

image.png

由此可见,链表的效率很高。

参考文章

有关链表练习题目可以去leetcode学习:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

链表与约瑟夫环 - JavaScript版 的相关文章

  • 无法将消息发布到服务工作人员,因为控制器值为空

    我正在尝试做一个website https secure depths 31934 herokuapp com 在 Service Worker 的帮助下可以离线使用 以缓存页面所需的文件 我试图让用户控制他希望缓存的图像 为此 我使用一个
  • 在 IE8 中使用 javascript __proto__

    你好 我在 javascript 中有这两个对象 var john firstname John lastname Smith var jane firstname Jane 这样做 jane proto john 我可以访问 Jane 的
  • 如何从 javascript 错误对象读取错误消息

    有人可以帮我解决以下问题吗 我正在通过 redux 操作进行后调用 如下所示 export const addEmployee firstName surname contactNumber email gt async dispatch
  • 多次训练brain.js?

    在第一次训练后 如何将新信息 仅新信息 而不是所有信息 因为这会花费太多性能 训练到我的用 Brain js 制作的神经网络 它有点粗糙 但您可以使用以下结构来实现 如果我们加入 2 个训练数据集 旧数据集与新数据集 然后重新训练keepN
  • JavaScript 可以检测用户的浏览器是否支持 gzip 吗?

    我可以使用 JavaScript 来检测用户的浏览器是否支持 gzip 压缩内容 客户端 而不是 Node js 或类似内容 我正在尝试支持以下边缘情况 有很多可能的文件可以加载到特定的 Web 应用程序上 最好在应用程序运行时根据需要加载
  • html 图像 src 调用 javaScript 变量

    这是我的代码 我想问 我怎样才能做到这一点 img src img apple 我一直在尝试使用 call 函数和 document onload 但它根本不起作用 有人可以救我吗 我假设你只是想用 javascript 更新图像 src
  • tomcat 7.0.50 java websocket 实现给出 404 错误

    我正在尝试使用 Java Websocket API 1 0 JSR 356 中指定的带注释端点在 tomcat 7 0 50 上实现 websocket 以下是我如何对其进行编码的简要步骤 1 使用 ServerEndpoint注解编写w
  • jquery 中可点击 div 中的按钮

    我有整个 div 您可以单击它来切换该 div 的主要部分 问题是我在该 div 中也有可点击的按钮 当我点击它时 它会执行它应该做的事情 但同时也会切换整个 div 我怎样才能禁用它 Use event stopPropagation 单
  • 如何绕过Access-Control-Allow-Origin?

    我正在一个平台上对我自己的服务器进行ajax调用 他们设置了阻止这些ajax调用的平台 但我需要它从我的服务器获取数据以显示从我的服务器数据库检索到的数据 我的 ajax 脚本正在运行 它可以将数据发送到我的服务器的 php 脚本以允许其处
  • Angular 2 将字符串转换为 md5 哈希

    我找到了ts md5 https www npmjs com package ts md5包 但在示例中它有一个hashStr方法 但现在不行了 类型上不存在属性 hashStr Md5 使用该错误后 该错误会记录在我的控制台中 我怎样才能
  • Javascript location.href 到 mailto 触发 GET HTTP,该 HTTP 在 Chrome 中被取消

    我有一个按钮可以触发以下 javascript 函数 function sendEmail var mail mailto email protected cdn cgi l email protection location href m
  • 在 javascript 中实现固定位置会导致 Safari 滚动时出现抖动

    固定位置不适用于我的用例 因为它固定在浏览器窗口上 您可能会处于文本在屏幕右侧之外且无法到达的状态 无论如何 我尝试使用绝对定位 然后调整javascript中的 顶部 它在 Firefox 和 Chrome 中运行良好 但在 Safari
  • 为什么我的 D3 SVG 图上的轴不会更新?

    I have 简单的 D3 散点图 http www raxacoricofallapatorius com test scattertest html我在显示数据的几个不同属性之间切换 但是虽然我可以更改数据点 并按照我想要的方式进行转换
  • 如何在 Javascript 中连接 C# ActiveX 事件处理程序

    我尝试使用几个代码片段将 ActiveX 对象与 Javascript 事件处理程序挂钩 我无法确定为什么事件处理程序没有被调用 带有项目的 Github 存储库 https github com JesseKPhillips Csharp
  • 此版本的 CLI 仅与 Angular 版本 5.0.0 或更高版本兼容错误

    我已经有 Angular 项目在 4 版本中运行 在安装新项目时 不幸的是我安装了 6 版本的 Angular cli 在以 4 版本运行的旧项目中运行 ngserve 命令时 这会引发错误 您的全局 Angular CLI 版本大于本地版
  • 如何使用 Javascript OAuth 库不暴露您的密钥?

    看着Twitter OAuth 库 https dev twitter com docs twitter libraries 我看到了这个注释 将 JavaScript 与 OAuth 结合使用时要小心 不要暴露你的钥匙 然后 看着jsOA
  • 如果 jquery 验证激活,如何在单选按钮中放置红色边框[重复]

    这个问题在这里已经有答案了 我的问题是 如果 jquery 验证像示例图片中那样激活 我无法使单选按钮具有红色边框 任何人都可以帮我解决这个问题吗 http i38 photobucket com albums e149 eloginko
  • javascript:完全删除top.location.hash?

    如果我的地址栏中已经有一个哈希值 例如domain com whatever 我打电话 top location hash wathever 被转换为domain com 没有任何内容 是否可以完全删除哈希值 所以没有 left 因为如果我
  • VS Code 扩展 - 获取完整路径

    我正在为 VS Code 编写一个插件 我需要知道调用扩展的文件的路径 无论是从编辑器上下文菜单或资源管理器上下文菜单调用还是用户只需键入扩展命令 function activate context get full path of the
  • 如何从 Cloud Functions for Firebase 文件夹读取证书文件

    我正在尝试读取 certs 文件夹下的文件 如下所示 functions certs idp public cert perm 这是我用来读取文件的代码 fs readFileSync path join dirname certs idp

随机推荐

  • 极简式 Unity 获取 bilibili 直播弹幕、SC、上舰、礼物等 插件

    极简式 Unity 获取 bilibili 直播弹幕 SC 上舰 礼物等 1 声明 下载链接 软件均仅用于学习交流 请勿用于任何商业用途 2 介绍 该项目为Unity实时爬取B站直播弹幕 项目介绍 通过传入B站直播间账号 实现监控B站直播弹
  • java threadlocal 详解_Java中的ThreadLocal深入理解详解

    提到 ThreadLocal是什么 ThreadLocal是一个关于创建线程局部变量的类 通常情况下 我们创建的变量是可以被任何一个线程访问并修改的 而使用ThreadLocal创建的变量只能被当前线程访问 其他线程则无法访问和修改 Glo
  • sha256的python实现

    在 Python 中可以使用 hashlib 库来实现 SHA 256 哈希算法 代码如下 import hashlib defsha256 data sha256 hashlib sha256 sha256 update data enc
  • 为什么printf只能用_cdecl调用约定

    1 什么是调用约定 调用约定 Calling conventions 和type representations 名称修饰 name mangling 同是应用二进制接口 application binary interface ABI 概
  • 分析rocketmq-client产生大量rocketmq_client.log日志文件的原因处理方案

    源码 public static final String CLIENT LOG USESLF4J rocketmq client logUseSlf4j public static final String CLIENT LOG ROOT
  • 05 两层神经网络 - 神经网络和深度学习 [Deep Learning Specialization系列]

    本文是Deep Learning Specialization系列课程的第1课 Neural Networks and Deep Learning 中Shallow Neural Network部分的学习笔记 在前面的章节中 我们以逻辑回归
  • Yolov5改进之更改损失函数(EIOU、SIOU)

    目录 1 修改metrics py文件 2 修改loss py函数 1 修改metrics py文件 找到bbox iou代码段 def bbox iou box1 box2 xywh True GIoU False DIoU False
  • 测试用例----测试大纲法

    一 应用场合 在一个程序中涉及多个窗口 每个窗口有多个操作 窗口和窗口之间有一定的联系 或者说操作之间的联系 为了弄清它们之间的联系 使用测试大纲法 二 使用测试大纲法分析程序 1 列大纲 提纲 分析需求 列出所有的窗口以及每个窗口包含的操
  • MQTT 固定报头 中 剩余长度字段的计算

    剩余长度 简介 位置 固定报头中 从第2个字节开始 剩余长度等于可变报头的长度 10字节 加上有效载荷的长度 剩余长度 Remaining Length 表示当前报文剩余部分的字节数 包括可变报头和负载的数据 剩余长度不包括用于编码剩余长度
  • 什么是区块链----概念

    前言 从2016年年初开始 区块链这个概念越来越热越来越火 有人说他可以颠覆金融行业 也有人觉得这就是个噱头 这个2016火起来的技术其实早在2008年 比特币的诞生就基于区块链 技术火归火 落地的应用却没有那么多 周围的朋友同学都听说过这
  • 搭建Serv-U FTP服务器共享文件外网远程访问「无公网IP」

    文章目录 1 前言 2 本地FTP搭建 2 1 Serv U下载和安装 2 2 Serv U共享网页测试 2 3 Cpolar下载和安装 3 本地FTP发布 3 1 Cpolar云端设置 3 2 Cpolar本地设置 4 公网访问测试 5
  • linux系统通过docker安装oracle远程访问(附带相关问题解决方案)

    文章目录 一 虚拟机网络配置 二 安装docker 三 拉取oracle镜像并配置 四 设置oracle支持外部连接访问 重难点 总结 一 虚拟机网络配置 虚拟机配置的方案 1 桥接模式 虚拟机和主机共用同一个网段 适用于固定网络的开发环境
  • auto refresh

    div user div
  • TCP为什么需要三次握手进行连接,二次或四次不可以吗?

    一 三次握手的作用 为了确认双方具有接收和发送的能力 二 三次握手的原因 1 可以阻止重复历史连接的初始化 主要原因 2 可以同步双方的初始序列号 3 可以避免资源的浪费 三 分析原因 1 为了防止旧的重复连接初始化造成混乱 当客户端发送了
  • 嵌入式软件中如何排查bug?

    明确Bug现象 要准确描述Bug出现的场景 现象 能复现就最好 查看日志信息 嵌入式系统日志可以帮助定位问题 看是否有报错 异常信息 用仿真工具调试 许多嵌入式芯片都有相应的仿真调试工具 可以在仿真环境下单步跟踪 查看变量值等 加打印调试
  • C# DataSet和DataTable:将查询结果保存到DataSet或DataTable中

    在执行对表中数据的查询时还能将数据保存到 DataSet 中 但需要借助 DataAdapter 类来实现 在实际应用中 DataAdapter 与 DataSet 是在查询操作中使用最多的类 此外 还可以通过 DataSet 实现对表中数
  • android pdf框架

    系列文章目录 第一章 android pdf框架 文章目录 系列文章目录 前言 一 主流pdf解析库有哪些 二 对比与使用 1 库对比 2 使用方式 总结 前言 pdf已经使用很普遍了 android上的好用的pdf工具也有不少 个人更经常
  • 倪文迪陪你学蓝桥杯2021寒假每日一题:(2017省赛A第1、2题)

    2021年寒假每日一题 2017 2019年的省赛真题 本文内容由倪文迪 华东理工大学计算机系软件192班 和罗勇军老师提供 文章目录 一 2017年蓝桥杯软件类 C语言大学A组 1 迷宫 2 跳蚱蜢 2 1 建模 2 2 判重 2 3 m
  • 罗技MX Keys从蓝牙连接切换为优联(无线接收器)连接

    不知道什么原因用最近MX Keys蓝牙连接mac怪卡的 按一个键按四五下电脑上才有反应 于是还是想用无线接收器连接来控制电脑 按照壳子上按fn o来切换好像不太管用 于是试了很久 最后用罗技自家的键盘管理软件切换上了 先下一个Logi Op
  • 链表与约瑟夫环 - JavaScript版

    前言 在很多编程语言中 数组需要预先给定一个长度 添加新的元素很难 而且添加 删除等操作也比较烦 需要循环操作 JavaScript提供了push 和splice 等函数来解决这类问题 注意 在js中数组是对象 Object js没有内置链