约瑟夫问题的几种解法

题目

【论述题】
分别用顺序表、循环链表完成约瑟夫问题

(参考步骤:顺序表(链表步骤类似)

//1定义数据类型

#define  maxsize 100
 typedef struct node
 { 

....
 }SeqList,*PSeqList;

//定义创建顺序表函数

PSeqList CreatList(int n){

......

}

//定义删除元素函数

Delete_SeqList(PSeqList L,int i){//删除元素

}

//定义销毁顺序表函数

Destroy_SeqList(PSeqList *L){//销毁顺序表

}

//定义约瑟夫求解函数

int josephus_SeqList(PSeqList yosephus_seq,int s,int m){//约瑟夫算法

}

//定义主函数

void main(){//主函数

}

1、先看循环链表问题解法

这里先不用老师提供的框架,先用简单流水过程理解思想,不考虑代码的重用性

#include<stdio.h>  
//#include<stdlib.h>
#include<malloc.h>  
int i;//for循环需要的元素 
//由于先追求了解算法思想,故这里不采用用户输入人数和杀人数字 
int num=10,killNum=3;//总人数,杀人数字
//定义结构体 
typedef struct List  
{  
    int  data;  
    struct List *next;  
}LinkList,*PLinkList;  
   
   
int main()  
{  
    PLinkList beg,p1,p2;
    //建立循环链表
    /*基本思想:
    0;创建头结点
    1;for循环创建其余n-1个节点,并将每一个节点串成一个联表(此时还不是循环链表)
    2;将链表尾节点指向头结点beg 
	*/
    beg=(PLinkList)malloc(sizeof(LinkList));
    beg->data=1;
    p1=beg;
    for(i=1;i<num;i++){
    	p2=(PLinkList)malloc(sizeof(LinkList));
    	p2->data=i+1;//使得链表中的元素按照1到n 
    	p1->next=p2;
    	p1=p2;
    	
	}
	p1->next=beg;//最后一个节点指向头结点 
	
	//#测试代码#打开注释,测试所有节点是否可以正确循环 
//	for( i=0;i<num;i++){//输出所有节点的data,并将beg指针指向循环链表最后创建的那个节点 
// 	printf("%d\t",beg->data);
// 	beg=beg->next;
//	}
//	printf("%d\t",beg->data);//若能输出1,则表示最后一个节点能正常指向头结点,即可正常循环 


	/*杀人思想:
	由于beg一开始就指向data为1的节点,所以要杀报数第killNum的人,实际上只要将beg指向要杀的那个人的前面那个人,
	然后用一个指针(p3)指向要杀人,然后将此时beg的next指向要杀的人的后面(p3->next),再杀人free(p1)就行了。
	(这样做的原因是防止杀掉人后前一个人无法正常指向杀掉人的后面,导致循环中断) 
	*/ 
	PLinkList p3; 
	while(beg->next!=beg){
		//for循环使beg指向要删除的前一个 
		for(i=1;i<killNum-1;i++){
			beg=beg->next;
		}
		//输出被杀号码 
		printf("%d\t",beg->next->data); 
		//开始杀人 
		p3=beg->next; 
		beg->next=p3->next;
		free(p3);
		//已杀死,接下来应该从beg后面开始数
		beg=beg->next; 
		
	} //退出循环时只有一个人了 
	//输出该人号码,并释放空间 
	printf("%d\t",beg->data); 
	free(beg);
    return 0;   
} 

使用老师给的框架(由于老师给的框架有的不知道什么意思,所以擅自改了一点)

使用了大量上面的代码,复制粘贴,注意函数定义以及返回值就可以了;

#include<stdio.h>  
//#include<stdlib.h>
#include<malloc.h>
#define  maxsize 100
int i;//for循环需要的元素 

typedef struct node
{
	int data;
	struct node *next;
}SeqList,*PSeqList;
PSeqList beg,p1,p2,p3,p4;
//定义创建链表函数

PSeqList CreatList(int n){
	beg=(PSeqList)malloc(sizeof(SeqList));
    beg->data=1;
    p1=beg;
    for(i=1;i<n;i++){
    	p2=(PSeqList)malloc(sizeof(SeqList));
    	p2->data=i+1;//使得链表中的元素按照1到n 
    	p1->next=p2;
    	p1=p2;
    }
	p1->next=beg;
	return beg;
}

//定义删除元素函数
//由于不清楚这里的L和i指的是什么,且当做L为已经从L指向的这个人开始数,数第i个人kill(偷懒,将i改成killNum,直接用上面的代码)
void Delete_SeqList(PSeqList L,int killNum){
	while(beg->next!=beg){
		//for循环使beg指向要删除的前一个 
		for(i=1;i<killNum-1;i++){
			beg=beg->next;
		}
		//输出被杀号码 
		printf("%d\t",beg->next->data); 
		//开始杀人 
		p3=beg->next; 
		beg->next=p3->next;
		free(p3);
		//已杀死,接下来应该从beg后面开始数
		beg=beg->next; 
		
	} //退出循环时只有一个人了 
	//输出该人号码,并释放空间 
	printf("\n胜利者:"); 
	printf("%d\t",beg->data); 
	free(beg); 
}
//定义约瑟夫求解函数
//认为 yosephus_seq是循环链表头,s为从第几个人开始数,m是killNum 
void josephus_SeqList(PSeqList yosephus_seq,int s,int m){//约瑟夫算法
	//for循环使beg指向第s个人,从他开始数
	for(i=1;i<s;i++){
		beg=beg->next;
	}
	//调用杀人函数  
	Delete_SeqList(beg,m); 
}

//定义主函数

void main(){//主函数
	//调用链表创建函数
	PSeqList p=CreatList(maxsize);
	//开始杀人
	josephus_SeqList(p,1,3);
	 
}

2、再看顺序表问题解法

在某仙女的指导下完成

#include<stdio.h>
#include<stdlib.h>
#define  maxsize 100

typedef struct node
{
	int data[maxsize];
	int length;
}SeqList,*PSeqList;

//定义创建顺序表函数
PSeqList CreatList(int n){
	int i;
	PSeqList PL;
	PL=(PSeqList)malloc(sizeof(SeqList));
	if(PL)
		PL->length=n;
	
	for(i=0;i<n;i++){
		PL->data[i]=i+1;
	}
	return  PL;
}
//定义删除元素函数
int Delete_SeqList(PSeqList L,int i){//删除下标为i的元素

	//三部曲:表空、位置不合法、删除元素
	if(!L)
	{
		printf("表是空的不能删除!");
		return (-1);
	}
		
	else if(i<0||i>L->length-1)
		printf("删除元素的位置不合法");
	else
		for(;i<L->length-1;i++)
			L->data[i]=L->data[i+1];
		L->length--;

		return (1);

}
//定义销毁顺序表函数
void Destroy_SeqList(PSeqList L){//销毁顺序表
	
	free(L);
	L=NULL;
}

//定义约瑟夫求解函数
int josephus_SeqList(PSeqList yosephus_seq,int s,int m){//约瑟夫算法,起始序号为s,计数值为m
	int i,s1,w;
	if(!yosephus_seq->length){
		printf("表是空的");
		return 0;	
	}
	
	s1=s-1;//s的下标
	for(i=yosephus_seq->length;i>0;i--)
	{
		s1=(s1+m-1)%i;
		w=yosephus_seq->data[s1];
		printf("%d\t",w);
		Delete_SeqList(yosephus_seq,s1);
	}
	return (1);
	 
}
//定义主函数
void main(){//主函数
	PSeqList myP=CreatList(20);
	josephus_SeqList(myP,1,3);
	
}


  • 6
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值