分别利用线性表的顺序存储形式和链式存储形式,按照出列的顺序印出各人的编号。文末贴出了源代码
为实现上述功能,可选用顺序存储结构和链式存储结构,为此需要两个抽象数据类型。线性表抽象数据类型的定义为:
ADT List {
数据对象:D={ ai | ai ∈ ElemSet, i=1,2,3,……,n,n≥0}
数据关系:R1={<ai-1,ai>,ai-1,ai∈ D, i=2,3……n,n≥0}
基本操作:
InitList(&L)
操作结果:构造一个空的线性表L。
DestoryList(&L)
初始条件:线性表L已存在。
操作结果:销毁线性表L。
ClearList(&L)
初始条件:线性表L已存在。
操作结果:将L重置为空表。
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。
PriorElem ( L, cur _ e, &pre_e )
初始条件:线性表L已存在。
操作结果:若cur_e是L的数据元素且不是第1个,则用pre _e返回它的前驱,否则操作失败。
NextElem ( L, cur_ e, &next_e )
初始条件:线性表L已存在。
操作结果:若cur_e是L的数据元素且不是最后一个,则用next _ e返回它的后继,否则操作失败。
GrtElem(L , i , &e)
初始条件:线性表L已存在,1≤i≤ListLength(L)+1。
操作结果:用e返回L中第i个数据元素的值。
ListEmpty (L)
初始条件:线性表L已存在。
操作结果:若L 为空表,则返回TRUE,否则返回 FALSE。
ListLength (L)
初始条件:线性表L已存在。
操作结果:返回L中数据元素个数。
LocateElem ( L,e, compare() )
初始条件:线性表L已存在,compare()是判定函数。
操作结果:返回L中第1个与e满足关系compare()的数据元素的位序。若这样的数据元素不存在,则返回值0。
ListTraverse ( L,visit())
初始条件:线性表L已存在。
操作结果:依次对L的每个数据元素调用函数 visit()。一旦visit()失败,则操作失败。
}
ADT List
int main()
{
初始化;
接受命令;
处理命令;
}
2)线性表单元模块—实现线性表的抽象数据类型;
3)约瑟夫环单元模块—实现将成员存储在线性表中,并将线性表中的成员按指定顺序出队;
各模块之间的调用关系如下:
1) 元素类型
#define ElemType people //元素类型
typedef struct
{
int peopleID;
int data;
}people;
2) 所用到的线性表基本操作
typedef struct
{
ElemType *elem;
int length;
int listsize;
} SqList;
Status InitList_Sq(SqList &L,int LIST_INIT_SIZE);
// 构造一个空的线性表L。
void print_Sq(SqList &L);
//打印线性表中所有元素
Status DeleteK(SqList &a,int i,int k);
//从线性表a中删除第i个元素起的k个元素
Status ListInsert_Sq(SqList &L, int i, ElemType e);
//若线性表L存在,将元素e插入到L第i个位置
Status ListDelete_Sq(SqList &L,int i,ElemType &e);
//若线性表L以及第i个元素存在,将其从表中删除并保存到e中
3) 程序源代码
/*库函数*/
#include
#include
#include
#include
using namespace std;
/*宏定义*/
#define LISTINCREMENT 10
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define ElemType people
/*线性表定义*/
typedef int Status;
typedef struct
{
int peopleID;
int data;
}people;
typedef struct
{
ElemType *elem;
int length;
int listsize;
} SqList;
/*函数声明*/
Status InitList_Sq(SqList &L,int LIST_INIT_SIZE);// 构造一个空的线性表L。
void print_Sq(SqList &L);
Status DeleteK(SqList &a,int i,int k);//2-10 从线性表a中删除第i个元素起的k个元素
Status ListInsert_Sq(SqList &L, int i, ElemType e);
Status ListDelete_Sq(SqList &L,int i,ElemType &e);
Status Josephus(int peopleNum,int firstdata);
int main()
{
cout<<"线性表(数组)解决约瑟夫问题\n";
cout<<"请确定人数\n";
int peopleNum;
int firstdata;
peopleNum=60000;
//firstdata=peopleNum/2;
cin>>peopleNum;
cout<<"请确定初始密码\n";
cin>>firstdata;
clock_t start, stop;
double duration;
start=clock();
int result=Josephus(peopleNum,firstdata);
stop=clock();
duration=((double)(stop-start))/CLK_TCK;
if(result==OK)
cout<<"执行成功"<<endl;
else
cout<<"执行失败"<<endl;
printf("线性表(数组)算法(peopleNum=%d,firstdata=%d)花费时间为%fs\n",peopleNum,firstdata,duration);
return 0;
}
Status InitList_Sq(SqList &L,int LIST_INIT_SIZE)
{
L.elem = (ElemType *)malloc(LIST_INIT_SIZE*sizeof(ElemType));
if (!L.elem) return OK; // 存储分配失败
L.length = 0; // 空表长度为0
L.listsize = LIST_INIT_SIZE; // 初始存储容量
return OK;
} // InitList_Sq
void print_Sq(SqList &L)
{
cout<<"编号\t密码"<<endl;
for(int i=0;i<L.length;i++) cout<<L.elem[i].peopleID<<"\t"<<L.elem[i].data<<endl;
}
Status DeleteK(SqList &a,int i,int k)//2-10 从线性表a中删除第i个元素起的k个元素
{
if(i<1||k<0||i+k>a.length) return INFEASIBLE ;
else
{
for(int j=i-1;j<i-1+k;j++)
{
a.elem[j]=a.elem[j+k];
a.length--;
}
return OK;
}
}
Status ListInsert_Sq(SqList &L, int i, ElemType e)
{ // 算法2.4
// 在顺序线性表L的第i个元素之前插入新的元素e,
// i的合法值为1≤i≤ListLength_Sq(L)+1
ElemType *p;
if (i < 1 || i > L.length+1) return ERROR; // i值不合法
if (L.length >= L.listsize)
{ // 当前存储空间已满,增加容量
ElemType *newbase = (ElemType *)realloc(L.elem,
(L.listsize+LISTINCREMENT)*sizeof (ElemType));
if (!newbase) return ERROR; // 存储分配失败
L.elem = newbase; // 新基址
L.listsize += LISTINCREMENT; // 增加存储容量
}
ElemType *q = &(L.elem[i-1]); // q为插入位置
for (p = &(L.elem[L.length-1]); p>=q; --p) *(p+1) = *p;
// 插入位置及之后的元素右移
*q = e; // 插入e
L.length=L.length+1;; // 表长增1
return OK;
} // ListInsert_Sq
Status ListDelete_Sq(SqList &L,int i,ElemType &e)
{
if((i<1)||(i>L.length))
return ERROR;
ElemType *p=&(L.elem[i-1]);
e=*p;
ElemType *q=L.elem+L.length-1;
for(++p;p<=q;++p)
*(p-1)=*p;
--L.length;
return OK;
}
Status Josephus(int peopleNum,int firstdata)
{
if(peopleNum<=0) return ERROR;
SqList L;
InitList_Sq(L,peopleNum);
if(firstdata==0) return ERROR;
int a,b;
people x;
srand((int)time(NULL));
for(int i=0;i<peopleNum;i++)
{
a = rand()%peopleNum+1;
b=rand()%peopleNum;
x.data=a*pow(-1,b);
x.peopleID=i+1;
ListInsert_Sq(L,i+1,x);
}
print_Sq(L);
cout<<"现在开始\n";
cout<<"编号\t密码"<<endl;
people e;
int outpeople,lastposition=0;
if(firstdata>0)
outpeople=firstdata%peopleNum;
else
outpeople=(peopleNum+2-((-1)*firstdata)%peopleNum)%peopleNum;
while(L.length>0)
{
if(outpeople==0) outpeople=L.length;
ListDelete_Sq(L, outpeople,e);
if(L.length)
{
if(e.data>0)
{
lastposition=outpeople%L.length;
outpeople=(e.data+lastposition-1)%L.length;
}
else
{
if(outpeople==1) lastposition=L.length;
else
lastposition=outpeople-1;
outpeople=e.data+lastposition-1;
if(outpeople>0) outpeople=outpeople%L.length;
else outpeople=(L.length+2-((-1)*outpeople)%L.length)%L.length;
}
}
cout<<e.peopleID<<"\t"<<e.data<<"\n";
}
return OK;
}
#define ElemType int
2) 所用到的线性表的基本操作
typedef struct DuLNode
{
ElemType data;
int number; //记录顺时针的编号
struct DuLNode *prior;
struct DuLNode *next;
}DuLNode, *DuLinkList;
void print(DuLinkList L);
//打印双向循环链表的每个元素
Status InitDuLinkList(DuLinkList &head);
//构建双向循环链表
Status InsertDuLinkList(DuLinkList &head,ElemType e);
//若双向循环链表head存在,向表头插入数据e
Status DelDuLinkList(DuLinkList &head,int m,ElemType &e);
//若存在,则删除并返回第m个结点的数据,并把头结点赋给删掉结点的下一个
3) 源代码
/*头文件*/
#include
#include
#include
#include
using namespace std;
/*宏定义*/
#define ElemType int
#define OK 1
#define INFEASIBLE -1
#define ERROR -1
/*双向循环链表定义*/
typedef struct DuLNode
{
ElemType data;
int number; //记录顺时针的编号
struct DuLNode *prior;
struct DuLNode *next;
}DuLNode, *DuLinkList;
typedef int Status;
/*函数声明*/
void print(DuLinkList L);
Status InitDuLinkList(DuLinkList &head); //构建双向循环链表
Status InsertDuLinkList(DuLinkList &head,ElemType e); //向循环链表插入数据e
Status DelDuLinkList(DuLinkList &head,int m,ElemType &e); //删除并返回第m个结点的数据,并把头结点赋给删掉结点的下一个
Status Josephus(int n,int m); //报数大于0,则顺时针数,确定出栈人后,出栈人顺时针下一位继续数
//报数小于0,则逆时针数,确定出栈人后,出栈人逆时针下一位继续数
int main()
{
clock_t start, stop;
int m,n;
//n=10000;
// m=n/2;
cout<<"解决约瑟夫环问题\n";
cout<<"请输入人数n:\n";
cin>>n;
if(n<=0) return ERROR;
cout<<"请指定初值m:\n";
cin>>m;
double duration;
start=clock();
int result=Josephus(n,m);
stop=clock();
duration=((double)(stop-start))/CLK_TCK;
if(result==OK)
cout<<"执行成功"<<endl;
else
cout<<"执行失败"<<endl;
printf("双向循环链表算法花费时间为%fs\n",duration);
return 0;
}
Status InitDuLinkList(DuLinkList &head) //构建双向循环链表
{
//创建一个首元节点,链表的头指针为head
head=(DuLinkList)malloc(sizeof(DuLNode));
//对节点进行初始化
head->prior=NULL;
head->next=NULL;
return OK;
}
Status InsertDuLinkList(DuLinkList &head,ElemType e) //向循环链表插入数据e
{
if(head->next==NULL||head->prior==NULL) //如果链表为空,则直接给head节点赋值
{
head->data=e;
head->number=1;
head->next=head;
head->prior=head;
return OK;
}
//创建新的节点并初始化
DuLinkList body=(DuLinkList)malloc(sizeof(DuLNode));
if(!body) return ERROR;
body->data=e;
head->prior->next=body;
body->prior=head->prior;
body->number=((body->prior)->number)+1;
body->next=head;
head->prior=body;
return OK;
}
Status DelDuLinkList(DuLinkList &head,int m,ElemType &e) //删除并返回第m个结点的数据,并把头结点赋给删掉结点的下一个
{
int number;
if(head->next==NULL&&head->prior==NULL) return ERROR;
if(head->next==head&&head->prior==head)
{
e=head->data;
number=head->number;
head->next=head->prior=NULL;
printf("%d\t%d\n",number,e);
return OK;
}
int count;
DuLinkList body=head,temp;
if(m>0)
{
count=1;
while(count<m)
{
head=head->next;
count++;
}
e=head->data;
number=head->number;
printf("%d\t%d\n",number,e);
head->prior->next=head->next;
head->next->prior=head->prior;
temp=head;
head=head->next;
free(temp);
return OK;
}
else if(m<0)
{
count=-1;
while(count>m)
{
head=head->prior;
count--;
}
e=head->data;
number=head->number;
printf("%d\t%d\n",number,e);
head->prior->next=head->next;
head->next->prior=head->prior;
temp=head;
head=head->prior;
free(temp);
return OK;
}
else //m==0
head=head->prior;
e=head->data;
number=head->number;
printf("%d\t%d\n",number,e);
head->prior->next=head->next;
head->next->prior=head->prior;
temp=head;
head=head->next;
free(temp);
return OK;
}
void print(DuLinkList L)
{
DuLinkList head=L;
while(L->next!=head)
{
cout<<L->number<<"\t";
cout<<L->data;
cout<<endl;
L=L->next;
}
cout<<L->number<<"\t";
cout<<L->data;
cout<<endl;
}
Status Josephus(int n,int m) //报数大于0,则顺时针数,确定出队人后,出对人顺时针下一位继续数
//报数小于0,则逆时针数,确定出栈人后,出栈人逆时针下一位继续数
{
if(n<=0) return ERROR;
int e;
DuLinkList L;
InitDuLinkList(L);
int a,b,x;
srand((int)time(NULL));
/**/for(int i=0;i<n;i++)
{
a = rand()%n+1;
b=rand()%n;
x=a*pow(-1,b);
InsertDuLinkList(L,x);
}
printf("已随机生成%d个人的数据,顺时针依次为:\n",n);
print(L);
cout<<"出栈顺序依次为:"<<endl;
cout<<"编号\t数值\n";
while(L->next)
{
if(m>0) m=m%n;
else if(m<0)
{
m=((-m)%n)*(-1);
}
else return ERROR;
DelDuLinkList(L,m,m);
n--;
}
return OK;
}