约瑟夫环(综合性实验)

约瑟夫环(综合性实验)

1. 需求分析

需求:
约瑟夫问题的一种描述是,编号为1, 2, …, n的n个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。一开始任选一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始顺序报数, 报到m时停止报数。报m的人出列,将他的密码作为新的m值,位于他顺时针方向上的下一个人开始重 新从1报数,如此下去,直至所有人全部出列。试设计一个程序求出出列顺序。要求: 利用单向循环链表存储结构模拟此过程,按照出列的顺序打印出每个人的编号。
分析:

  1. 输入的形式和输入值的范围:按照提示将数据放在文件后,输入Y,输出结果生成在文件“ 约瑟夫环结果.txt”中。
  2. 输出的形式:输出数个int型数字。
  3. 程序所能达到的功能:
    利用单向循环链表存储结构模拟约瑟夫环,按照出列的顺序打印出每个人的编号。
  4. 测试数据:
    两组数据,分别是:
    6
    3 1 7 2 4 8
    1

    7
    3 1 7 2 4 8 4
    20
    将两组数据放入“约瑟夫环.txt”中,输入Y,程序将运行结果放入文件“约瑟夫环结果.txt”中。

2. 概要设计

  1. 为了实现程序功能,需要定义顺序栈的抽象数据类型。
ADT List { 
数据对象: D={ ai | ai ∈ElemSet, i=1,2,...,n, n≥0 } 
数据关系: R1={ <ai-1, ai >|ai-1, ai∈D, i=2,...,n } 
typedef struct lnote{             //链表节点 
	int number;                   //编号 
	int data;                     //密码 
	struct lnote *next;
}*node,NODE;
typedef struct LIST{             //链表结构  
	node head;
	node tail;
	int len;
}list;
基本操作:
	初始化操作 InitList( &L )
		操作结果:构造一个空的线性表L。 
	结构销毁操作 DestroyList( &L ) 
		初始条件:线性表 L 已存在。
		操作结果:销毁线性表 L。
	线性表判空操作 ListEmpty( L )
		初始条件:线性表 L 已存在。
		操作结果:若 L 为空表,则返回 TRUE,否则返回FALSE。
	求线性表的长度 ListLength( L )
		初始条件:线性表 L 已存在。
		操作结果:返回 L 中数据元素的个数。
	求数据元素的前驱 PriorElem( L, cur_e, &pre_e )
		初始条件:线性表 L 已存在。
		操作结果:若 cur_e 是 L 的元素,则用pre_e 返 回它的前驱,否则操作失败,pre_e无 定义。
	求数据元素的后继 NextElem( L, cur_e, &next_e )
		初始条件:线性表 L 已存在。
		操作结果:若 cur_e 是 L 的元素,则用next_e 返 回它的后继,否则操作失败,next_e 无定义。
	求线性表中第i个数据元素 GetElem( L, i, &e )
		初始条件:线性表 L 已存在,并且 1≤i≤ListLength(L) 。
		操作结果:用 e 返回 L 中第 i 个数据元素的值。
	定位函数 LocateElem( L, e, compare( ) )
		初始条件:线性表 L 已存在,e 为给定值, compare( ) 是元素判定函数。
		操作结果:返回 L 中第 1 个与 e 满足关系 compare( ) 的元素的位序。 若这样的元素不存在,则返回值为 0。
	遍历线性表 ListTraverse(L, visit( ))
		初始条件:线性表 L 已存在。 visit( ) 为某个访问函数。
		操作结果:依次对 L 中每个元素调用 函数visit( )。一旦 visit( )失败, 则操作失败。
	线性表置空 ClearList( &L )
		初始条件:线性表 L 已存在。
		操作结果:将 L 重置为空表。
	改变第 i 个数据元素的值 PutElem( &L, i, e )
		初始条件:线性表 L 已存在,并且 1≤i≤ListLength(L) 。
		操作结果:L 中第 i 个元素赋值 e 。
	插入数据元素 ListInsert( &L, i, e )
		初始条件:线性表 L 已存在,且 1≤i≤ListLength(L)+1 。
		操作结果:在 L 中的第 i 个元素之前插入 新的元素 e,L 的长度增1。
	删除数据元素 ListDelete( &L, i, &e )
		初始条件:线性表 L 已存在并且非空, 且1≤i≤ListLength(L) 。
		操作结果:删除 L中的第 i 个元素,并且用 e 返 回其值,L 的长度减1} ADT List

