鱼C论坛

 找回密码
 立即注册
查看: 550|回复: 2

[已解决]约瑟夫环 - 找神奇数字

[复制链接]
发表于 2024-11-2 11:55:10 | 显示全部楼层 |阅读模式

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

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

x
本帖最后由 UNKNOWN404 于 2024-11-2 15:04 编辑

大家好,

我最近在练习一个算法,通过双向环链表狀问题来找出一个神奇数字,移除全部'X'、只保留'O'。我已经完成了部分代码,但遇到了一些困难,希望得到大家的帮助。

由'O'和'X'组成的字符串,需要通过一个双向链表来模拟这个过程。算法需要从顺时针开始数,遇到第一个'X'时删除它并转换方向,然后重复这个过程。

我已经有了基本的节点定义和链表创建函数,但是不确定如何实现寻找神奇数字的函数。以下是我目前的代码框架:

范例:
输入:OXOXOXX
输出:神奇数字为 7


  1. /
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #define MAX_LENGTH 1000

  6. /* 定义节点 */
  7. typedef struct Node {
  8.     char data;           // 纪录 'O'和'X'
  9.     struct Node *next;   // 指向下一个节点的指针
  10.     struct Node *prev;   // 指向前一个节点的指针
  11. } Node;

  12. /* 建立一个新节点的函式 */
  13. Node *createNode(char data) {
  14.     // 使用 malloc 分配内存给新节点
  15.     Node *newNode = (Node*)malloc(sizeof(Node));
  16.    
  17.     // 检查内存是否成功分配
  18.     if (newNode == NULL) {
  19.         printf("内存分配失败\n");
  20.         exit(1);  // 如果失败,退出执行
  21.     }
  22.    
  23.     // 初始化新节点的资料和指针
  24.     newNode->data = data;
  25.     newNode->next = NULL;
  26.     newNode->prev = NULL;
  27.    
  28.     return newNode;  // 返回新创建的节点
  29. }

  30. /* 建立双向环状链节串行的函式 */
  31. Node *createCircularList(char *str) {
  32.     int i = 0;
  33.     int len = strlen(str);  // 获取字符串长度
  34.     if (len == 0) return NULL;  // 如果字符串为空,返回 NULL

  35.     Node* head = createNode(str[0]);  // 建立头节点
  36.     Node* current = head;

  37.     // 为字符串中的每个字符创建一个节点并连接
  38.     for (i = 1; i < len; i++) {
  39.         Node* newNode = createNode(str[i]);
  40.         current->next = newNode;
  41.         newNode->prev = current;
  42.         current = newNode;
  43.     }
  44.    
  45.     // 将最后一个节点和第一个节点连接,形成双向环状结构
  46.     current->next = head;
  47.     head->prev = current;
  48.    
  49.     return head;  // 返回头节点
  50. }

  51. /* 计算环状链节串行中节点数量的函式 */
  52. int countNodes(Node *head) {
  53.     if (head == NULL) return 0;  // 如果链节串行为空,返回 0

  54.     int count = 1;  // 从 1 开始计数(头节点)
  55.     Node *current = head->next;  // 从第二个节点开始

  56.     // 遍历链表直到回到头节点
  57.     while (current != head) {
  58.         count++;
  59.         current = current->next;
  60.     }

  61.     return count;  // 返回节点总数
  62. }

  63. /* 打印双向环状链节串行的函式 */
  64. void printList(Node* head) {
  65.     if (head == NULL) {
  66.         printf("链节串行为空\n");
  67.         return;
  68.     }

  69.     Node *current = head;
  70.     do {
  71.         printf("%c ", current->data);  // 打印当前节点的数据
  72.         current = current->next;       // 移动到下一个节点
  73.     } while (current != head);  // 当回到头节点时停止
  74.     printf("\n");
  75. }

  76. /* 从双向环状链节串行中移除指定节点的函式 */
  77. Node *removeNode(Node* head, Node* nodeToRemove) {
  78.     if (head == NULL || nodeToRemove == NULL) {
  79.         printf("错误:removeNode 函数收到空指针\n");
  80.         return head;
  81.     }

  82.     // 如果要移除的是头节点
  83.     if (head == nodeToRemove) {
  84.         if (head->next == head) {
  85.             // 如果链节串行中只有一个节点
  86.             free(head);
  87.             return NULL;
  88.         }
  89.         // 更新头节点
  90.         Node *newHead = head->next;
  91.         newHead->prev = head->prev;
  92.         head->prev->next = newHead;
  93.         free(head);
  94.         return newHead;
  95.     }

  96.     // 移除中间的节点
  97.     nodeToRemove->prev->next = nodeToRemove->next;
  98.     nodeToRemove->next->prev = nodeToRemove->prev;
  99.     free(nodeToRemove);

  100.     return head;
  101. }


  102. /* 释放双向环状链节串行内存的函式 */
  103. void freeList(Node *head) {
  104.     if (head == NULL) return;

  105.     Node* current = head->next;
  106.     Node* temp;

  107.     // 释放除了头节点外的所有节点
  108.     while (current != head) {
  109.         temp = current;
  110.         current = current->next;
  111.         free(temp);
  112.     }

  113.     // 释放头节点
  114.     free(head);
  115. }

  116. /* 修改后的查找神奇数字的函式 */
  117. int findMagicNumber(Node **head, char *originalStr) {
  118.     int i = 0;
  119.     int magicNumber = 1;  // 从 1 开始尝试
  120.     int isClockwise = 1;  // 1 表示顺时针,0 表示逆时针
  121.     Node *current = *head;
  122.     int remainingX = 0;  // 记录剩余的 'X' 数量

  123.     // 计算初始 'X' 的数量
  124.     Node *temp = *head;
  125.     do {
  126.         if (temp->data == 'X') remainingX++;
  127.         temp = temp->next;
  128.     } while (temp != *head);

  129.     // 主循环:持续直到所有 'X' 被移除
  130.     while (remainingX > 0) {
  131.         printf("当前链表: ");
  132.         printList(*head);
  133.         printf("尝试神奇数字: %d (方向: %s)\n",
  134.                magicNumber,
  135.                isClockwise ? "顺时针" : "逆时针");

  136.         // 移动到第 magicNumber 个节点
  137.         for (i = 1; i < magicNumber; i++) {
  138.             if (isClockwise) {
  139.                 current = current->next;
  140.             } else {
  141.                 current = current->prev;
  142.             }
  143.         }

  144.         // 如果当前节点是 'X',移除它并切换方向
  145.         if (current->data == 'X') {
  146.             printf("移除节点: %c\n", current->data);
  147.             Node *nodeToRemove = current;
  148.             current = isClockwise ? current->next : current->prev;
  149.             *head = removeNode(*head, nodeToRemove);
  150.             remainingX--;

  151.             if (*head == NULL) {
  152.                 printf("错误:链节串行为空\n");
  153.                 return -1;
  154.             }

  155.             // 切换方向
  156.             isClockwise = !isClockwise;
  157.             printf("切换方向为: %s\n", isClockwise ? "顺时针\n" : "逆时针\n");
  158.         } else {
  159.             // 如果是 'O',重建链表并重置方向为顺时针
  160.             printf("遇到 'O',重建链表\n\n");
  161.             freeList(*head);
  162.             *head = createCircularList(originalStr);
  163.             current = *head;
  164.             isClockwise = 1;  // 重置为顺时针
  165.             magicNumber++;    // 增加神奇数字
  166.         }
  167.     }

  168.     return magicNumber;  // 返回找到的神奇数字
  169. }

  170. /* 修改主函数以传递原始字符串 */
  171. int main() {
  172.     // 步骤 1: 打开输入文件
  173.     FILE *file = fopen("input.txt", "r");
  174.     if (file == NULL) {
  175.         printf("无法打开 input.txt 文件\n");
  176.         return 1;
  177.     }

  178.     // 步骤 2: 读取输入字符串
  179.     char str[MAX_LENGTH];
  180.     if (fgets(str, MAX_LENGTH, file) == NULL) {
  181.         printf("无法从 input.txt 读取数据\n");
  182.         fclose(file);
  183.         return 1;
  184.     }
  185.     fclose(file);

  186.     // 步骤 3: 移除字符串末尾的换行符(如果存在)
  187.     str[strcspn(str, "\n")] = 0;
  188.     printf("输入: %s\n", str);

  189.     // 步骤 4: 创建双向环状链节串行
  190.     Node* head = createCircularList(str);
  191.     if (head == NULL) {
  192.         printf("创建环状链表失败\n");
  193.         return 1;
  194.     }

  195.     // 步骤 5: 查找神奇数字,传入原始字符串用于重建
  196.     int magicNumber = findMagicNumber(&head, str);

  197.     // 步骤 6: 输出结果
  198.     if (magicNumber != -1) {
  199.         printf("神奇数字为 %d\n", magicNumber);
  200.     } else {
  201.         printf("未能找到神奇数字\n");
  202.     }

  203.     // 步骤 7: 释放剩余节点的内存
  204.     freeList(head);
  205.     return 0;
  206. }
