数据结构C语言—约瑟夫环问题

                                   90行代码用双向链表解决约瑟夫环问题

问题描述:

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

设计要求:

(1)采用双向循环链表存储结构,描述线性表的抽象数据类型。

(2)写一高效算法,根据报数值m选择指针的移动方向。

代码如下:

#include<stdio.h>
#include<stdlib.h>
typedef struct Node
{
int date,num;                    //记录密码和序号
struct Node *next,*prior;  //前继指针和后续指针
}Node;

//双向链表初始化
Node *Inslist()
{
Node *head;
head=(Node *)malloc(sizeof(Node));
head->next=head;
head->prior=head;
return head;
}

//录入数据
void createlist(Node *L,int n)
{
Node *s,*r;
int i,x;
r=L;
scanf("%d",&x);           //输入密码
r->date=x;
r->num=1;
for(i=2;i<=n;i++){
        scanf("%d",&x);   //录入每个人的密码
        s=(Node *)malloc(sizeof(Node));
        s->date=x;
        s->num=i;           //初始化每个人的序号
        s->prior = r;        //插入新的结点
        s->next = r->next;
        r->next->prior= s;
        r->next= s;
        r=s;
}
}

//双向循环链表的输出
void printflist(Node *L,int t)
{
Node *p;
p=L;
int m,i,sum,k=0;
printf("输入报数值m:");
scanf("%d",&m);
while(p->next!=p){
            sum=t-k;                       //sum为剩余人数
            while(m-sum>0) 
            m=m-sum;
            if(m<=sum/2){             //判断链表寻找方向,提高查找效率
            for(i=1;i<m;i++){
                p=p->next;
            }
            printf("%d ",p->num);
            m=p->date;
            p->prior->next=p->next;
            p->next->prior=p->prior;
            L=p->next;
            free(p);
            p=L;
    }
    else{
            m=sum-m+1;
            for(i=1;i<=m;i++){
                p=p->prior;
            }
            printf("%d ",p->num);
            m=p->date;
            p->prior->next=p->next;
            p->next->prior=p->prior;
            L=p->next;
            free(p);
            p=L;
    }
            k++;
}
printf("%d",p->num);
printf("\n");
}
int main(void)
{
Node *L;
int x,m;
L=Inslist();
printf("输入几个数:\n");
scanf("%d",&x);
printf("输入数据\n");
createlist(L,x);
printf("输出数据\n");
printflist(L,x);
system("pause");
return 0;
}

程序运行结果如下图:

  • 11
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
约瑟夫环问题是一个经典的问题,描述为: 有 n 个人围成一圈,从第 k 个人开始报数,报到 m 的人出圈,直到剩下最后一个人。求出出圈人的顺序。 解决这个问题的一种经典算法是使用循环链表。具体实现如下: 1. 定义一个结构体表示链表节点,包括节点编号和指向下一个节点的指针。 struct Node { int num; struct Node* next; }; 2. 创建一个循环链表,将每个节点按顺序连接起来。 struct Node* createList(int n) { struct Node* head = NULL; struct Node* prev = NULL; for (int i = 1; i <= n; i++) { struct Node* node = (struct Node*)malloc(sizeof(struct Node)); node->num = i; node->next = NULL; if (head == NULL) { head = node; } else { prev->next = node; } prev = node; } prev->next = head; return head; } 3. 定义一个函数,实现约瑟夫环问题的解决过程。 void josephus(int n, int k, int m) { struct Node* head = createList(n); struct Node* p = head; struct Node* prev = NULL; for (int i = 0; i < k - 1; i++) { prev = p; p = p->next; } while (n > 1) { for (int i = 0; i < m - 1; i++) { prev = p; p = p->next; } printf("%d ", p->num); prev->next = p->next; struct Node* temp = p; p = p->next; free(temp); n--; } printf("%d\n", p->num); free(p); } 在主函数中调用 josephus 函数,传入 n、k、m 三个参数即可得到出圈人的顺序。 int main() { int n = 6, k = 3, m = 4; josephus(n, k, m); return 0; } 输出结果为:3 6 4 2 5 1 这个算法的时间复杂度为 O(nm),在数据量较大时可能会比较慢。如果需要更高效的解决方案,可以使用数学公式推导出出圈人的顺序,时间复杂度可以优化到 O(n)。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值