【数据结构】使用循环链表结构实现约瑟夫环问题

news2024/12/26 20:47:07

目录

1.循环链表的定义

2.约瑟夫环问题

3.创建循环链表

4.删除节点操作

5.打印所有节点

6.实现约瑟夫环问题的完整程序代码


🌈嗨!我是Filotimo__🌈。很高兴与大家相识,希望我的博客能对你有所帮助。

💡本文由Filotimo__✍️原创,首发于CSDN📚。

📣如需转载,请事先与我联系以获得授权⚠️。

🎁欢迎大家给我点赞👍、收藏⭐️,并在留言区📝与我互动,这些都是我前进的动力!

🌟我的格言:森林草木都有自己认为对的角度🌟。

1.循环链表的定义

循环链表是一种特殊的单链表,它的特点是链表中的最后一个节点指向链表的头节点,形成一个闭环。

这种结构使得循环链表可以从任意节点开始遍历,并且可以方便地在链表中插入或删除节点。它可以通过不断重复遍历整个链表来实现循环的效果。

2.约瑟夫环问题

约瑟夫环问题是一个经典的数学问题,假设 n 个人站成一个环状,从第一个人开始报数,每次报到 m 的人出列,再从下一个人开始重新报数,直到所有人都出列。最后剩下的人的编号即为最后的获胜者。

3.创建循环链表

// 定义循环链表的节点
typedef struct Node {
    int data;               // 节点数据
    struct Node* next;      // 指向下一个节点的指针
} Node;

// 创建循环链表
Node* createCircularLinkedList(int n) {
    Node* head = NULL;
    Node* temp = NULL;

    // 创建链表节点
    for (int i = 1; i <= n; i++) {
        Node* newNode = (Node*)malloc(sizeof(Node));
        newNode->data = i;

        if (head == NULL) {
            head = newNode;
        } else {
            temp->next = newNode;
        }

        temp = newNode;
    }

    // 将最后一个节点指向头节点,形成循环
    temp->next = head;

    return head;
}

在函数createCircularLinkedList中,整数n作为参数,表示链表中节点的数量。它定义了两个指针变量head和temp,分别用于指向链表的头节点和临时节点。

该函数使用for循环创建链表的节点。对于每个节点,首先使用malloc函数动态分配内存空间,将返回的指针强制转换为 Node*类型,并将其赋值给newNode->data。然后,根据链表是否为空,将newNode插入链表中。如果链表为空,将head指向newNode;否则,将 newNode添加为temp的下一个节点。

完成节点的创建后,将最后一个节点的next指针指向头节点,形成循环。最后,返回头节点head。

4.删除节点操作

// 在循环链表中删除指定位置的节点
Node* deleteNode(Node* head, int k) {
    // 链表为空,直接返回
    if (head == NULL) {
        return NULL;
    }

    Node* current = head;
    Node* prev = NULL;

    // 遍历链表,直到找到要删除的节点
    int count = 1;
    while (count != k) {
        prev = current;
        current = current->next;
        count++;
    }

    // 删除节点并更新指针
    if (prev != NULL) {
        prev->next = current->next;
    } else {
        head = current->next;   // 删除头节点时更新头指针
    }
    free(current);

    return head;
}

函数deleteNode接受一个循环链表的头节点head和要删除的节点位置k作为参数。

它定义两个指针变量current和prev,并初始化current为head,prev为NULL。

我们使用while循环遍历链表,直到找到要删除的位置k。在循环中,将current赋值给prev,将current->next赋值给current,并将count递增。这样,当循环结束时,current就指向了要删除的节点,prev则指向了要删除节点的前一个节点。

在找到要删除的节点后,通过判断prev是否为NULL来确定要删除的是否是头节点。如果prev不为NULL,则设置prev->next为current->next,这样就将current节点从链表中删除。如果prev为NULL,则说明要删除的是头节点,需要将head指向current->next来更新头指针。

最后,使用free函数释放被删除节点current的内存,并返回更新后的头节点head。

5.打印所有节点

// 打印循环链表中的所有节点
void printCircularList(Node* head) {
    if (head == NULL) {
        return;
    }

    Node* current = head;

    do {
        printf("%d ", current->data);
        current = current->next;
    } while (current != head);

    printf("\n");
}

该函数定义指针变量current并初始化为head,同时使用do-while循环遍历循环链表。在循环中,打印current节点的数据域data,并将current->next赋值给current,这样就能够依次输出链表中的所有节点值。

在循环结束后,通过输出换行符\n,打印完整的链表内容。

6.实现约瑟夫环问题的完整程序代码

#include <stdio.h>
#include <stdlib.h>

// 定义循环链表的节点
typedef struct Node {
    int data;               // 节点数据
    struct Node* next;      // 指向下一个节点的指针
} Node;

// 创建循环链表
Node* createCircularLinkedList(int n) {
    Node* head = NULL;
    Node* temp = NULL;

    // 创建链表节点
    for (int i = 1; i <= n; i++) {
        Node* newNode = (Node*)malloc(sizeof(Node));
        newNode->data = i;

        if (head == NULL) {
            head = newNode;
        } else {
            temp->next = newNode;
        }

        temp = newNode;
    }

    // 将最后一个节点指向头节点,形成循环
    temp->next = head;

    return head;
}