复制代码
最佳答案
2024-11-2 11:55:30
你在实现约瑟夫环问题时遇到了一些困难。根据你的描述和代码框架,我注意到了一些需要修正的地方。以下是一些建议和修改:

1. **字符串读取和处理**:
   - 你在读取字符串时使用了`char str;`,这应该是一个字符数组而不是单个字符。
   - 使用`fgets`读取字符串时,确保字符串数组的大小足够大。

2. **创建链表**:
   - 在`createCircularList`函数中,`createNode(str)`应该是`createNode(str[i])`,因为你需要为每个字符创建节点。

3. **查找神奇数字的逻辑**:
   - 在`findMagicNumber`函数中,确保在每次重建链表时正确地重置`current`指针。
   - 确保在移除节点后,`current`指针指向下一个有效节点。

4. **文件读取和字符串处理**:
   - 确保在读取字符串后移除换行符。
   - 使用`str[strcspn(str, "
")] = 0;`来移除换行符。

以下是一些修改后的代码片段:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #define MAX_LENGTH 1000

  5. typedef struct Node {
  6.     char data;
  7.     struct Node *next;
  8.     struct Node *prev;
  9. } Node;

  10. Node *createNode(char data) {
  11.     Node *newNode = (Node*)malloc(sizeof(Node));
  12.     if (newNode == NULL) {
  13.         printf("内存分配失败
  14. ");
  15.         exit(1);
  16.     }
  17.     newNode->data = data;
  18.     newNode->next = NULL;
  19.     newNode->prev = NULL;
  20.     return newNode;
  21. }

  22. Node *createCircularList(char *str) {
  23.     int len = strlen(str);
  24.     if (len == 0) return NULL;

  25.     Node* head = createNode(str[0]);
  26.     Node* current = head;

  27.     for (int i = 1; i < len; i++) {
  28.         Node* newNode = createNode(str[i]);
  29.         current->next = newNode;
  30.         newNode->prev = current;
  31.         current = newNode;
  32.     }

  33.     current->next = head;
  34.     head->prev = current;
  35.     return head;
  36. }

  37. int findMagicNumber(Node **head, char *originalStr) {
  38.     int magicNumber = 1;
  39.     int isClockwise = 1;
  40.     Node *current = *head;
  41.     int remainingX = 0;

  42.     Node *temp = *head;
  43.     do {
  44.         if (temp->data == 'X') remainingX++;
  45.         temp = temp->next;
  46.     } while (temp != *head);

  47.     while (remainingX > 0) {
  48.         for (int i = 1; i < magicNumber; i++) {
  49.             current = isClockwise ? current->next : current->prev;
  50.         }

  51.         if (current->data == 'X') {
  52.             Node *nodeToRemove = current;
  53.             current = isClockwise ? current->next : current->prev;
  54.             *head = removeNode(*head, nodeToRemove);
  55.             remainingX--;
  56.             isClockwise = !isClockwise;
  57.         } else {
  58.             freeList(*head);
  59.             *head = createCircularList(originalStr);
  60.             current = *head;
  61.             isClockwise = 1;
  62.             magicNumber++;
  63.         }
  64.     }

  65.     return magicNumber;
  66. }

  67. int main() {
  68.     FILE *file = fopen("input.txt", "r");
  69.     if (file == NULL) {
  70.         printf("无法打开 input.txt 文件
  71. ");
  72.         return 1;
  73.     }

  74.     char str[MAX_LENGTH];
  75.     if (fgets(str, MAX_LENGTH, file) == NULL) {
  76.         printf("无法从 input.txt 读取数据
  77. ");
  78.         fclose(file);
  79.         return 1;
  80.     }
  81.     fclose(file);

  82.     str[strcspn(str, "
  83. ")] = 0;
  84.     printf("输入: %s
  85. ", str);

  86.     Node* head = createCircularList(str);
  87.     if (head == NULL) {
  88.         printf("创建环状链表失败
  89. ");
  90.         return 1;
  91.     }

  92.     int magicNumber = findMagicNumber(&head, str);

  93.     if (magicNumber != -1) {
  94.         printf("神奇数字为 %d
  95. ", magicNumber);
  96.     } else {
  97.         printf("未能找到神奇数字
  98. ");
  99.     }

  100.     freeList(head);
  101.     return 0;
  102. }
复制代码


希望这些建议和修改能帮助你解决问题!如果有其他问题,欢迎继续提问。

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

使用道具 举报

发表于 2024-11-2 11:55:30 | 显示全部楼层    本楼为最佳答案   
你在实现约瑟夫环问题时遇到了一些困难。根据你的描述和代码框架,我注意到了一些需要修正的地方。以下是一些建议和修改:

1. **字符串读取和处理**:
   - 你在读取字符串时使用了`char str;`,这应该是一个字符数组而不是单个字符。
   - 使用`fgets`读取字符串时,确保字符串数组的大小足够大。

2. **创建链表**:
   - 在`createCircularList`函数中,`createNode(str)`应该是`createNode(str[i])`,因为你需要为每个字符创建节点。

3. **查找神奇数字的逻辑**:
   - 在`findMagicNumber`函数中,确保在每次重建链表时正确地重置`current`指针。
   - 确保在移除节点后,`current`指针指向下一个有效节点。

4. **文件读取和字符串处理**:
   - 确保在读取字符串后移除换行符。
   - 使用`str[strcspn(str, "
")] = 0;`来移除换行符。

以下是一些修改后的代码片段:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #define MAX_LENGTH 1000

  5. typedef struct Node {
  6.     char data;
  7.     struct Node *next;
  8.     struct Node *prev;
  9. } Node;

  10. Node *createNode(char data) {
  11.     Node *newNode = (Node*)malloc(sizeof(Node));
  12.     if (newNode == NULL) {
  13.         printf("内存分配失败
  14. ");
  15.         exit(1);
  16.     }
  17.     newNode->data = data;
  18.     newNode->next = NULL;
  19.     newNode->prev = NULL;
  20.     return newNode;
  21. }

  22. Node *createCircularList(char *str) {
  23.     int len = strlen(str);
  24.     if (len == 0) return NULL;

  25.     Node* head = createNode(str[0]);
  26.     Node* current = head;

  27.     for (int i = 1; i < len; i++) {
  28.         Node* newNode = createNode(str[i]);
  29.         current->next = newNode;
  30.         newNode->prev = current;
  31.         current = newNode;
  32.     }

  33.     current->next = head;
  34.     head->prev = current;
  35.     return head;
  36. }

  37. int findMagicNumber(Node **head, char *originalStr) {
  38.     int magicNumber = 1;
  39.     int isClockwise = 1;
  40.     Node *current = *head;
  41.     int remainingX = 0;

  42.     Node *temp = *head;
  43.     do {
  44.         if (temp->data == 'X') remainingX++;
  45.         temp = temp->next;
  46.     } while (temp != *head);

  47.     while (remainingX > 0) {
  48.         for (int i = 1; i < magicNumber; i++) {
  49.             current = isClockwise ? current->next : current->prev;
  50.         }

  51.         if (current->data == 'X') {
  52.             Node *nodeToRemove = current;
  53.             current = isClockwise ? current->next : current->prev;
  54.             *head = removeNode(*head, nodeToRemove);
  55.             remainingX--;
  56.             isClockwise = !isClockwise;
  57.         } else {
  58.             freeList(*head);
  59.             *head = createCircularList(originalStr);
  60.             current = *head;
  61.             isClockwise = 1;
  62.             magicNumber++;
  63.         }
  64.     }

  65.     return magicNumber;
  66. }

  67. int main() {
  68.     FILE *file = fopen("input.txt", "r");
  69.     if (file == NULL) {
  70.         printf("无法打开 input.txt 文件
  71. ");
  72.         return 1;
  73.     }

  74.     char str[MAX_LENGTH];
  75.     if (fgets(str, MAX_LENGTH, file) == NULL) {
  76.         printf("无法从 input.txt 读取数据
  77. ");
  78.         fclose(file);
  79.         return 1;
  80.     }
  81.     fclose(file);

  82.     str[strcspn(str, "
  83. ")] = 0;
  84.     printf("输入: %s
  85. ", str);

  86.     Node* head = createCircularList(str);
  87.     if (head == NULL) {
  88.         printf("创建环状链表失败
  89. ");
  90.         return 1;
  91.     }

  92.     int magicNumber = findMagicNumber(&head, str);

  93.     if (magicNumber != -1) {
  94.         printf("神奇数字为 %d
  95. ", magicNumber);
  96.     } else {
  97.         printf("未能找到神奇数字
  98. ");
  99.     }

  100.     freeList(head);
  101.     return 0;
  102. }
复制代码


希望这些建议和修改能帮助你解决问题!如果有其他问题,欢迎继续提问。

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

使用道具 举报

发表于 2024-11-2 14:51:20 From FishC Mobile | 显示全部楼层
双向遍历节点,遇到 X 就删除节点,这和约瑟夫环有什么关系,神奇的数字和残存节点又是什关系,你这不止1个“O”,是都留下还是只留1个?
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-4-19 16:19

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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