3.1.4【约瑟夫问题:无头单向循环链表】

39 阅读2分钟

1. 题目

设编号为12,……nn个人围坐一圈,约定编号为k (1≤k≤n)的人从1开始报数,数到m的那个人出列。它的下一位继续从1开始报数,数到m的人出列,依次类推,最后剩下一个为猴王。

2. 解题举例

  • 编号 为k者 ,开始前指定
  • 每个人 编号 从1 开始
  • 数到m 的那个人 被杀
  • 被杀死者的下个人 从1 报数

刚开始如下:

假设n=6总共6人,k=1从第一个人开始,m=5,每次从1数到5。

第一轮报数后如下:

从1号开始,数5个数,数完5个数,5号被杀死,第一轮报数后,剩余人数如下。

第二轮报数后,如下:

从6开始报号1,然后4出局,下个人为6。

第三轮报数后,如下:

第四轮报数后,如下:

第五轮报数后,如下:

3. 代码

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

typedef struct LinkListNode
{
    int data;
    struct LinkListNode *next;
} LLN, *LL;

int main(int argc, const char *argv[])
{
    LL H = NULL;    // 无头链表的头指针
    LL PDel = NULL; // 用于指向被删除节点

    LL PTail = NULL; // 永远指向当前链表的尾
    LL PNew = NULL;  // 永远指向新创建的节点

    int i;
    int all_num = 6;   // 猴子总数
    int start_num = 1; // 从几号猴子开始数
    int kill_num = 5;  // 数到几杀死猴

    // 1.创建出一个单向循环链表
    //(1)创建有 all_num 个节点的 无头 单向链表
    H = (LL)malloc(sizeof(LLN));
    if (NULL == H)
    {
        perror("H malloc failed");
        return -1;
    }
    H->data = 1;    //规定编号从1开始
    H->next = NULL; //初始化空指针域

    PTail = H; // 尾指针指向当前的第一个结点

    // 顺序创建到规定数目的 结点
    for (i = 2; i <= all_num; i++)
    {
        // 创建新的节点
        PNew = (LL)malloc(sizeof(LLN));
        if (NULL == PNew)
        {
            perror("PNew malloc failed");
            return -1;
        }

        // 将新结点装上数据
        PNew->data = i;
        PNew->next = NULL;

        // 将新结点链接到链表尾
        PTail->next = PNew; // 链接到链表的尾
        PTail = PNew;       // 尾指针继续指向当前链表的尾
    }

    // 1 2 3 4 5 6

    //(2)将 头结点 保存到 链表的尾结点的next指向 形成 无头单向循环 链表
    PTail->next = H; // 形成 无头单向循环链表

    // 2.开始杀猴子
    //(1)将头指针移动到开始猴子的号码处
    for (i = 0; i < start_num - 1; i++)
        H = H->next;

    //(2)循环进行杀猴子
    while (H != H->next) // 终止:就剩一个猴子,只有一个节点
    {
        // 将头指针移动到即将删除节点的前一个节点
        // -2 理解为从1开始数的,和被删结点的 前个结点上
        for (i = 0; i < kill_num - 2; i++)
            H = H->next;

        // 指向被删结点
        PDel = H->next;

        // 跨过删除节点
        // H->next = PDel->next;
        H->next = H->next->next;

        printf("kill is -------------%d\n", PDel->data);
        free(PDel);
        PDel = NULL;

        // 杀死猴子后,从被杀死结点 的下一个节点 开始继续数,
        // 即将头指针移动到开始数的地方
        H = H->next;
    }
    printf("king is=================== %d\n", H->data);

    return 0;
}