鱼C论坛

 找回密码
 立即注册
查看: 32|回复: 1

[学习笔记] 学习循环链表,约瑟夫问题

[复制链接]
发表于 昨天 22:52 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
循环链表——约瑟夫问题

  1. #include <iostream>
  2. using namespace std;

  3. typedef int ElemType;

  4. typedef struct Node {
  5.     ElemType data;
  6.     struct Node *next;
  7. } LinkNode, *LinkList;

  8. // 初始化循环链表
  9. bool InitList(LinkList &L) {
  10.     L = new LinkNode;
  11.     if (!L) {
  12.         return false;
  13.     }
  14.     L->next = L;
  15.     L->data = -1;
  16.     return true;
  17. }

  18. // 尾插法
  19. bool insert_tail(LinkList &L, ElemType e) {
  20.     if (!L) {
  21.         return false;
  22.     }
  23.     LinkNode *p = L;
  24.     while (p->next != L) {
  25.         p = p->next;
  26.     }
  27.     LinkNode *s = new LinkNode;
  28.     if (!s) {
  29.         return false;
  30.     }
  31.     s->data = e;
  32.     s->next = p->next;
  33.     p->next = s;
  34.     return true;
  35. }

  36. void printList(const LinkList &L) {
  37.     if (!L) {
  38.         return;
  39.     }
  40.     LinkNode *p = L->next;
  41.     while (p != L) {
  42.         cout << p->data << " ";
  43.         p = p->next;
  44.     }
  45.     cout << endl;
  46. }

  47. bool Joseph(LinkList &L, int interval) {
  48.     if (!L || L->next == L) {
  49.         cout << "循环链表为空" << endl;
  50.         return false;
  51.     }
  52.     if (interval <= 0) {
  53.         cout << "间隔数必须大于0" << endl;
  54.         return false;
  55.     }
  56.     LinkNode *p = L->next, *pre=L; // p指向要删除的结点,pre指向要删除结点的前一个结点
  57.     int times = 0;
  58.     while (L->next != L) {
  59.         // 找到要删除的结点的前一个结点和要删除的结点
  60.         // 从1 开始计数,删除计数到interval 的结点,不包括头结点
  61.         for (int i = 1; i < interval; i++) {
  62.             pre = p;
  63.             p = p->next;
  64.             if (p == L) { // 跳过头结点计数
  65.                 pre = p;
  66.                 p = L->next;
  67.             }
  68.         }
  69.         pre->next = p->next;
  70.         LinkNode *temp = p;  // 用temp 保存要删除的结点,删除
  71.         p = p->next;
  72.         times++;
  73.         cout << "第" << times << "次删除的元素为" << temp->data << endl;
  74.         delete temp;
  75.         if (p == L){  //防止计数错误,当p指向头结点时,重新指向头结点的下一个结点
  76.             pre = p;
  77.             p = L->next;
  78.         }
  79.         printList(L);
  80.     }
  81.     return true;
  82. }

  83. int main() {
  84.     LinkList L;
  85.     // 1.初始化一个空的循环链表
  86.     if (!InitList(L)) {
  87.         exit(-1);
  88.     } else {
  89.         cout << "初始化成功" << endl;
  90.     }
  91.     // // 2.尾插法插入元素
  92.     // cout << "请输入要插入的元素,ctrl d结束" << endl;
  93.     // ElemType e;
  94.     // while (cin >> e) {
  95.     //     insert_tail(L, e);
  96.     // }
  97.     // cin.clear();
  98.     for (int i = 1; i <= 10; i++) {
  99.         insert_tail(L, i);
  100.     }
  101.     cout << endl;

  102.     // // 3.打印循环链表
  103.     // printList(L);

  104.     // 约瑟夫环
  105.     Joseph(L, 9);

  106.     return 0;
  107. }
复制代码

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 昨天 22:54 | 显示全部楼层
循环链表是一种特殊的链表,其中最后一个节点的指针指向头节点,从而形成一个环状结构。约瑟夫问题是一个经典的数学应用问题:有 n 个人围成一圈,从第 k 个人开始报数,数到 m 的人出列,然后从下一个人继续报数,直到所有人出列。循环链表非常适合模拟这个过程。

