约瑟夫环问题 (用循环链表解决)

时间:2021-09-30 20:27:11

/*
已知N个人围坐在一张圆桌周围,从编号为k的人开始报数,数到m的那个人出列,他的下
一个人又从1开始报数,数到m的那个人又出列,以此规则重复下去,直到圆桌周围的全
部出列.

 

基本思想
(1),建立一个具有n个链结点且不带头结点的循环链表
(2),确定第一个报数点的位置
(3),不断地从链表中删除一个链结点,直到链表中还有一个链结点止
*/
#include <stdio.h>
#include <malloc.h>

struct list
{
    int data;
    struct list *link;
};

void josephus(int n, int m, int k)
{
    struct list *p, *r, *list = NULL;
    int i;
    //list 为第一个结点
    for (i = 1; i <= n; i++)
    {
        p = (struct list *)malloc(sizeof(struct list));
        p->data = i;
       
        if (list == NULL)
            list = p;
        else
            r->link = p;
        r = p;
    }
   
    p->link = list;//建立一个循环链表 指向第一个结点
    p = list;//p为首节点
   
    for (i = 1; i < k; i++)
    {
        r = p;
        p = p->link;
    }//此时p指向第一个出发结点(即第k处)
   
    while (p->link != p)//循环结束条件为只剩下最后一个节点 
    {
        for (i = 1; i < m; i++)
        {
            r = p;
            p = p->link;
        }//p指向第m个结点,r指向第m-1个结点
        r->link = p->link;//删除第M个结点
        printf("%4i", p->data);
        free(p);
        p = r->link;
    }
   
    printf("/n最后被删除结点是%4i/n", p->data);
}

int main(void)
{
    josephus(8, 4, 9);
   
    return 0;
}