3.具体代码

#include<stdio.h>
#include<stdlib.h>

typedef struct lnote{             //链表节点 
	int number;                   //编号 
	int data;                     //密码 
	struct lnote *next;
}*node,NODE;
typedef struct LIST{             //链表结构  
	node head;
	node tail;
	int len;
}list;

void createlist(list *p);                      //创建线性表
void add_node(list *p,int password,int num);   //添加节点
void delete_node(list *p,int num);             //删除节点

int main()
{
	FILE *information,*result;
	char judge; 
	int n,m,sum;
	printf("请将数据依次放入文件'约瑟夫环.txt.'\n格式如下:\n人数\n各个人的密码\n初始密码\n");                                   
	printf("是否放入?(Y/N)");
	scanf("%c",&judge);
	while(judge != 'Y'&&judge != 'y')
	{
	    printf("请将数据放入文件'约瑟夫环.txt.'\n");                                    
	    printf("是否放入?(Y/N)");
		getchar();
	    scanf("%c",&judge);
	}
	if((information=fopen("约瑟夫环.txt","rt"))==NULL)
	{
		exit(-1);
	}
	if((result=fopen("约瑟夫环结果.txt","w"))==NULL)
	{
        printf("\n无法创建“约瑟夫环结果.txt”!");
        exit(-1);
    }
	for(int sequence = 1;(fscanf(information,"%d",&n))!=EOF;sequence++)  //模拟约瑟夫环过程 
	{	
	    list loop;
	    createlist(&loop);                   //创建链表 
	    for(int i = 1;i<=n;i++)              //读取数据并写入链表 
	    {
		    int password;
		    fscanf(information,"%d",&password);
		    add_node(&loop,password,i);
	    }
	    fscanf(information,"%d",&m);        //读取初始上限值 
	    node p;
	    p = loop.head->next;
	    int delete_num=1;
        fprintf(result,"第%d组数据结果:",sequence);
	    for(;loop.len != 0;)
	    {
	        for(int i = 1;i < m;i++)      //报数过程 
		    {
		        if(p == loop.tail)        //报数到链表尾,从头链表再次循环 
			    {
				    delete_num=1;
			        p = loop.head->next;	
			    }  	
			    else                     //报数 
			    {
			        delete_num++;
				    p = p->next; 
			    }
		    }
		    fprintf(result,"%d ",p -> number);    //出列 
		    m = p->data;                          //密码作为新m值 
		    if(p == loop.tail)
		    {
			    p = loop.head->next;	
		    }	
		    else
		    {
			    p = p->next; 
		    }
		    delete_node(&loop,delete_num);	     //删除链表中出列的节点 
		    if(p == loop.head->next)             //出列者若为链表尾,则从链表头开始 
		    {
			    delete_num=1;
		    }
	    } 
	    fprintf(result,"\n");
	} 
    printf("结果已生成在“约瑟夫环结果.txt”"); 
    return 0;	
} 
void createlist(list *p)                         //创建线性表
{
	p->head = malloc(sizeof(NODE));
	p->head->next = NULL;
	p->tail = p->head; 
	p->len=0;
}
void add_node(list *p,int password,int num)       //添加节点
{
	node q;
	q = malloc(sizeof(NODE));
	q->data = password;
	q->number = num;
	q->next = NULL;
	p->tail->next = q;
	p->tail = q;
	p->len++;
}
void delete_node(list *p,int num)             //删除节点
{
	node q,r;
	q = p->head;
	for(int n = 1;n++ < num;q = q->next);
	r=q->next;
	q->next=r->next;
	if(num == p->len)
	{
		p->tail = q;
	}
	free(r);
	p->len--;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值