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

这篇具有很好参考价值的文章主要介绍了【数据结构】使用循环链表结构实现约瑟夫环问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【数据结构】使用循环链表结构实现约瑟夫环问题,数据结构与算法,数据结构,c++,c语言,笔记,青少年编程,学习,改行学it

目录

1.循环链表的定义

2.约瑟夫环问题

3.创建循环链表

4.删除节点操作

5.打印所有节点

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


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

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

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

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

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

【数据结构】使用循环链表结构实现约瑟夫环问题,数据结构与算法,数据结构,c++,c语言,笔记,青少年编程,学习,改行学it

【数据结构】使用循环链表结构实现约瑟夫环问题,数据结构与算法,数据结构,c++,c语言,笔记,青少年编程,学习,改行学it

1.循环链表的定义

循环链表与常规链表的区别在于,其尾节点指向头节点,形成一个环形结构。循环链表可以分为单向循环链表和双向循环链表两种类型。

单向循环链表的定义为:每个节点包含一个数据元素和指向下一个节点的指针,而最后一个节点的指针会指向第一个节点,形成一个环形结构。

双向循环链表的定义为:每个节点包含一个数据元素以及两个指针,一个指向前一个节点,一个指向后一个节点,而第一个节点的前驱指针指向最后一个节点,最后一个节点的后继指针指向第一个节点,也形成了一个环形结构。

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

2.约瑟夫环问题

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

解决约瑟夫环问题的步骤(设定问题的输入为n个人和要出局的报数m):

1. 将n个人编号为1到n。
2. 从第一个人开始报数,报到m的人出局。
3. 从出局的人的下一个人开始重新报数,继续报到m的人出局。
4. 重复第3步,直到只剩下一个人为止。

3.创建单向循环链表

typedef struct node {
    int number;
    struct node* next;
} person;

// 初始化一个循环链表,表示圆桌上的人
person* initlink(int n) {
    person* head = (person*)malloc(sizeof(person));
    head->number = 1;
    head->next = NULL;
    person* cyclic = head;
    
    // 创建 n-1 个节点,并连接成循环链表
    for (int i = 2; i <= n; i++) {
        person* body = (person*)malloc(sizeof(person));
        body->number = i;
        body->next = NULL;
        cyclic->next = body;
        cyclic = cyclic->next; 
    }
    
    cyclic->next = head;
    return head;
}

定义一个名为person的结构体,由整型变量number和指向下一节点的指针next构成。

函数initlink用于初始化一个循环链表,表示圆桌上的人。函数首先创建一个头节点,然后使用for循环创建其他的节点并连接成循环链表。最后返回头节点。

这段代码用于创建一个循环链表,其中头节点的number字段表示第一个人在圆桌上的位置,后续节点的number字段按顺序递增,最后一个节点的next字段指向头节点形成一个循环链表结构。

4.约瑟夫环求解过程

// 找到第 k 个人并开始报数,数到第 m 个人出列
void findandkillk(person* head, int k, int m) {
    person* tail = head;
    while (tail->next != head) {
        tail = tail->next;
    }
    
    person* p = head;
    while (p->number != k) {
        tail = p;
        p = p->next;
    }
    
    // 从第 k 个人开始报数,直到只剩下一个人
    while (p->next != p) {
        for (int i = 1; i < m; i++) {
            tail = p;
            p = p->next;
        }
        
        // 删除第 m 个人出列,并释放内存
        tail->next = p->next;
        printf("出列人的编号为: %d\n", p->number);
        
        person* temp = p;
        p = p->next;
        free(temp);
    }
    
    printf("出列人的编号为: %d\n", p->number);
    free(p);
}

从第k个人开始报数,每次报到第m个人就将其出列。

先用循环找到链表中的尾节点,即满足tail->next = head的节点。

再用循环找到链表中编号为k的节点,并在找到之前更新尾节点的位置。

