题目
【论述题】
分别用顺序表、循环链表完成约瑟夫问题
(参考步骤:顺序表(链表步骤类似)
//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);
}