C语言循环单链表(约瑟夫环问题)

话不多说,直接上代码

首先是.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 遍历一下链表,得到开始数的位置结点得地址然后传到删除函数里面就可以完成这个功能。

  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值