再用循环进行报数和出列操作,直到链表中只剩下最后一个人。循环中的内层循环每次进行m-1次迭代,找到第m个人之前的节点并更新尾节点的位置。随后,删除第m个人,并释放其内存。外层循环在每次迭代之后更新当前节点的位置,并继续进行报数和出列操作。

最后,输出剩下的最后一个人的编号,并释放其内存。

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

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

typedef struct node {
    int number;
    struct node* next;
} person;

// 初始化一个循环链表,表示圆桌上的人
person* initlink(int n) {
    person* head = (person*)malloc(sizeof(person));
    head->number = 1;
    head->next = NULL;
    person* cyclic = head;
    
    // 创建 n-1 个节点,并连接成循环链表
    for (int i = 2; i <= n; i++) {
        person* body = (person*)malloc(sizeof(person));
        body->number = i;
        body->next = NULL;
        cyclic->next = body;
        cyclic = cyclic->next; 
    }
    
    cyclic->next = head;
    return head;
}

// 找到第 k 个人并开始报数,数到第 m 个人出列
void findandkillk(person* head, int k, int m) {
    person* tail = head;
    while (tail->next != head) {
        tail = tail->next;
    }
    
    person* p = head;
    while (p->number != k) {
        tail = p;
        p = p->next;
    }
    
    // 从第 k 个人开始报数,直到只剩下一个人
    while (p->next != p) {
        for (int i = 1; i < m; i++) {
            tail = p;
            p = p->next;
        }
        
        // 删除第 m 个人出列,并释放内存
        tail->next = p->next;
        printf("出列人的编号为: %d\n", p->number);
        
        person* temp = p;
        p = p->next;
        free(temp);
    }
    
    printf("出列人的编号为: %d\n", p->number);
    free(p);
}

int main() {
    printf("输入圆桌上的人数 n: ");
    int n;
    scanf("%d", &n);
    person* head = initlink(n);
    
    printf("从第 k 人开始报数 (k > 1 且 k < %d): ", n);
    int k;
    scanf("%d", &k);
    
    printf("数到第 m 个人出列:");
    int m;
    scanf("%d", &m);
    
    findandkillk(head, k, m);
    
    return 0; 
}

代码中的主要函数有initlink和findandkillk。

initlink函数根据输入的人数 n,初始化一个循环链表。循环链表中的每个节点都存储一个人的编号,编号从 1 到 n。该函数返回链表的头节点指针。

findandkillk函数用于解决约瑟夫环问题。它接收初始化好的循环链表的头节点指针,起始编号 k 和报数间隔 m 作为参数。首先,它找到从第 k 个人开始报数的位置,并且记录该位置的上一个节点,即tail。接着,通过迭代法,每次报数到第 m 个人时,将其从链表中删除,并释放相应的内存空间。直到链表中只剩一个节点时,停止迭代,并输出最后剩下的那个人的编号。

在main函数中,用户输入要解决的约瑟夫环问题的相关参数,然后调用findandkillk函数进行求解。

程序截图如下:

【数据结构】使用循环链表结构实现约瑟夫环问题,数据结构与算法,数据结构,c++,c语言,笔记,青少年编程,学习,改行学it文章来源地址https://www.toymoban.com/news/detail-800700.html

