javascript循环链表之约瑟夫环的实现方法

yizhihongxing

当我们在处理需要循环的数据时,循环链表是一种非常常见的数据结构。而约瑟夫环是一个经典的可用于解决Josephus问题的算法,即在一个有限的环中每隔k个(k > 1)数杀掉一个人,直到剩下最后一个人。在 JavaScript 中,我们可以用循环链表来实现该算法。

首先,我们需要定义一个循环链表数据结构

循环链表由链表头和尾组成,头尾相接即为循环链表。我们需要实现添加元素、删除元素、获取某个元素等基本操作。以下是一个简单的 JavaScript 循环链表实现:

class Node {
  constructor(value) {
    this.value = value;
    this.next = null;
  }
}

class CircularLinkedList {
  constructor() {
    this.head = null;
    this.tail = null;
    this.length = 0;
  }

  // 添加元素
  append(value) {
    const newNode = new Node(value);
    if (this.length === 0) {
      this.head = newNode;
      this.tail = newNode;
      newNode.next = this.head;
    } else {
      this.tail.next = newNode;
      this.tail = newNode;
      newNode.next = this.head;
    }
    this.length++;
  }

  // 删除元素
  remove(position) {
    if (position > -1 && position < this.length) {
      let current = this.head;
      let previous = null;
      let index = 0;
      if (position === 0) {
        this.head = current.next;
        this.tail.next = this.head;
        if (this.length === 1) {
          this.tail = null;
        }
      } else if (position === this.length - 1) {
        current = this.tail;
        previous = this.head;
        while (previous.next !== this.tail) {
          previous = previous.next;
        }
        this.tail = previous;
        this.tail.next = this.head;
      } else {
        while (index++ < position) {
          previous = current;
          current = current.next;
        }
        previous.next = current.next;
      }
      this.length--;
    }
  }

  // 获取某个元素
  getElementAt(index) {
    if (index >= 0 && index < this.length) {
      let node = this.head;
      for (let i = 0; i < index && node !== null; i++) {
        node = node.next;
      }
      return node;
    }
    return null;
  }

  // 辅助函数:打印循环链表
  print() {
    let current = this.head;
    let str = "";
    let index = 0;
    while (index < this.length) {
      str += current.value + " ";
      current = current.next;
      index++;
    }
    console.log(str);
  }
}

接下来,我们来实现约瑟夫环算法

约瑟夫环的算法思路如下:

  1. 创建一个长度为n的循环链表
  2. 从链表头开始依次遍历链表,每遍历到第k个节点,就将该节点删除
  3. 不断重复步骤2,直到只剩下一个节点为止

接下来,我们按照算法思路,来实现约瑟夫环的代码:

function josephus(n, k) {
  const list = new CircularLinkedList();
  for (let i = 1; i <= n; i++) {
    list.append(i);
  }
  let current = list.head;
  while (list.length > 1) {
    let count = 1;
    while (count < k) {
      current = current.next;
      count++;
    }
    const next = current.next;
    list.remove(list.indexOf(current.value));
    current = next;
  }
  return list.head.value;
}

我们调用 josephus(10, 2),即可得到结果为 5,即当有10个人,每隔2个人杀掉一个,最后剩下的人的编号为5。

示例2:将删除过程输出,供参考

为了更好地理解算法的实现过程,我们可以将删除过程输出。这里将算法修改一下,增加输出功能:

function josephusWithLog(n, k) {
  const list = new CircularLinkedList();
  for (let i = 1; i <= n; i++) {
    list.append(i);
  }
  let current = list.head;
  let log = "";
  while (list.length > 1) {
    let count = 1;
    while (count < k) {
      current = current.next;
      count++;
    }
    const next = current.next;
    const removed = list.remove(list.indexOf(current.value));
    log += `第${current.value}号被删除,`;
    if (removed !== null) {
      log += `剩余人数为${list.length},剩余人员为:`;
      let current = list.head;
      while (current !== null) {
        log += current.value + " ";
        current = current.next;
      }
      log += "\n";
    }
    current = next;
  }
  log += `最后剩余${list.head.value}号。`;
  console.log(log);
  return list.head.value;
}

我们调用 josephusWithLog(10, 2),即可得到下面的输出:

第2号被删除,剩余人数为9,剩余人员为:1 3 4 5 6 7 8 9 10 
第4号被删除,剩余人数为8,剩余人员为:1 3 5 6 7 8 9 10 
第6号被删除,剩余人数为7,剩余人员为:1 3 5 7 8 9 10 
第8号被删除,剩余人数为6,剩余人员为:1 3 5 7 9 10 
第10号被删除,剩余人数为5,剩余人员为:1 3 5 7 9 
第5号被删除,剩余人数为4,剩余人员为:1 3 7 9 
第1号被删除,剩余人数为3,剩余人员为:3 7 9 
第9号被删除,剩余人数为2,剩余人员为:3 7 
最后剩余3号。

