约瑟夫生者死者游戏问题

news/2024/11/8 12:22:20/文章来源:https://www.cnblogs.com/yuxiyuxi/p/18534827

C++使用单向循环链表解决
需要实现节点的插入和删除
——我为++做实事


1 、节点定义:

struct node
{
    int number; // 表示序号
    node *next;
};

2 、节点的插入:

为每个节点(人)发放生死序号:index
考虑链表为空和不为空的情况

void insert_Node(node *&head, int index)
{
    node *newNode = new node;
    // 如果链表为空
    if (head == nullptr)
    {
        newNode->number = index;
        newNode->next = newNode; // next指针指向自己
        head = newNode;          // 把自己设为头节点
    }
    else
    {
        newNode->number = index;
        newNode->next = head; // next指针指向头节点
        node *N = find_tail(head);
        N->next = newNode; // 尾节点的next指向自己
    }
}

3 、删除节点的操作:

当我们删除链表中的节点时,一般只需要修改附近节点的 next 指针即可,不过此题使用了 new 来分配空间,所以还需要 delete 掉节点,防止内存泄漏。如果用数组模拟链表就不用考虑真的“删除”节点这个问题。

3 .1 有以下几种情况:
如果是头节点是否有且只有头节点除了头节点还有其他节点
如果不是头节点
3.2 需要注意释放内存

delete node
代码:

void del_Node(node *&head, node *victim)
{
    if (victim == head) 			// 如果删除的是头节点
    {
        node *tail = find_tail(head);
        if (head == tail) 			// 链表只有一个节点
        {
            delete head;    		// 释放内存
            head = nullptr; 		// 设置为空
        }
        else						// 除了头节点还有其他节点
        {
            head = head->next; 		// 修改头节点
            tail->next = head; 		// 尾节点指向新的头节点
            delete victim;     		// 释放内存
        }
    }
    else							// 删的不是头节点
    {
        node *before_victim = head;
        while (before_victim->next != victim)
            before_victim = before_victim->next;
            
        before_victim->next = victim->next; // 删除 victim,修改前面节点的next指针
        delete victim;                      // 释放内存
    }
}

4. Main 函数

一定要初始化头节点为空,作为链表的一个标志
代码逻辑:
为 30 个人发号码牌
循环 15 次,每次丢出去一个人(好残忍)
每次从当前的人这里,往前走 8 步,找到 victim
删除 victim
指针移动到这个 victim 下一位,下次循环就从这人开始,继续走 8 步……
代码:

int main()
{
    node *head = nullptr;			// 一定要初始化头节点为空
    for (int i = 1; i <= 30; i++)
        insert_Node(head, i);    int all_people = 30, half_people = all_people / 2;
    node *victim = head;
    while (half_people--)
    {
        for (int i = 0; i < 8; i++)
            victim = victim->next;        cout << victim->number << " ";
        node *next_vic = victim->next;
        del_Node(head, victim);
        victim = next_vic;        cout << endl;
        // print(head);
    }
    return 0;
}

最后是些无关紧要的辅助函数

1、find_tail 函数

// 返回链表最后一个节点的指针
node *find_tail(node *head)
{
    node *N = head;
    while (N->next != head) // find尾节点
    {
        N = N->next;
    }
    return N;
}

2、打印链表函数(debug 用可删)

// 打印当前剩下的所有人
void print(node *head)
{
    node *c = head;
    if (c == nullptr)
        return; // 空链表处理
    do
    {
        cout << c->number << " ";
        c = c->next;
    } while (c != head); // 打印直到头节点
    cout << endl;
}

小韩碎碎念 —有些 bug 值得注意:

1、对于链表的修改,包括插入和删除,传进函数一定要用 &,引用传递,否则只会在函数内部修改,不会对原始链表有任何影响。

2、关于 while 和 do-while 的一个 bug:
源代码:

void print(node * head)
{
    node *c = head;
    while(c->next != head)
    cout << c->number << " ";
}

问题:
print 函数的逻辑问题print 函数缺少打印链表最后一个节点的代码,因为它只循环到 c->next != head,而没有打印尾节点。因此,你会错过打印最后一个节点
改成 do-while 循环后的代码:

