顺序表和单循环链表实现约瑟夫环

约瑟夫环
[问题描述]
  约瑟夫(Joseph)问题的一种描述是:编号为1,2,…,n的n个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。一开始任选一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始顺序报数,报到m时停止报数。报m的人出列,将他的密码作为新的m值,从他在顺时针方向上的下一个人开始重新从1报数,如此下去,直至所有人全部出列为止。试设计一个程序求出出列顺序。
[基本要求]
  利用单向循环链表存储结构模拟此过程,按照出列的顺序印出各人的编号。
[测试数据]
由学生任意指定。
如:m的初值为20;n的值为7;密码:3,1,7,2,4,8,4;
(正确的输出结果应为6,1,4,7,2,3,5)。
(报告上要求写出多批数据测试结果)
[实现提示]
程序运行后首先要求用户输入初始报数上限值m,人数n,(设n≤30)。然后输入各人的密码。
[选作内容]
  向上述程序中添加在顺序结构上实现的部分。

单循环链表实现:

单链表的创建与基本操作

实现:
DeleteNode(LinkList &L,LinkList &s,int &m)函数实现了删除链表中的s结点并更新m的值,并添加了输出s结点编号的功能。
Josephus():不断寻找第m个结点,如果是头结点就跳过,找到后更新m的值并删除该结点,然后进行下一次寻找,直到链表中只有头结点为止。

typedef struct LNode
{
	int data;//存放密码
	int num;//存放编号
	LNode* next;
}LNode,*LinkList;
void InitList(LinkList &L)//头结点初始化
{
	L=new LNode;
	L->next=NULL;
}
void CreateListTail(LinkList &L,int n)//尾插法创建单循环链表
{
	LinkList p,r;
	L=new LNode;
	r=L;
	for (int i = 1; i <= n; i++)
	{
		p=new LNode;
		cin>>p->data;
		p->num=i;
		r->next=p;
		r=p;
	}
	r->next=L;//循环链表
}
void DeleteNode(LinkList &L,LinkList &s,int &m)//删除指定位置的结点
{
	if(s==L) return ;
	else 
	{
		LinkList q=L;
	while (q->next!=s)
	{
		q=q->next;
	}
	q->next=s->next;
	m=s->data;
	cout<<s->num<<' ';
	delete s;
	}
}
void Josephus()//算法实现部分
{
	LinkList L;
	InitList(L);//20 7 3 1 7 2 4 8 4
	int m,n;
	cin>>m>>n;
	CreateListTail(L,n);
	LinkList p=L->next;
	while (p)
	{
		if(p==L) break;
		for (int i = 1; i < m; i++)
		{
			p=p->next;
			if(p==L) p=p->next;
		}
		LinkList q=p->next;
		DeleteNode(L,p,m);
		p=q;
		if(p==L) p=p->next;
	}
}

顺序表实现:

顺序表的实现类似于静态数组实现
Josephus1():利用p作为表示数组下标的指针,每次向后查找m就是访问第(p+m-1)%i (i为当前顺序表的长度)个元素,输出其编号num并更新m的值,直到顺序表为空。

#define MAXSIZE 31
typedef struct
{
	int data;//存放密码
	int num;//存放编号
}Jos;
typedef struct
{
	Jos *elem;
	int length;
}SqList;
void InitList(SqList &L)//初始化顺序表
{
	L.elem=new Jos[MAXSIZE];
	if (!L.elem)
	{
		cout<<"false!"<<endl;
		return ;
	}
	L.length=0;
}
void ListInsert(SqList &L,int i,int e)//顺序表插入
{
	if ((i<1)||(i>L.length+1))
	{
		cout<<"false";
		return ;
	}
	if(L.length==MAXSIZE) cout<<"false";
	for (int j = L.length-1; j >= i-1; j--)
	{
		L.elem[j+1]=L.elem[j];
	}
	L.elem[i-1].data=e;
	L.elem[i-1].num=i;
	++L.length;
}
bool ListDelete(SqList &L,int i)//删除节点
{
	if((i<1)||(i>L.length)) 
	{
		cout<<"error"<<endl;
		return false;
	}
	for (int j = i; j <= L.length-1; j++)
	{
		L.elem[j-1]=L.elem[j];
	}
	--L.length;
	//cout<<"success!"<<endl;
	return true;
}
void Josephus1()//算法代码
{                        //样例:20 7 3 1 7 2 4 8 4
	SqList L;
	InitList(L);
	int m,n;
	cin>>m>>n;
	for (int i = 1; i <= n; i++)//输入部分
	{
		int x;
		cin>>x;
		ListInsert(L,i,x);
	}
	int p=0;
	for (int i = L.length; i >= 1; i--)
	{
		p=(p+m-1)%i;
		cout<<L.elem[p].num<<' ';
		m=L.elem[p].data;
		//cout<<"m:"<<m<<endl;
		ListDelete(L,p+1);
	}
}

运行实例

实例一:
20 7 3 1 7 2 4 8 4
6 1 4 7 2 3 5
实例二:
10 5 7 2 6 4 3
5 3 2 1 4

  • 6
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

新西兰做的饭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值