用循环链表实现Josephus问题

  Josephus问题:设有n个人围坐在一个圆桌周围,现从第s个人开始报数,数到第m的人出列,然后从出列的下一个人重新开始报数,数到第m的人又出列。如此反复直到所有的人全部出列为止。

  思路:构建一个没有头结点的循环链表,实现自己的删除函数,数到第几个结点就把这个结点从链表中删除,然后重新数。

  难点在于写删除函数。

  代码如下:

 

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

typedef struct student * PNode;

typedef struct student{
    int data;
    PNode next;    
}Node;

PNode create(int n)
{
    PNode head=(PNode)malloc(sizeof(Node));
    PNode p;
    int data=0;
    p=head;
    printf("请输入结点的值\n");
    scanf("%d",&data);
    p->data=data;
    while(--n)
    {
        p->next=(PNode)malloc(sizeof(Node));
        p=p->next;
        printf("请继续输入结点的值\n");
        scanf("%d",&data);
        p->data=data;
    }
    p->next=head;
    return head;
}
void print(PNode link)
{
    PNode head,p;
    if(link==NULL) return;
    head=link;
    p=link;
    while(p->next!=head)
    {
        printf("%d ",p->data);
        p=p->next;
    }
    printf("%d\n",p->data);
}



PNode del(PNode link,int num)
{
    PNode head=link;
    PNode p=link;
    PNode temp;
    if(link==NULL)
    {
    //       printf("链表为空");
        return NULL;
    }     
    //      printf("要删除结点的值为%d\n",num);
    //删除头结点    
    if(p->data==num)
    {
        if(p->next==head)   //只剩下一个结点的情况
        {
    //            printf("链表删除完毕。\n");
            free(link); 
            return NULL;
        }
        while(p->next!=head)
            p=p->next;
        temp=p->next;
        p->next=p->next->next;
        head=p->next;
        free(temp);
        return head;
    }    
    //删除非头结点
    while(p->next->data!=num && p->next!=head)
    {
        p=p->next;
    }
    if(p->next==head)
    {
   //        printf("没有找到这样的结点。\n");
        return head;
    }    
    temp=p->next;
    p->next=p->next->next;
    free(temp);
    return head;
}

void Josepus(PNode link,int n,int k,int m)
{
    if(link==NULL)
    {
        printf("链表为空\n");
        return;
    }    
    printf("打印出列的顺序:");
    PNode p=link;
    int r=k+m-2;  //r为链表要移动的次数,根据图示来进行r大小的确认
    while(r--)
    {
        p=p->next;
    }
    printf("%d ",p->data);
    p=del(p,p->data);
    while(p!=NULL)
    {        
        r=m-1;
        while(r--)
        {    
            p=p->next;
        }
        printf("%d ",p->data);
        p=del(p,p->data);
    }
    printf("\n");
}

int main(void)
{
        int n,num;
        int s,m;
        printf("请输入要创建多少个结点\n");
        scanf("%d",&n);
        PNode link=create(n);
        printf("打印初始链表\n");
        print(link);
        printf("请输入要从第几个人开始报数\n");
        scanf("%d",&s);
        printf("请输入要报多少个人\n");
        scanf("%d",&m);
        Josepus(link,n,s,m);/*      测试删除函数用地
         while(1)
    {
        printf("请输入要删除的结点的值\n");
        scanf("%d",&num);
        link=del(link,num);
        if(link==NULL)
            break;
        printf("打印删除后的链表\n");
        print(link);
    }
*/
    return 0;
}

 程序猿必读

转载于:https://www.cnblogs.com/longzhongren/p/4417904.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值