从输出可以清晰地看到,当有10个人,每隔2个人杀掉一个,算法的具体执行过程。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:javascript循环链表之约瑟夫环的实现方法 - Python技术站

(0)
上一篇 2023年6月8日
下一篇 2023年6月8日

相关文章

  • nodejs中模块定义实例详解

    Node.js中的模块定义是一个非常重要的概念,它允许开发者将代码片段和功能封装在一个可重用的单元中,以便在程序中其他地方使用。同时,模块定义也被广泛地应用于Node.js中各种第三方库和框架,因此良好的模块定义实践方法可以提升模块的可维护性和复用性。 1. 模块定义 一个Node.js模块通常包含两部分: 模块引入部分,以便在程序中引入模块,并定义该模块的…

    node js 2023年6月8日
    00
  • Docker部署Nuxt.js项目的实现

    下面我将详细讲解“Docker部署Nuxt.js项目的实现”的完整攻略,过程中包含两条示例说明。 一、什么是Docker Docker是一个开源的容器化平台,可以将应用程序及其依赖项打包在一个轻量级、可移植的容器中。Docker使得开发人员可以用同样的代码,在不同的环境中运行应用程序,同时也提高了应用程序在生产环境中的可靠性和可移植性。 二、在Docker中…

    node js 2023年6月8日
    00
  • 手把手教你VSCode配置JavaScript基于Node.js的调试环境

    手把手教你VSCode配置JavaScript基于Node.js的调试环境 简介 Visual Studio Code(以下简称“VSCode”)是一款优秀的文本编辑器,因其强大的插件生态系统、良好的性能和简便的操作流程而受到广泛欢迎。本文将向你介绍如何在VSCode下配置JavaScript基于Node.js的调试环境。 环境准备 在开始配置调试环境之前,…

    node js 2023年6月8日
    00
  • 代码规范需要防微杜渐code review6个小错误纠正

    下面我将详细讲解“代码规范需要防微杜渐code review6个小错误纠正”的完整攻略。 1. 概述 代码规范是指开发者在编码时需要遵循的一些约定,如变量命名、代码格式、注释规范等。良好的代码规范可以提高代码的可读性、可维护性和可扩展性。而code review(代码审核)则是指对开发人员提交的代码进行仔细的检查和审查,以便发现和纠正代码中的问题和错误。 在…

    node js 2023年6月8日
    00
  • Nodejs 获取时间加手机标识的32位标识实现代码

    一. 概述 在 Node.js 中,我们可以使用 crypto 模块的 createHash() 方法,将一个字符串转成 MD5 编码的32位标识。而我们可以将手机的IMEI或者序列号和时间戳进行拼接,生成一个带时间和手机标识的32位唯一标识。 二. 实现步骤 安装 crypto 模块 npm install crypto –save 引入 crypto …

    node js 2023年6月8日
    00
  • JavaScript中实现键值对应的字典与哈希表结构的示例

    在JavaScript中可以实现键值对应的字典或哈希表结构,可以使用对象(Object)或Map来实现。下面分别介绍两种方式的实现方法。 使用对象实现字典和哈希表 JavaScript中的对象是一种拥有键值对应关系的数据类型,可以使用对象模拟字典和哈希表结构。下面是一个示例: // 创建字典 const dict = { ‘key1’: ‘value1’, …

    node js 2023年6月8日
    00
  • nodejs使用Express框架写后端接口的全过程

    完整攻略如下: 介绍 Express是Node.js中最常用的web框架之一,它提供了路由、中间件、模板等功能,可以帮助我们快速开发Web应用程序和API。在此攻略中,我们将介绍如何使用Express框架编写Node.js后端接口。 步骤 安装Node.js 首先需要安装Node.js,可以到官网下载:https://nodejs.org/zh-cn/dow…

    node js 2023年6月8日
    00
  • 搞懂什么是Node.js原来这么简单

    搞懂什么是Node.js原来这么简单 Node.js是一种运行于服务器端的JavaScript运行时环境,它让开发者可以使用JavaScript语言来进行服务器端的开发。这篇文章将会详细介绍Node.js的相关知识,为初学者提供全面的学习攻略。 1. 了解Node.js的基本概念 Node.js是以Google Chrome浏览器的V8 JavaScript…

    node js 2023年6月7日
    00
合作推广
合作推广
分享本页
返回顶部