C语言:约瑟夫问题——使用循环链表解决

传说有30个乘客同乘一条船,因为严重超载,加上风浪水作,危险万分。船长告诉乘客,只有将全船一半的乘客投入海 中,其余人才能幸免于难。他们约定了一个规则:30个人围成一圈,由第一个人数起,依次报数,数到第9个人,便把他投入大海中,然后再从他的下一个人数起,数到第9个人,再将其扔下大海,如此循环地进行,直到剩下15个乘客为止。请问哪些位置是将被扔下大海的位置,留下的是谁。

(由这个传说产生了约瑟夫问题,总数n,删除数为k)

最后我写了一个函数是将结果输出到外部文本txt中。

我所写出的循环链表是基于单链表来写的简而言之就是,首先,生成我们所学过的单链表(我这里采用的是头插法),每次生成一个空间,就将该空间的成员信息进行赋初值,也就是把结构里面所定义的成员的位置信息进行赋值(如:第一个成员的位置信息就是1,接下去就是2,3,4....)

PS:需要注意的是,我这里是头插法,所以我在位置信息的时候是从30开始,最后整个单链表生成之后就是从1开始的一个正向顺序的链表。 当然你也可以选择把整个单链表生成之后再进行赋值,这样可能会更清晰,我这里是边想边写,就没有考虑到这么多。

准备工作完成之后,你就可以把单链表的尾部指针,和头部指针,将这两个指针连接起来(尾部指针就是指向NULL的那个指针),记住一定是尾部指针指向头部指针,也就是把头部指针赋值给尾部指针,千万不能把头部指针指向尾部,因为这样的话你就是把你的单链表结构破坏掉了。

最后是输出环节,看过我文章 的小伙伴应该都知道,想要输出内容到txt文本流应该要用fprintf,不然你就是大冤种,在输出中文字符的时候没有用fprintf就会乱码,当然我这里没有输出中文字符,但是养成好习惯,在当你想输出文本流的时候一般情况下都建议你去使用fprintf

(忘记了的朋友可以看看我这篇博客的文字部分:http://t.csdn.cn/Pue8v

下面是源代码:

(耐心看完,不懂得可以留言,我知道的话都会回复的,毕竟讨论代码是更能让人记忆深刻)

#include<stdio.h>
#define PF(format,...) printf(#format, ##__VA_ARGS__)
#include<stdlib.h>
int n = 30;//总数 
int k = 9; //待删除的总数 
/*
	循环链表, 从头开始,
	判断总数是否小于n/2个,
	a)不是那就每数到第k个就删除节点
	指向下一个节点
	b)如果小于等于n/2那就退出,将链表中生剩下的元素打印进txt文件 
*/

typedef struct _circu_link{
	
	int index;//成员下标 
	int member;//成员 
	struct _circu_link *next;
	
}circu_link; 

circu_link *mem_H = NULL;//成员信息 

void Initmember();//初始化结构 

void Delete_mem();//删除信息 

void PF_result();

void Put_TXT(); 

void Release_mem();

int main(void)
{
	Initmember();//初始化 
	Delete_mem();//符合条件的成员将其删除 
	PF_result();//打印结果 
	Put_TXT();//将结果存到外部txt文件 
	Release_mem();
	return 0;
}
void Initmember()//初始化结构
{
	circu_link *temp, *new_member;
	int i;
	for(i = n; i >= 1; i--)
	{
		new_member = (circu_link*)malloc(sizeof(circu_link));
		if(new_member == NULL)
		{
			PF(分配内存失败!\n);
			exit(1);
		}
		if(mem_H == NULL)
		{
			mem_H = new_member;
			new_member->index = i; 
			new_member->next = NULL;
		}
		else
		{
			temp = mem_H;
			mem_H = new_member;
			new_member->index = i;
			new_member->next = temp;
		 } 
	 }
	 temp = mem_H;
	 while(temp->next != NULL)
	 {
	 	temp = temp->next;
	  } 
	  temp->next = mem_H;//生成循环链表 
//	  temp = mem_H;
//	  for(i = 0; i < 60; i++)
//	  {
//	  	PF(%d****, temp->index);
//	  	temp = temp->next;
//	  }
	
} 

void Delete_mem()
{
	circu_link *previous = NULL, *current, *temp;;
	current = mem_H;
	int i = 0, count = 0;
	while(1)
	{
		if(i >= n/2)//判断是否已经删除掉n/2的成员 
		{
			break;
		}
		else
		{
			count++;
			previous = current;
			current = current->next;
		}
		if(count == k-1)
		{
			count = 0;
			i++;
			temp = current;
			previous->next = current->next;//删除
			free(temp);
			current = previous->next;
		}
	}
}

void PF_result()
{
	circu_link *temp;
	int i;
	temp = mem_H;
	PF(大难不死的成员如下:\n);	
	for(i = 0; i < n/2; i++)
	{
		PF(-%d-, temp->index);
		temp = temp->next;
	}
	PF(\n);
}

void Put_TXT()
{
	FILE *fp = NULL;
	circu_link *temp = mem_H;
	int i;
	fp = fopen("D:/D/约瑟夫问题/Put.txt", "w");
	for(i = 0; i < n/2; i++)
	{
		fprintf(fp, "%d-",temp->index);
		temp = temp->next;
	}
	fclose(fp);
}

void Release_mem()
{
	int i;
	circu_link *temp = NULL;
	for(i = 0; i < n/2; i++)
	{
		temp = mem_H;
		mem_H = mem_H->next;
		free(temp);
	}
}

外部文件也同样生成了:

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

竹等寒

谢过道友支持,在下就却之不恭了

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值