问题及描述:
约瑟夫双向生死问题是建立在约瑟夫问题基础上,正向计数后反向计数,然后在正向计数,然后在正向计数。具体描述如下:30个旅客同乘一条船,因为严重过载,加上风浪高大,危险万分;因此船长告诉乘客,只有将全船一半的旅客投入海中,其余人才能幸免遇难。无奈,大家只得同意这种方法,并议定30个人围成一圈,由第一个人开始,顺时针依次报数,数到第九人,便把他投入大海中,然后从他的下一个人数起,逆时针数到第5人,将他投入大海,然后从他逆时针的下一个人数起,顺时针数到第9人,再将他投入大海,如此循环,直到剩下15个乘客为止。问那些乘客是将被扔下大海的位置。
顺序表方式:
list.h
#define MaxSize 50
typedef int ElemType;
typedef struct
{
ElemType data[MaxSize];
int length;
} SqList;
void CreateList(SqList *&L, ElemType a[], int n);//用数组创建线性表
void InitList(SqList *&L);//初始化线性表InitList(L)
void DestroyList(SqList *&L);//销毁线性表DestroyList(L)
bool ListEmpty(SqList *L);//判定是否为空表ListEmpty(L)
int ListLength(SqList *L);//求线性表的长度ListLength(L)
void DispList(SqList *L);//输出线性表DispList(L)
bool GetElem(SqList *L,int i,ElemType &e);//求某个数据元素值GetElem(L,i,e)
int LocateElem(SqList *L, ElemType e);//按元素值查找LocateElem(L,e)
bool ListInsert(SqList *&L,int i,ElemType e);//插入数据元素ListInsert(L,i,e)
bool ListDelete(SqList *&L,int i,ElemType &e);//删除数据元素ListDelete(L,i,e)
list.cpp (对算法的listdelete进行修改)
#include <stdio.h>
#include <malloc.h>
#include "list.h"
//用数组创建线性表
void CreateList(SqList *&L, ElemType a[], int n)
{
int i;
L=(SqList *)malloc(sizeof(SqList));
for (i=0; i<n; i++)
L->data[i]=a[i];
L->length=n;
}
//初始化线性表InitList(L)
void InitList(SqList *&L) //引用型指针
{
L=(SqList *)malloc(sizeof(SqList));
//分配存放线性表的空间
L->length=0;
}
//销毁线性表DestroyList(L)
void DestroyList(SqList *&L)
{
free(L);
}
//判定是否为空表ListEmpty(L)
bool ListEmpty(SqList *L)
{
return(L->length==0);
}
//求线性表的长度ListLength(L)
int ListLength(SqList *L)
{
return(L->length);
}
//输出线性表DispList(L)
void DispList(SqList *L)
{
int i;
if (ListEmpty(L)) return;
for (i=0; i<L->length; i++)
printf("%d ",L->data[i]);
printf("\n");
}
//求某个数据元素值GetElem(L,i,e)
bool GetElem(SqList *L,int i,ElemType &e)
{
if (i<1 || i>L->length) return false;
e=L->data[i-1];
return true;
}
//按元素值查找LocateElem(L,e)
int LocateElem(SqList *L, ElemType e)
{
int i=0;
while (i<L->length && L->data[i]!=e) i++;
if (i>=L->length) return 0;
else return i+1;
}
//插入数据元素ListInsert(L,i,e)
bool ListInsert(SqList *&L,int i,ElemType e)
{
int j;
if (i<1 || i>L->length+1)
return false; //参数错误时返回false
i--; //将顺序表逻辑序号转化为物理序号
for (j=L->length; j>i; j--) //将data[i..n]元素后移一个位置
L->data[j]=L->data[j-1];
L->data[i]=e; //插入元素e
L->length++; //顺序表长度增1
return true; //成功插入返回true
}
//删除数据元素ListDelete(L,i,e)
bool ListDelete(SqList *&L,int i,ElemType &e)
{
int j;
if (i<0 || i>L->length) //参数错误时返回false
return false;
if(i==0) //
i=L->length; // 对j=0 的修改(2行)
i--; //将顺序表逻辑序号转化为物理序号
e=L->data[i];
for (j=i; j<L->length-1; j++) //将data[i..n-1]元素前移
L->data[j]=L->data[j+1];
L->length--; //顺序表长度减1
return true; //成功删除返回true
}
main.cpp
#include "list.h"
#include <stdio.h>
void main()
{
SqList *sq;
int n,f,s; //n代表船上的总人数,f代表第一次顺时针方向数的个数,s代表第二次逆时针的个数
int i,j=1; // j记录当前位置
printf("请输入船上的总人数:\n");
scanf("%d",&n);
printf("请输入顺时针方向的人数:\n");
scanf("%d",&f);
printf("请输入逆时针方向的人数:\n");
scanf("%d",&s);
printf("请输入开始位置的人的序号:\n");
scanf("%d",&j);
ElemType x[1000],e;
for(i=0;i<n;i++)
x[i]=i+1; //初始化数组
CreateList(sq, x, n); // 创建线性表
for(i=0;i<n/2;i++) //从第一个位置开始,第一次顺时针9人,第二次逆时针5人如此循环
{
if(i%2==0) // 以奇偶区分顺、逆时针方向
{
j=((j+f-1)+sq->length)%sq->length; //从第一个位置开始,顺时针数9个位置,应移动8个位置8
if(j==0)
j=sq->length; // j=0 表示为最后一个元素
if(ListDelete(sq,j,e))
printf("第%d次出局的序号为:%d\n",i+1,e); //删除并输出该元素
j=j%sq->length; // 结果修正( 处理j为最后一个元素的情况 下一次j开始时是从第一个位置 )
}
//顺时针的方法下一次开始的位置为j(在删除元素时是一次从下一个位置补上来)
else // 逆时针移动5个位置
{
j=((j-(s-1))+sq->length)%sq->length; //从第一个位置开始,逆时针数5个位置,应为移动4个位置
if(j==0)
j=sq->length;
if(ListDelete(sq,j,e))
printf("第%d次出局的序号为:%d\n",i+1,e); //删除并输出该元素
j=(j-1)%sq->length; // 结果修正(j为第一个元素)
} //逆时针的方法下一次开始的位置为j-1
}
printf("剩余的序号为:\n");
DispList(sq);
}
运行结果:
循环双链表方式:
cdlinklist.h
#ifndef CDLINKLIST_H_INCLUDED
#define CDLINKLIST_H_INCLUDED
//循环双链表基本运算函数
typedef int ElemType;
typedef struct DNode //定义双链表结点类型
{
ElemType data;
struct DNode *prior; //指向前驱结点
struct DNode *next; //指向后继结点
} CDLinkList;
void CreateListF(CDLinkList *&L,ElemType a[],int n); //头插法建立循环双链表
void CreateListR(CDLinkList *&L,ElemType a[],int n); //尾插法建立循环双链表
void InitList(CDLinkList *&L); //初始化循环双链表
void DestroyList(CDLinkList *&L); //销毁
bool ListEmpty(CDLinkList *L); //判断是否为空
int ListLength(CDLinkList *L); //求链表长度
void DispList(CDLinkList *L); //输出链表
bool GetElem(CDLinkList *L,int i,ElemType &e); //取链表元素
int LocateElem(CDLinkList *L,ElemType e); //查找元素
bool ListInsert(CDLinkList *&L,int i,ElemType e); //插入节点
bool ListDelete(CDLinkList *&L,int i,ElemType &e); //删除节点
#endif // CDLINKLIST_H_INCLUDED
cdlinklist.cpp
#include <stdio.h>
#include <malloc.h>
#include "cdlinklist.h"
void CreateListF(CDLinkList *&L,ElemType a[],int n) //头插法建立循环双链表
{
CDLinkList *s;
int i;
L=(CDLinkList *)malloc(sizeof(CDLinkList)); //创建头结点
L->next=NULL;
for (i=0; i<n; i++)
{
s=(CDLinkList *)malloc(sizeof(CDLinkList));//创建新结点
s->data=a[i];
s->next=L->next; //将*s插在原开始结点之前,头结点之后
if (L->next!=NULL) L->next->prior=s;
L->next=s;
s->prior=L;
}
s=L->next;
while (s->next!=NULL) //查找尾结点,由s指向它
s=s->next;
s->next=L; //尾结点next域指向头结点
L->prior=s; //头结点的prior域指向尾结点
}
void CreateListR(CDLinkList *&L,ElemType a[],int n) //尾插法建立循环双链表
{
CDLinkList *s,*r;
int i;
L=(CDLinkList *)malloc(sizeof(CDLinkList)); //创建头结点
L->next=NULL;
r=L; //r始终指向尾结点,开始时指向头结点
for (i=0; i<n; i++)
{
s=(CDLinkList *)malloc(sizeof(CDLinkList));//创建新结点
s->data=a[i];
r->next=s;
s->prior=r; //将*s插入*r之后
r=s;
}
r->next=L; //尾结点next域指向头结点
L->prior=r; //头结点的prior域指向尾结点
}
void InitList(CDLinkList *&L) //初始化循环双链表
{
L=(CDLinkList *)malloc(sizeof(CDLinkList)); //创建头结点
L->prior=L->next=L;
}
void DestroyList(CDLinkList *&L) //销毁
{
CDLinkList *p=L,*q=p->next;
while (q!=L)
{
free(p);
p=q;
q=p->next;
}
free(p);
}
bool ListEmpty(CDLinkList *L) //判断是否为空
{
return(L->next==L);
}
int ListLength(CDLinkList *L) //求链表长度
{
CDLinkList *p=L;
int i=0;
while (p->next!=L)
{
i++;
p=p->next;
}
return(i);
}
void DispList(CDLinkList *L) //输出链表
{
CDLinkList *p=L->next;
while (p!=L)
{
printf("%d ",p->data);
p=p->next;
}
printf("\n");
}
bool GetElem(CDLinkList *L,int i,ElemType &e) //取链表元素
{
int j=0;
CDLinkList *p;
if (L->next!=L) //双链表不为空表时
{
if (i==1)
{
e=L->next->data;
return true;
}
else //i不为1时
{
p=L->next;
while (j<i-1 && p!=L)
{
j++;
p=p->next;
}
if (p==L)
return false;
else
{
e=p->data;
return true;
}
}
}
else //双链表为空表时
return 0;
}
int LocateElem(CDLinkList *L,ElemType e) //查找元素
{
int n=1;
CDLinkList *p=L->next;
while (p!=NULL && p->data!=e)
{
n++;
p=p->next;
}
if (p==NULL)
return(0);
else
return(n);
}
bool ListInsert(CDLinkList *&L,int i,ElemType e) //插入节点
{
int j=0;
CDLinkList *p=L,*s;
if (p->next==L) //原双链表为空表时
{
s=(CDLinkList *)malloc(sizeof(CDLinkList)); //创建新结点*s
s->data=e;
p->next=s;
s->next=p;
p->prior=s;
s->prior=p;
return true;
}
else if (i==1) //原双链表不为空表但i=1时
{
s=(CDLinkList *)malloc(sizeof(CDLinkList)); //创建新结点*s
s->data=e;
s->next=p->next;
p->next=s; //将*s插入到*p之后
s->next->prior=s;
s->prior=p;
return true;
}
else
{
p=L->next;
while (j<i-2 && p!=L)
{
j++;
p=p->next;
}
if (p==L) //未找到第i-1个结点
return false;
else //找到第i-1个结点*p
{
s=(CDLinkList *)malloc(sizeof(CDLinkList)); //创建新结点*s
s->data=e;
s->next=p->next; //将*s插入到*p之后
if (p->next!=NULL) p->next->prior=s;
s->prior=p;
p->next=s;
return true;
}
}
}
bool ListDelete(CDLinkList *&L,int i,ElemType &e) //删除节点
{
int j=0;
CDLinkList *p=L,*q;
if (p->next!=L) //原双链表不为空表时
{
if (i==1) //i==1时
{
q=L->next; //删除第1个结点
e=q->data;
L->next=q->next;
q->next->prior=L;
free(q);
return true;
}
else //i不为1时
{
p=L->next;
while (j<i-2 && p!=NULL)
{
j++;
p=p->next;
}
if (p==NULL) //未找到第i-1个结点
return false;
else //找到第i-1个结点*p
{
q=p->next; //q指向要删除的结点
if (q==NULL) return 0; //不存在第i个结点
e=q->data;
p->next=q->next; //从单链表中删除*q结点
if (p->next!=NULL) p->next->prior=p;
free(q); //释放*q结点
return true;
}
}
}
else
return false; //原双链表为空表时
}
main.cpp
#include <malloc.h>
#include <stdio.h>
#include "cdlinklist.h"
void main()
{
int n,f,s,st,m=1; //n代表船上的总人数,f代表第一次顺时针方向数的个数,s代表第二次逆时针的个数,a为开始位置的人的序号
CDLinkList *dl,*p; //*dl 为双链表的头指针 *p指向当前指针
printf("请输入船上的总人数:\n"); // 在创建循环双链表的时候,实际创建的有n+1个元素 头结点也算在其中
scanf("%d",&n);
printf("请输入顺时针方向的人数:\n");
scanf("%d",&f);
printf("请输入逆时针方向的人数:\n");
scanf("%d",&s);
printf("请输入开始位置的人的序号:\n");
scanf("%d",&st);
int a[1000];
int i;
for(i=0;i<n;i++)
a[i]=i+1; // 初始化数组
InitList(dl);
CreateListR(dl, a, n); //尾插法建立双链表
p=dl->next; //指向表头节点
while(m<st) //指向开始位置的节点
{
p=p->next;
m++;
}
// 删除过程
for(i=0;i<n/2;i++) //从第一个位置开始,第一次顺时针9人,第二次逆时针5人如此循环
if(i%2==0) // 以奇偶区分顺、逆时针方向
{
CDLinkList *a;
int j=0;
while(j<f-1) //顺时针数9个人,即从第一个位置开始移动8个位置
{
p=p->next;
if(p==dl)
j--; // 运行到头结点时在进行一次移动
j++;
}
printf("出局的序号为:%d\n",p->data);
a=p;
a->prior->next=a->next;
a->next->prior=a->prior;
p=a->next; // 下一次节点开始的位置(顺时针)
free(a);
}
else // 逆时针移动5个位置
{
CDLinkList *a;
int j=0;
while(j<s-1) //逆时针数5个人,即从第一个位置开始移动4个位置
{
p=p->prior;
if(p==dl)
j--;
j++;
}
printf("出局的序号为:%d\n",p->data);
a=p; //删除节点
a->prior->next=a->next;
a->next->prior=a->prior;
p=a->prior; // 下一次节点开始的位置(逆时针)
free(a);
}
printf("剩余的序号为:\n");
DispList(dl); //输出剩余的序号
}
运行结果: