今天把题目进行补充说明加上一个小练习题,单向循环链表的约瑟夫环问题。
约瑟夫环问题是一个经典的数学问题,题目大致为编号分别为1,2,......,n个人围坐在一圈,约定序号为k(1<=k<=n)得人从1开始计数,数到m的那个人出列,他的下一位又从1开始计数,数到m的那个人又出列,直到所有人都出列为止。
看完这个题目之后我们就可以清楚的反应出这是一个可以用单项循环链表来完成的问题。所以我们先写出算法思路:用一个不带头结点的循环链表来处理Josephu问题,先构成一个有n个结点的单项循环链表,然后从k结点起从1计数,计到m时,对应结点从列表中删除;然后再从删除的下一个节点开始计数,直到所有节点全部列出时算法截止。
程序代码为:
linklist.h:
/*
作者:张小五
时间:2018年1月29日
*/
#ifndef LINKLIST_H_
#define LINKLIST_H_
typedef struct node{ //结点类型
int data; //结点的数据域
struct node *next; //结点元素的后继指针域
}linkNode,*linkp;
void CreateList(linkp H); //建立单链表
void PrintList(linkp H);//打印单链表
linkp GetList(linkp H,int i);//根据序号查找
void InsertList(linkp H,int x ,int i);//插入元素
void DeleteList(linkp H,int i);//删除元素
void L1n_Ln1(linkp H);//倒置列表
void Josephu(linkp H,int n ,int k,int m); //约瑟夫环问题
#endif // LINKLIST_H_
linklist.c
//约瑟夫环问题
void Josephu(linkp H,int n,int k,int m){
//首先我们需要先创建一个单向循环链表
int i;
linkp p,r;
H = NULL;
printf("排列之前的链表为:\n");
for(i=1;i<=n;i++){ //建立一个循环链表
p = (linkp)malloc(sizeof(linkNode));
p->data = i;
if(H==NULL){
H = p;
r = p;
}else{
r->next = p; //r结点代替头结点不停移动链接本表
r=p;
}
printf("%d ",p->data);
}
p->next = H; //尾结点链接头结点,形成一个环
p = H;
printf("\n排列之后的链表为:\n");
for(i=1;i<k;i++){//寻找第K个结点
r = p;
p = p->next;
}
while (p->next!=p){ //当结点数大于1时
for(i=1;i<m;i++){//依次报数
r = p;
p = p->next;
}
r->next = p->next; //删除报数出的结点
printf("%d ",p->data);//打印输出
free(p); //释放删除的结点空间
p = r->next; //从下一节点开始重新计数
}
printf("%d",p->data); //最后一个出列的数
free(p);
}
main.c
/*
作者:张小五
时间:2018年1月29日
*/
#include "stdio.h"
#include "linklist.h"
#include "linklist.c"
int main(int argc,char *argv[]){
linkp H;
/*H =(linkp)malloc(sizeof(linkNode));
H->next = NULL;
CreateList(H);
PrintList(H);*/
/*int i;
linkp temp;
printf("请输入要查找的位置:");
scanf("%d",&i);
temp = GetList(H ,i-1);
if(temp!=NULL){
printf("你要查找的数值是%d\n",temp->data);
}else{
printf("你要查找的位置不存在!\n");
}*/
/*int x,i;
printf("请输入要插入的数据和位置:\n");
scanf("%d %d",&x,&i);
InsertList(H,x,i-1);*/
/*int i ;
printf("请输入要删除的位置:");
scanf("%d",&i);
DeleteList(H,i-1);*/
/*L1n_Ln1(H);
PrintList(H);*/
int n,k,m;
printf("请依次输入排列的数据个数,开始的位置,间隔数量:\n");
scanf("%d %d %d",&n,&k,&m);
Josephu(H,n,k,m);
return 0;
}
运行结果截图:
当然,这个问题还有很多其他的解决形式,比如说双向循环链表,在这里就不列出代码了。