约瑟夫环问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围,每个人手里都有一个密码。玩家随机输入一个初始密码m,从编号为k的人开始报数,数到m的那个人出列,并将其手中的密码视为m;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围人全部出列。
新学了单循环链表的操作,简单写了一下约瑟夫环,有不对的地方还望大神指出。
代码如下:
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int sequence, password;//玩家的序号和密码
struct node* next;
}Node,*List;
struct node* link_create(int n);
void play(Node* head, int n, int k, int m);
void link_print(Node* head,int n);
int main()
{
Node* head;
int n = 0,k=0,m=0;//n为玩家人数,k为起始位置,m为初始密码
printf("请输入玩家人数\n");
scanf_s("%d", &n);
printf("请输入开始计数的位置\n");
scanf_s("%d", &k);
printf("请输入初始密码\n");
scanf_s("%d", &m);
head = link_create(n);//创建一个长度为n的链表
link_print(head, n);
play(head, n, k, m);
}
struct node* link_create(int n)
{
List p=NULL,q=NULL,head;
head = (List)malloc(sizeof(Node));//创建一个链表的表头
p = head;
if (n != 0)
{
for (int i = 1; i <= n; i++)//通过循环进行链表结点的插入,实现初始化
{
int password = 0;
q = (List)malloc(sizeof(Node));
q->sequence = i;
printf("请输入序号为%d的密码\n",q->sequence);
scanf_s("%d", &password);
q->password = password;
p->next = q;
p = q;
}
q->next = head->next;//初始化完毕后,将尾节点指向头结点的下一位
free(head);//头结点内没有存储数据,因此将该头结点释放
head = NULL;//防止野指针
}
return q->next;//返回新的头结点
}
void play(Node* head, int n, int k, int m)
{
//用两个指针来进行删除操作
List p = head;
Node* r = head->next;
if (k != 1)//链表第一个元素的标号就是1,这里不要和数组元素的下标混为一谈
{
for (int i = 1; i < k; i++)
{
p = r;
r = r->next;
}
}
while (n--)
{
for (int j = 1; j < m - 1; j++)
{
p = r;
r = r->next;
}
printf("->%d", r->sequence);
p->next = r->next;
m = r->password;//将出列的玩家的密码设为新的密码
free(r);
p = p->next;
r = p->next;
}
printf("\n");
}
void link_print(Node* head,int n)
{
Node* p = head;
for (int i = 1; i <= n; i++)
{
printf("(%d,%d) ", p->sequence,p->password);
p = p->next;
}
printf("\n");
}