约瑟夫环的c语言描述

约瑟夫环的c语言描述

问题描述

约瑟夫(Joseph)问题的一种描述是:编号为1,2,…,n的n个人按顺时针方向围坐一圈.每人持有一个密码(正整数)。一开始任选一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始顺序报数,报到m时停止报数。报m的人出列,将他的密码作为新的m值,从他在顺时针方向上的下一个人开始重新从1报数,如此下去,直至所有人全部出列为止。

代码(C语言)

#include <stdio.h>
#include <stdlib.h>
#define ERROR 0
#define SUCCESS 1
#define NUMBER 7 //总人数
typedef int Status;

typedef struct Joseph
{
    int password; //正整数密码
    int index;
    struct Joseph *next; //后继
} LNode, *LinkList;

Status CreatList_T(LinkList *L, int n);
Status PrintIndex(LinkList *L, int n);
Status ListDel(LinkList *L, int i);
Status ListDel_Elem(LinkList *L, LinkList pos);

int main(void)
{
    LinkList L;
    CreatList_T(&L, NUMBER); //建立总人数为NUMBER的链表
    PrintIndex(&L, NUMBER);  //按照约瑟夫环规则输出出列顺序
    return 0;
}

/* 尾插法建立无头结点的链表,同时为每个人输入其密码 */
Status CreatList_T(LinkList *L, int n)
{
    *L = (LinkList)malloc(sizeof(LNode));
    printf("Please input the password of 1st people: "); //先为第一个人赋值
    scanf("%d", &((*L)->password));
    (*L)->index = 1;
    (*L)->next = *L;
    LinkList tail = *L;

    for (int i = 0; i < n - 1; i++) //为其余人赋值
    {
        LinkList s = (LinkList)malloc(sizeof(LNode));
        printf("Please input the password of %dth people: ", i + 2);
        scanf("%d", &s->password);
        s->index = i + 2;
        s->next = *L; //尾元指向首元
        tail->next = s;
        tail = s; //tail指向尾元
    }
    return SUCCESS;
}

/* 删除链表中的第i个元素 */
Status ListDel(LinkList *L, int i)
{
    if (*L == NULL)
        return ERROR;

    LinkList p = *L, q;
    int j = 1;
    if (i == 1) //区分首节点与其余节点的删除方式
    {
        while (p->next != *L)
            p = p->next;
        *L = (*L)->next;
        free(p->next);
        p->next = *L;
    }
    else
    {
        while (j < i - 1) //将p指向pos的前驱
        {
            p = p->next, j++;
        }
        if (p->next != *L) //当前删除节点不是首元节点
        {
            q = p->next; //先用q指向当前删除元素
            p->next = p->next->next; //再将p后移
            free(q);
        }
        else //当前删除节点是首元结点
        {
            *L = (*L)->next; //将L指向第二个结点
            free(p->next);
            p->next = *L;
        }
    }

    return SUCCESS;
}

/* 将链表中的元素pos删除 */
Status ListDel_Elem(LinkList *L, LinkList pos)
{
    if (*L == NULL)
        return ERROR;

    LinkList p = *L, q;
    if (pos == *L) //区分首节点与其余节点的删除方式
    {
        while (p->next != *L) //将p指向尾元
            p = p->next;
        *L = (*L)->next;
        free(p->next);
        p->next = *L;
    }
    else
    {
        while (p->next != pos) //将p指向pos的前驱
            p = p->next;
        q = p->next; //先用q指向当前删除元素
        p->next = p->next->next; //再将p后移
        free(q);
    }

    return SUCCESS;
}

/* 按照约瑟夫环规则输出出列顺序 */
Status PrintIndex(LinkList *L, int n)
{
    int limit;
    LinkList p = *L, q;
    printf("Please input the limit: ");
    scanf("%d", &limit); //要求用户输入上限值
    printf("The order in which they listed was:\n\t");
    for (int i = 0; i < n; i++)
    {

        if (limit < 1) //上限必须为正整数
            return ERROR;
        for (int j = 1; j < limit; j++)
            //找到下一位出列者,注意初始已经移动了一位
            p = p->next;
        if(p->next != p)
            printf("%d -> ", p->index);
        else 
            printf("%d", p->index);
        limit = p->password;
        q = p;
        p = p->next;    //指向下一位
        ListDel_Elem(L, q); //删除链表中当前出列的人
    }
    return SUCCESS;
}

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值