void print(node * head) 
{ node *c = head; if (c == nullptr) return; // 空链表处理 do { cout << c->number << " "; c = c->next; } while (c != head); // 打印直到头节点 cout << endl; 
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/828773.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

精选 Top10 开源调度工具,解锁高效工作负裁自动化

在大数据和现代 IT 环境中,任务调度与工作负载自动化(WLA)工具是优化资源利用、提升生产效率的核心驱动力。随着企业对数据分析、实时处理和多地域任务调度需求的增加,这些工具成为关键技术。本文将介绍当前技术发展背景下的Top 10开源任务调度工具,并探讨它们在大数据和工…

五分钟入门双拼!

从零开始学双拼的第一篇:概述‍这是从零开始学双拼的第一篇:概述 双拼的原理 如果你使用全拼,想要完整敲出一个字的读音,需要敲出这个字拼音的每个字母。 虽然简拼能简化一点步骤,但除非是很常见的成语、俗语,否则重码率很高,选词很困难。 有没办法提高效率呢?有的,那…

SVN提交日志模板设置

前言:每次提交时都要手动输入很多固定日志信息,或者在最近中选择信息记录会比较麻烦,通过这个设置可以在每次提交时,自动填充日志信息 设置步骤 1:先进入你想要提交svn自动设置模板时的目录(例如策划同学进入到Table表格提交记录,程序同学进入到代码提交目录,美术同学进…

ubuntu:旧版本配置apt源(ubuntu 21.10)

一,旧版本ubuntu上的apt源不能用了 # apt-get update 忽略:1 http://mirrors.aliyun.com/ubuntu hirsute InRelease 忽略:2 http://mirrors.aliyun.com/ubuntu hirsute-security InRelease 忽略:3 http://mirrors.aliyun.com/ubuntu hirsute-updates InRelease 忽略:4 http://…

医药企业数据治理,从何入手?一文讲清楚!

在医药行业,随着企业信息化进程的加速推进,ERP、CRM等系统纷纷引入业务流程。这些系统的不断增加,虽提升了业务管理的精细度,但也带来了数据的分散与冗余问题,数据治理因此成为企业面临的关键挑战。那么,医药企业的数据治理该如何入手?本文将为您逐一解析。 1. 数据标准…

【SpringBoot开发】 文件上传 (秒传、断点续传、分片上传)

原创 Java技术前沿引言 文件上传在软件开发项目中极为常见,涵盖了图片、音频、视频及各类文档的上传需求。对于小型文件,简单的Form表单上传机制通常足以应对。然而,当面对体积庞大的文件,如超过1GB的文件,或用户处于网络条件不佳的环境下时,传统的上传方式便显得力不从心…

数据采集与融合第三次作业

码云仓库地址 https://gitee.com/sun-jiahui22/crawl_project作业1仓库地址 https://gitee.com/sun-jiahui22/crawl_project/tree/master/作业3/实验3.1作业2的仓库地址 https://gitee.com/sun-jiahui22/crawl_project/tree/master/作业3/实验3.2作业3的仓库地址 https://gitee…

【java编程】深入浅出JVM(四):类文件结构

原创 菜菜的后端私房菜Java文件编译成字节码文件后,通过类加载机制到Java虚拟机中,Java虚拟机能够执行所有符合要求的字节码,因此无论什么语言,只要能够编译成符合要求的字节码文件就能够被Java虚拟机执行. Java虚拟机和字节码是语言、平台无关性的基石. 本篇文章将深入浅出…

HyperWorks实体网格划分

实体网格剖分 在 HyperMesh 中,使用 Solid Map 功能进行实体网格剖分。该面板如下图所示:图 4-4 Solid Map 面板 通过 Solid Map Panel 进行实体网格剖分: • 通过主菜单栏选择 3D 页面 > solid map 。 • 通过下拉式菜单选择 Mesh > create > Solid Map。 Solid Ma…

VS 2022 不支持 .NET Framework 4.5 项目解决办法(Visual Studio 2022)

VS 2022 不支持 .NET Framework 4.5 项目解决办法(Visual Studio 2022) 概述 最近 C# 开发工具 Visual Studio 升级到了 2022,打开速度快了很多,开发体验也舒服很多。只是使用过程中遇到了一个比较尴尬的问题:默认Visual Studio 2022 不再支持安装 .NET Framework 4.5 组件…

新建流程隐藏指定流程(建模+api+ecode)

ecode代码 `// 功能总开关 let enable = true; let list=[]; $.ajax({ type:GET, url:/api/xiangxin/Multiple/HideProcess, success:function(res){ res.data.map((i)=>{ // console.log(lc :, i.lc); list.push(i.lc); }) } }) let pd; //判断是否是新建流程页面 ecodeSDK…

分布式事物传递 NetMQ测试

using NetMQ; using NetMQ.Sockets; using System; using System.Threading; namespace 消息传递库_NetMQ服务端 {internal class Program{public static void Main(){using (var publisher = new PublisherSocket()){// 绑定到一个端口,等待订阅者连接publisher.Bind("t…