话不多说,直接上代码
首先是.h头文件
#ifndef _CLINKLIST_H__
#define _CLINKLIST_H__
typedef int data_t;
typedef struct clinklist {
data_t data;
struct clinklist* next;
}Clinklist;
#include <stdio.h>
#include <stdlib.h>
Clinklist* Linklist_Creat();
void Clinklist_Insert(Clinklist* L, int n);
data_t* Clinklist_Delete_Pos(Clinklist* L, int n, int m,data_t arr[]);
void Clinklist_Show(Clinklist* L, int n);
#endif //
可以看到我定义了一个常规的链表结构,约瑟夫环只需要我们写入一串从1开始增加的数到链表中,当然我们需要将这个单链表写成无头循环单链表,其次这个问题只需要用到单链表的增加元素和删除元素这两个功能,具体看.c文件
#include "clinklist.h"
Clinklist* Linklist_Creat()//初始化
{
Clinklist* L = (Clinklist*)malloc(sizeof(Clinklist));//开辟空间
if (L == NULL)
{
printf("malloc failed!\n");
return NULL;
}
L->data = 1;
L->next = L;
return L;
}
void Clinklist_Insert(Clinklist* L,int n)
{
for (n; n >1; n--)
{
Clinklist* p = (Clinklist*)malloc(sizeof(Clinklist));
if (p == NULL)
{
printf("element malloc fail!\n");
return ;
}
p->data = n;
p->next = L->next;
L->next = p;
}
return ;
}
data_t* Clinklist_Delete_Pos(Clinklist* L, int n, int m, data_t arr[])
{
int len = 0;
Clinklist* p = L;
for (int i = 1;n!=0 ; i++)
{
if (i%(m-1)==0)
{
arr[len] = p->next->data;
Clinklist* q = p->next;
p->next = q->next;
free(q);
q = NULL;
n--;
len++;
i = 0;
}
p = p->next;
}
return arr;
}
void Clinklist_Show(Clinklist* L,int n)
{
Clinklist* q = L;
for (int i = 0; i < n; i++)
{
printf("%d", q->data);
q = q->next;
}
puts(" ");
}
我使用的是头插法使元素插入到链表中去,虽然定义的是有头链表,但是我将头结点的data赋值为1,让它加入到循环中去,可以起到和无头链表一样的效果,在 Clinklist_Delete_Pos()函数中,Clinklist* L是创建的链表头节点,
int n是约瑟夫环的人数,
int m是从第几人开始数,
data_t arr[]是存放淘汰的人的元素下标
for (int i = 1;n!=0 ; i++)
{
if (i%(m-1)==0)
{
arr[len] = p->next->data;
Clinklist* q = p->next;
p->next = q->next;
free(q);
q = NULL;
n--;
len++;
i = 0;
}
p = p->next;
}
这一段代码是在进行删除结点,实现for循环的退出条件是n=0;人数为零时退出,那就不用在写销毁的函数,if(i%(m-1)==0)判断是不是到需要删除结点的前一个结点,条件成立就进行删除操作。
接下来是main函数:
#include "clinklist.h"
int main()
{
data_t arr[50]={0};
int n, m;
Clinklist* L = Linklist_Creat();
printf("请输入参与人数:\n");
scanf_s("%d", &n);
Clinklist_Insert(L,n);
Clinklist_Show(L,n);
printf("请输入淘汰数字:\n");
scanf_s("%d", &m);
Clinklist_Delete_Pos(L, n, m, arr);
printf("淘汰顺序是:\n");
for (int i = 0; i < n; i++)
{
printf(" %d ", arr[i]);
}
puts(" ");
return 0;
}
运行截图:
还可以从第几人开始数,需要在删除结点函数的前面加入一个for 遍历一下链表,得到开始数的位置结点得地址然后传到删除函数里面就可以完成这个功能。