// 在循环链表中删除指定位置的节点
Node* deleteNode(Node* head, int k) {
    // 链表为空,直接返回
    if (head == NULL) {
        return NULL;
    }

    Node* current = head;
    Node* prev = NULL;

    // 遍历链表,直到找到要删除的节点
    int count = 1;
    while (count != k) {
        prev = current;
        current = current->next;
        count++;
    }

    // 删除节点并更新指针
    if (prev != NULL) {
        prev->next = current->next;
    } else {
        head = current->next;   // 删除头节点时更新头指针
    }
    free(current);

    return head;
}

// 打印循环链表中的所有节点
void printCircularList(Node* head) {
    if (head == NULL) {
        return;
    }

    Node* current = head;

    do {
        printf("%d ", current->data);
        current = current->next;
    } while (current != head);

    printf("\n");
}

int main() {
    int n, k;
    printf("请输入总人数:");
    scanf("%d", &n);
    printf("请输入报数的间隔:");
    scanf("%d", &k);

    // 创建循环链表
    Node* head = createCircularLinkedList(n);
    printf("初始序列:");
    printCircularList(head);

    // 模拟约瑟夫环问题
    while (head->next != head) {
        head = deleteNode(head, k);
        printf("淘汰第 %d 号\n", k);
        printCircularList(head);
    }

    printf("胜出者是:%d\n", head->data);

    return 0;
}

createCircularLinkedList 函数用于创建循环链表,deleteNode 函数用于删除指定位置的节点,printCircularList 函数用于打印循环链表中的所有节点。在 main 函数中,首先获取用户输入的总人数和报数的间隔,然后创建循环链表并打印初始序列。然后通过循环调用 deleteNode 函数和 printCircularList 函数模拟约瑟夫环问题的过程,直到只剩下一个节点,即胜出者。最后,输出胜出者的编号。

程序运行结果如下:

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于Java SSM框架实现智能停车场系统项目【项目源码+论文说明】

基于java的SSM框架实现智能停车场系统演示 摘要 本论文主要论述了如何使用JAVA语言开发一个智能停车场管理系统&#xff0c;本系统将严格按照软件开发流程进行各个阶段的工作&#xff0c;采用B/S架构&#xff0c;面向对象编程思想进行项目开发。在引言中&#xff0c;作者将论述…

MySQL数据库的基础概念

目录 顾名思义&#xff0c;数据库是用于存储数据的&#xff0c;那这些数据被存储在哪呢&#xff1f; 文件也能存储数据&#xff0c;那在这个基础上&#xff0c;为什么还要搞出一个数据库来存储数据呢&#xff1f; MySQL的客户端登录/退出指令、服务端的启动/关闭指令 数据…

oracle怎么导入dmp文件??????

目录 oracle怎么导入dmp文件&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f; 先看&#xff1a; 方法一&#xff1a;【推荐】 winR输入 输入&#xff1a; 检验&#xff1a; 导入成功&#xff01; 方法二&#xff1a; 直接在 PLSQL Developer…

技术探秘:在RISC Zero中验证FHE——由隐藏到证明:FHE验证的ZK路径(1)

1. 引言 开源代码实现见&#xff1a; https://github.com/hashcloak/fhe_risc0_zkvm&#xff08;Rust&#xff09;https://github.com/weikengchen/vfhe-profiled&#xff08;Rust&#xff09;https://github.com/l2iterative/vfhe0&#xff08;Rust&#xff09; L2IV Resea…

一问掌握SpringBoot常见注解,后无压力。

文章目录 一、&#x1f50e; SpringBoot常用注解大全&#x1f341;&#x1f341; 01. RequestMapping 注解&#x1f341; 1.1. RequestMapping 是什么&#xff1f;&#x1f341; 1.2. RequestMapping 特点有哪些&#xff1f;&#x1f341; 1.3. RequestMapping 作用是什么&…

SpringBoot中处理处理国际化

SpringBoot中处理处理国际化 1. 创建SpringBoot项目2. resource下创建i18n目录3. 右键i18n新建资源包4. 弹框中添加需要支持的国际化语言5. messages.properties中添加需要国际化的键6. application.yaml添加配置7. 国际化工具8. 使用功能9 场景问题 1. 创建SpringBoot项目 2.…

智能配电房在线监测系统

智能配电房在线监测系统是一个综合性的系统&#xff0c;依托电力智慧运维工具-电易云&#xff0c;主要用于监控和调整配电房的环境、安防和电气设备状态。以下是该系统的一些主要功能和特点&#xff1a; 环境监控&#xff1a;实时监测配电房内的温度、湿度、SF6气体浓度、臭氧浓…

论文阅读笔记(12月15)--DialogXL