到了这里,关于【数据结构】使用循环链表结构实现约瑟夫环问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构与算法——约瑟夫环

    目录 一、例题引入         # 解题思路         #图例分析         #代码段         #题解小结  二、循环链表         分析:         直接看代码:  三、标记数组         分析:         代码: 四、递归算法          #沿用解释         设有n个人坐在圆桌周围,

    2024年02月08日
    浏览(31)
  • 重温数据结构与算法之约瑟夫问题

    约瑟夫问题 ,是一个计算机科学和数学中的问题,在计算机编程的算法中,类似问题又称为 约瑟夫环 ,又称“丢手绢问题”。 据说著名犹太历史学家 Josephus 有过以下的故事: 在罗马人占领乔塔帕特后,39个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也

    2024年02月08日
    浏览(31)
  • 【数据结构与算法】【约瑟夫问题】还在用递归?教你用链表秒杀约瑟夫

     🎉🎉欢迎光临🎉🎉 🏅我是苏泽,一位对技术充满热情的探索者和分享者。🚀🚀 🌟特别推荐给大家我的最新专栏 《数据结构与算法:初学者入门指南》📘📘 本专栏纯属为爱发电永久免费!!! 这是苏泽的个人主页可以看到我其他的内容哦👇👇 努力的苏泽 http://su

    2024年02月19日
    浏览(30)
  • 数据结构—约瑟夫环问题(C语言版)

    目录 首先什么是约瑟夫环 约瑟夫环实现方式 一、创建结构体变量 二、初始化链表 三、构建循环链表 四、删除链表  五、完整代码及注释讲解 约瑟夫环 是 循环链表 中的一个经典问题;题目描述:n 个人围成一圈,从第一个人开始报数,数到 m 的人出列,再由下一个人重新

    2024年02月11日
    浏览(31)
  • 【数据结构与算法】约瑟夫环(C/C++)

    约瑟夫问题的一种描述是:编号为1,2,…,n的n个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。一开始任选一个正整数作为报数上限值m,从第一个人开始。按顺时针方向自1开始顺序报数,报到m时停止报数。报m的人出列,将他的密码作为新的m值,从他在顺时针方向上

    2024年02月12日
    浏览(22)
  • C语言数据结构-用链表解决约瑟夫环问题

    只是普通的大学生一枚,不会很牛的技巧和算法,只是在做数据结构作业中的一点感悟和思考。也不知道自己写得对不对,有什么意见和建议都可以直接指出来哦,我虚心接受(低头鞠躬.jpg)...... 试用线性表的链表存储结构来实现约瑟夫(Josephu)问题。约瑟夫问题如下:设有

    2024年02月06日
    浏览(34)
  • 约瑟夫死者游戏-C语言实现-双向循环链表

    设计题目 1 : 约瑟夫生者死者游戏 [问题描述]: 约瑟夫生者死者游戏的大意是: 30 个旅客同乘一条船,因为严重超载,加上风高浪大, 危险万分;因此船长告诉乘客,只有将全船一半的旅客投入海中,其余人才能幸免遇难。无 奈,大家只得同意这种办法,并议定 30 个人围

    2024年02月03日
    浏览(29)
  • 数据结构实验---顺序表的合并---链表的基本操作---重点解析约瑟夫问题

    实验的写法多种多样,但本文并未采用 #define 定义容量的写法,这样写已经是很老旧过时的写法。所有实验主体采用均为动态开辟,后续如果利用 C++ 来写或许会应用更多语法… 本篇展示数据结构的两个实验 其中,重点分析约瑟夫问题 实验中代码的命名风格等均与下方博客

    2024年02月16日
    浏览(49)
  • C语言---数据结构实验---顺序表的合并---链表的基本操作---重点解析约瑟夫问题

    实验的写法多种多样,但本文并未采用 #define 定义容量的写法,这样写已经是很老旧过时的写法。所有实验主体采用均为动态开辟,后续如果利用 C++ 来写或许会应用更多语法… 本篇展示数据结构的两个实验 其中,重点分析约瑟夫问题 实验中代码的命名风格等均与下方博客

    2024年02月16日
    浏览(35)
  • 循环链表解决约瑟夫环问题

    n 个人围成一圈,从第一个人开始报数,数到 m 的人出列,再由下一个人重新从 1开始报数,数到 m 的人再出圈,依次类推,直到所有的人都出圈,请输出依次出圈人的编号。 n个人围成一圈,很容易可以想到用循环链表解决问题,用结点代表每个人,节点的数据域存储人的编号

    2024年02月07日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包