在您提供的代码中,定义了一个循环链表结构,并实现了初始化、尾插法和打印功能。但约瑟夫问题的函数不完整。下面我将解释关键部分,并提供一个完整的约瑟夫问题实现。

首先,循环链表的基本操作:
- InitList:初始化链表,创建一个头节点并使其指向自身。
- insert_tail:使用尾插法在链表末尾添加新节点。
- printList:遍历并打印链表中的数据(跳过头节点)。

约瑟夫问题函数需要模拟报数出列的过程。以下是完整的实现:


  1. #include <iostream>
  2. using namespace std;

  3. typedef int ElemType;

  4. typedef struct Node {
  5.     ElemType data;
  6.     struct Node *next;
  7. } LinkNode, *LinkList;

  8. // 初始化循环链表
  9. bool InitList(LinkList &L) {
  10.     L = new LinkNode;
  11.     if (!L) {
  12.         return false;
  13.     }
  14.     L->next = L;
  15.     L->data = -1;
  16.     return true;
  17. }

  18. // 尾插法
  19. bool insert_tail(LinkList &L, ElemType e) {
  20.     if (!L) {
  21.         return false;
  22.     }
  23.     LinkNode *p = L;
  24.     while (p->next != L) {
  25.         p = p->next;
  26.     }
  27.     LinkNode *s = new LinkNode;
  28.     if (!s) {
  29.         return false;
  30.     }
  31.     s->data = e;
  32.     s->next = p->next;
  33.     p->next = s;
  34.     return true;
  35. }

  36. void printList(const LinkList &L) {
  37.     if (!L) {
  38.         return;
  39.     }
  40.     LinkNode *p = L->next;
  41.     while (p != L) {
  42.         cout << p->data << " ";
  43.         p = p->next;
  44.     }
  45.     cout << endl;
  46. }

  47. // 约瑟夫问题函数
  48. void josephus(LinkList &L, int m) {
  49.     if (!L || L->next == L) {
  50.         cout << "链表为空或只有头节点!" << endl;
  51.         return;
  52.     }
  53.     LinkNode *p = L->next; // 从第一个数据节点开始
  54.     LinkNode *prev = L;    // 记录p的前驱节点
  55.     while (L->next != L) { // 当还有数据节点时循环
  56.         for (int i = 1; i < m; i++) { // 数m-1次
  57.             prev = p;
  58.             p = p->next;
  59.             if (p == L) { // 如果遇到头节点,跳过
  60.                 prev = p;
  61.                 p = p->next;
  62.             }
  63.         }
  64.         // 删除当前节点p
  65.         prev->next = p->next;
  66.         cout << p->data << " ";
  67.         delete p;
  68.         p = prev->next;
  69.         if (p == L) { // 如果删除后指向头节点,调整到下一个数据节点
  70.             p = p->next;
  71.             prev = L;
  72.         }
  73.     }
  74.     cout << endl;
  75. }

  76. int main() {
  77.     LinkList L;
  78.     InitList(L);
  79.     int n, m;
  80.     cout << "请输入人数n:";
  81.     cin >> n;
  82.     cout << "请输入报数m:";
  83.     cin >> m;
  84.     for (int i = 1; i <= n; i++) {
  85.         insert_tail(L, i);
  86.     }
  87.     cout << "初始链表:";
  88.     printList(L);
  89.     cout << "出列顺序:";
  90.     josephus(L, m);
  91.     return 0;
  92. }
复制代码


使用说明:
1. 代码首先初始化循环链表,然后使用尾插法插入数据(例如人的编号)。
2. josephus 函数模拟报数过程,每次数到 m 时删除节点并输出数据。
3. 在循环中,如果指针遇到头节点,会自动跳过以确保只处理数据节点。

这个实现确保了约瑟夫问题的正确模拟,代码简洁易读。如果您有更多问题,欢迎继续提问!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-9-30 04:06

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表