论文阅读笔记(12月15)–DialogXL 基本情况介绍&#xff1a; 作者&#xff1a;Weizhou Shen等 单位&#xff1a;中山大学 时间&期刊&#xff1a;AAAI 2021 主题&#xff1a;对话情绪识别(ERC)–文本模态 论文链接&#xff1a;https://ojs.aaai.org/index.php/AAAI/article…

如何在Go中并发运行多个函数

引言 Go语言的一个流行特性是它对并发的一流支持,即一个程序可以同时做多件事。随着计算机从更快地运行单个代码流转向同时运行更多代码流,能够并发地运行代码正在成为编程的重要组成部分。为了让程序运行得更快,程序员需要把程序设计成并发运行,这样程序中并发的每一部分…

HQL优化之数据倾斜

group by导致倾斜 前文提到过&#xff0c;Hive中未经优化的分组聚合&#xff0c;是通过一个MapReduce Job实现的。Map端负责读取数据&#xff0c;并按照分组字段分区&#xff0c;通过Shuffle&#xff0c;将数据发往Reduce端&#xff0c;各组数据在Reduce端完成最终的聚合运算。…

SpringCloud-高级篇(八)

&#xff08;1&#xff09;TCC模式 前面学了XA和AT模式&#xff0c;这两种模式最终都能实现一致性&#xff0c;和隔离性&#xff0c;XA是强一致&#xff0c;AT是最终一致&#xff0c;隔离性呢XA是在第一阶段不提交&#xff0c;基于事务本身的特性来完成隔离&#xff0c;AT则是…

MongoDB表的主键可以重复?!MongoDB的坑

MongoDB表的主键可以重复&#xff1f;&#xff01; 眼见为实&#xff1f; 碰到一个奇怪的现象&#xff0c; MongoDB的一个表居然有两个一样的_id值&#xff01; 再次提交时&#xff0c;是会报主键冲突的。那上图&#xff0c;为什么会有两个一样的_id呢&#xff1f; 将它们的…

【halcon深度学习】目标检测的数据准备过程中的一个库函数determine_dl_model_detection_param

determine_dl_model_detection_param “determine_dl_model_detection_param” 直译为 “确定深度学习模型检测参数”。 这个过程会自动针对给定数据集估算模型的某些高级参数&#xff0c;强烈建议使用这一过程来优化训练和推断性能。 过程签名 determine_dl_model_detection…

10 新字符设备驱动文件

一、新字符设备驱动原理 因为 register_chrdev 和 unregister_chrdev 两个函数是老版本驱动文件&#xff0c;现在可以用新字符设备驱动 API 函数。 1. 分配和和释放设备号 使用 register_chrdev 函数注册字符设备的时候只需要给定一个主设备号即可&#xff0c;但是这样会带来两…

【面试】广告优化

a1&#xff1a;点击率公式是什么&#xff1f;点击率低的原因是什么&#xff1f; 点击率点击/曝光&#xff0c;点击率低的原因主要有两点&#xff1a;一是创意不吸引人&#xff1b;二是目标受众不准确/定向过宽不精确&#xff0c;广告曝光给了对产品不感兴趣用户 a2&#xff1a;…

数据库——关系数据的规范化:范式判断【知识点罗列+例题讲解】

知识点罗列&#xff1a; 各种范式之间的关系 1.第一范式1NF&#xff1a; 如果关系模式R中所有的属性都具有原子性&#xff0c;均是不可再分的&#xff08;一个属性不能再被分解成更小的数据单元&#xff09;&#xff0c;则称R属于第一范式&#xff0c;简称1NF&#xff0c;记作R…

linux常见错误

1.E45: ‘readonly‘ option is set (add ! to override) 首先使用以下命令从Vim编辑器中出来&#xff1a;:qa!(强制退出) 接下来&#xff0c;使用sudo vim filename和更高版本&#xff1a;:wq 2.Bash script – "/bin/bash^M: bad interpreter: No such file or direc…

yolov5单目测距+速度测量+目标跟踪

要在YOLOv5中添加测距和测速功能&#xff0c;您需要了解以下两个部分的原理&#xff1a; 单目测距算法 单目测距是使用单个摄像头来估计场景中物体的距离。常见的单目测距算法包括基于视差的方法&#xff08;如立体匹配&#xff09;和基于深度学习的方法&#xff08;如神经网…

安捷伦N9020A 是德keysight/N9020A

N9020A信号分析仪自动化和通讯接口&#xff1a; 符合 LXI、SCPI 和 IVI-COM USB 3.0、1000Base-T LAN、GPIB 编程与 PSA、8566/68 和 856x 的远程语言兼容性 通用 X 系列用户界面 / 开放式 Windows 7 操作系统&#xff08;标准&#xff09; 将现有的 MXA 从 Windows XP 迁移到…

CAN 五: CAN编程实践

1、CAN基本驱动步骤 (1)CAN参数初始化 工作模式、波特率等函数&#xff1a;HAL_CAN_Init (2)使能CAN时钟和初始化相关引脚 GPIO模式设为复用功能模式函数&#xff1a;HAL_CAN_MspInit(CAN的初始化回调函数) (3)设置过滤器 过滤器的配置函数&#xff1a;HAL_CAN_ConfigFil…