约瑟夫环问题求解!!

Devilxl 2003-10-13 08:08:07
约瑟夫环的问题大家清楚吧,小弟我有急用,自己想了好长时间还是不知道该怎么办好!!希望各位高手给个答案!!谢谢了! !


要求是用单循环链表,对接点建一个结构体!!
请于10月15日前给出答案,谢谢!!!!!!
...全文
427 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
mfcer2 2003-10-21
  • 打赏
  • 举报
回复
to wweixiaoyu:

你问的是一个删除结点的关键性问题!

"--------------------------------------------
pPrv = pCur = *ppHead;
/* 将pPrv初始为指向尾结点,为删除作好准备 */
while (pPrv->next != *ppHead)
pPrv = pPrv->next;
--------------------------------------------
"
在一个循环链表要进行结点删除,一定要在待删除的结点的前一个结点处定位指针,即一定要有一个指定指向待删除结点的前驱.只有这样才有可能用后面的语句"pPrv->next = pCur->next;"//此时pCur是指向待删除的那个结点的;
而上面的语句(我用双引号括起来的几句),就是为这个指向待删除结点的"前驱指针pPrv"进行初始化的.因为我们开始要删除结点时,是从头结点(pCur已经初始指向这个结点了,见最上面的一句)开始试探该结点是否符合删除的条件的.所以一开始pPrv就应指向最后一个结点(注意,程序中是循环链表).这样在进行循环链表的删除之前,经过一系列的初始化语句,pCur指向链表中第一个结点,而pPrv是指向最后一个结点.

再看这里:
" /* 这里是记数,无非是移动iCipher-1趟指针! */
for (iCounter = 1; iCounter < iCipher; iCounter++)
{
pPrv = pCur;
pCur = pCur->next;
}
"
这里是在记数的同时,继续保证pCur指向当前待测结点,而pPrv中保存的是pCur"以前"的值,即pPrv总是指向pCur的前一个结点.如此以来这两个指针总是一前一后,随时为删除结点作好准备.

祝你好运!!!
mfcer2 2003-10-21
  • 打赏
  • 举报
回复
stdlib.h是一个C的头文件,里面有一些相关的函数和常量的声明.

在TC中是这样在stdlib.h文件中写的:"Definitions for common types, variables, and functions."
意思是通用类型,变量,和函数的定义.

我们常用的函数中有malloc, realloc,free,system等都是在这个头文件中声明的,还有NULL,min(a,b),总之很多了.你最好可以自己打开看一看,对于一个初学者常常看相关的头文件是很有益处的!

祝你好运:-D
teddyzhai 2003-10-21
  • 打赏
  • 举报
回复
#include <stdlib.h>
请问MFCER2,这是什么标准库啊,我怎么查不到啊??
wweixiaoyu 2003-10-20
  • 打赏
  • 举报
回复
你好mfcer2!问一个问题

/* 将pPrv初始为指向尾结点,为删除作好准备 */
while (pPrv->next != *ppHead)
pPrv = pPrv->next;

我怎么觉得没有起作用呀!因为后面你马上就pPrv = pCur。
mfcer2 2003-10-20
  • 打赏
  • 举报
回复
不要删了,这已经是很少的了.

我曾经用C++写了一个线性的数据结构类,很大的,比这个大多了.

这上面的已经是很少了.一两百行的程序,真是少的可怜,怎么删?

你教我吧!
TianGuangZao 2003-10-15
  • 打赏
  • 举报
回复
to 楼主:
mfcer2 大大给的明明就是 c 程序呀!怎么会说成 c++ 呢?!也太离谱了点。
感觉已经很不错了,再短就是要改变数据的存储结构了。
本身链表的实现需要占用长度,你可以动动脑筋把 mfcer2 里你觉得罗嗦的几句给去掉。
mfcer2 2003-10-15
  • 打赏
  • 举报
回复
to 楼主:

你要的是单向循环链表程序,就不能短了.我已经尽力写短一点,以免贴子太长,不太好看.
不过用数组做可以短一点,但又不合你的要求,SO,我用的是"单向循环链表".也不长啊!

:-)

88!
Devilxl 2003-10-15
  • 打赏
  • 举报
回复
真是太谢谢了,main函数下的结构体是不是太多了,我要是删的的话,能删掉那些??


TianGuangZao 2003-10-15
  • 打赏
  • 举报
回复
下面这个是从 CSDN 得来,也不知道是哪位大大写的。用数组实现。

约瑟夫问题
这是17世纪的法国数学家加斯帕在《数目的游戏问题》中讲的一个故事:15个教徒和15个非教徒在深海上遇险,必
须将一半的人投入海中,其余的人才能幸免于难,于是想了一个办法:30个人围成一圆圈,从第一个人开始依次报
数,每数到第九个人就将他扔入大海,如此循环进行直到仅余15个人为止。问怎样排法,才能使每次投入大海的都
是非教徒.

*问题分析与算法设计
约瑟夫问题并不难,但求解的方法很多;题目的变化形式也很多。这里给出一种实现方法。
题目中30个人围成一圈,因而启发我们用一个循环的链来表示。可以使用结构数组来构
成一个循环链。结构中有两个成员,其一为指向下一个人的指针,以构成环形的链;其
二为该 人是否被扔下海的标记,为1表示还在船上。从第一个人开始对还未扔下海的
人进行计数,每数到9时,将结构中的标记改为0,表示该人已被扔下海了。这样循环
计数直到有15个人被扔下海为止.


#include <stdio.h>
struct node
{
int nextp; /* 指向下一个人的指针 */
int no_out; /* 释放被扔下海的标记 */

} link[30+1]; /* 30 个人, 0 号没用 */

int main()
{
int i, j, k;
printf("The original circle is(+:pagendom, @:christian):\n");

for(i = 1; i <= 30; i++) /* 初始化 */
{
link[i].nextp = i + 1; /* 指针指向下一个人(数组元素下标) */
link[i].no_out = 1; /* 标志 1, 表示人都在船上 */
}
link[30].nextp = 1; /* 第30个人的指针指向第一个,构成环 */

j = 30; /* j:指向已经处理完的数组元素,从link[i]指向的人开始计数 */

for(i = 0; i < 15; i++) /* i:已经下海的人数计数器 */
{
for(k = 0; ; ) /* k:决定哪个人被扔下海的计数器 */
if(k < 15)
{
j = link[j].nextp; /* 修改指针,取下一个人 */
k + =link[j].no_out; /* 进行计数。因已下海的人计数标记为0 */
}
else break; /* 计数到15则停止计数 */
link[j].no_out = 0; /* 下海 */
}

for( i = 1; i <= 30; i++)
printf("%3d", i);
printf("\n");
for( i = 1; i <= 30; i++) /* 输出结果 */
printf("%3c", link[i].no_out ? '@' : '+');
printf("\n");
}

playboyxp 2003-10-14
  • 打赏
  • 举报
回复
#include <iostream.h>
void main()
{
int a[17],i,j,k=1,integer;
for(i=0;i<17;i++)
a[i]=i+1;
cin>>integer;
i=-1;
while(1)
{
for(j=0;j<integer;)
{
i=(i+1)%17;
if(a[i]!=0) j++;
}
if(k==17) break;
cout<<a[i]<<" ";
a[i]=0;
k++;
}
cout<<a[i]<<endl;
}
Devilxl 2003-10-14
  • 打赏
  • 举报
回复
大哥你好厉害呀,小弟我无限崇拜!但是小弟我还没碰过C++,能不能给个纯C的程序,再简单点的,上面这个我真的看晕了!!我用的是TC2.0!您上面的实现环境是不是有TC2.0了!要是有了,麻烦您给一再简单点C程序!!谢谢!
mfcer2 2003-10-14
  • 打赏
  • 举报
回复
/*
* 下面是我帮你写的一个“约瑟夫环算法”的实现。经测试后是对的,好好享用吧!
* :-)
* 约瑟夫环是:编号为1,2, ... ,n的n个人按顺时针方向围坐一圈,每个人
* 持有一个密码。一开始任选一个正整数作为报数上限值m,从第一个人开
* 始按顺时针方向自1开始顺报数,报到m时停止报数。报到m时停止报数。
* 报m的人出列,将他的密码作为新的m值,从他在顺时针方向上的下一个人
* 开始重新从1报数,如此下去,直至所有人全部出列为止。
*
* 分析:
* 可以先建一个单向循环链表;而整个“约瑟夫环”问题的过程,最终是
* 把这个链表删空为止。但在删时不能顺着删,而是按该问题的方案来删,
* 这也是这个问题的价值所在。细节部分可以看StatGame函数。
*--------------------------------------------------------------
* 实现环境:Dev-C++ 4.8.6.0, TC2.0
* 完成时间:2003年10月13日
*/

#include <stdio.h>
#include <stdlib.h>

#define MAX_NODE_NUM 100
#define TRUE 1U
#define FALSE 0U

typedef struct NodeType
{
int id; /* 编号 */
int cipher; /* 密码 */
struct NodeType *next;
} NodeType;

/* 创建单向循环链表 */
static void CreaList(NodeType **, const int);
/* 运行"约瑟夫环"问题 */
static void StatGame(NodeType **, int);
/* 打印循环链表 */
static void PrntList(const NodeType *);
/* 得到一个结点 */
static NodeType *GetNode(const int, const int);
/* 测试链表是否为空, 空为TRUE,非空为FALSE */
static unsigned EmptyList(const NodeType *);

int main(void)
{
int n, m;
NodeType *pHead = NULL;

while (1)
{
printf("请输入人数n(最多%d个): ", MAX_NODE_NUM);
scanf("%d", &n);
printf("和初始密码m: ");
scanf("%d", &m);
if (n > MAX_NODE_NUM)
{
printf("人数太多,请重新输入!\n");
continue;
}
else
break;
}

CreaList(&pHead, n);
printf("\n------------ 循环链表原始打印 -------------\n");
PrntList(pHead);
printf("\n-------------- 出队情况打印 ---------------\n");
StatGame(&pHead, m);
printf("\n\"约瑟夫环\"问题完成!\n");

return 0;
}

static void CreaList(NodeType **ppHead, const int n)
{
int i, iCipher;
NodeType *pNew, *pCur;

for (i = 1; i <= n; i++)
{
printf("输入第%d个人的密码: ", i);
scanf("%d", &iCipher);
pNew = GetNode(i, iCipher);
if (*ppHead == NULL)
{
*ppHead = pCur = pNew;
pCur->next = *ppHead;
}
else
{
pNew->next = pCur->next;
pCur->next = pNew;
pCur = pNew;
}
}
printf("完成单向循环链表的创建!\n");
}

static void StatGame(NodeType **ppHead, int iCipher)
{
int iCounter, iFlag = 1;
NodeType *pPrv, *pCur, *pDel;

pPrv = pCur = *ppHead;
/* 将pPrv初始为指向尾结点,为删除作好准备 */
while (pPrv->next != *ppHead)
pPrv = pPrv->next;

while (iFlag) /* 开始搞了! */
{
/* 这里是记数,无非是移动iCipher-1趟指针! */
for (iCounter = 1; iCounter < iCipher; iCounter++)
{
pPrv = pCur;
pCur = pCur->next;
}
if (pPrv == pCur) /* 是否为最后一个结点了 */
iFlag = 0;
pDel = pCur; /* 删除pCur指向的结点,即有人出列 */
pPrv->next = pCur->next;
pCur = pCur->next;
iCipher = pDel->cipher;
printf("第%d个人出列, 密码: %d\n",
pDel->id, /* 这个编号标识出列的顺序 */
pDel->cipher);
free(pDel);
}
*ppHead = NULL; /* 没人了!为了安全就给个空值 */
}

static void PrntList(const NodeType *pHead)
{
const NodeType *pCur = pHead;

if (EmptyList(pHead))
return;

do
{
printf("第%d个人, 密码: %d\n", pCur->id,
pCur->cipher);
pCur = pCur->next;
} while (pCur != pHead);
}

static NodeType *GetNode(const int iId, const int iCipher)
{
NodeType *pNew;

pNew = (NodeType *)malloc(sizeof(NodeType));
if (!pNew)
{
printf("Error, the memory is not enough!\n");
exit(-1);
}
pNew->id = iId;
pNew->cipher = iCipher;
pNew->next = NULL;

return pNew;
}

static unsigned EmptyList(const NodeType *pHead)
{
if (!pHead)
{
printf("The list is empty!\n");
return TRUE;
}

return FALSE;
}
/***********************************************
第一组测试结果
人数n为7, 初始密码m为20
------------ 循环链表原始打印 -------------
第1个人, 密码: 3
第2个人, 密码: 1
第3个人, 密码: 7
第4个人, 密码: 2
第5个人, 密码: 4
第6个人, 密码: 8
第7个人, 密码: 4

-------------- 出队情况打印 ---------------
第6个人出列, 密码: 8
第1个人出列, 密码: 3
第4个人出列, 密码: 2
第7个人出列, 密码: 4
第2个人出列, 密码: 1
第3个人出列, 密码: 7
第5个人出列, 密码: 4
************************************************
第二组测试结果
人数n为8, 初始密码m为15
------------ 循环链表原始打印 -------------
第1个人, 密码: 5
第2个人, 密码: 4
第3个人, 密码: 3
第4个人, 密码: 2
第5个人, 密码: 9
第6个人, 密码: 1
第7个人, 密码: 7
第8个人, 密码: 8
-------------- 出队情况打印 ---------------
第7个人出列, 密码: 7
第6个人出列, 密码: 1
第8个人出列, 密码: 8
第3个人出列, 密码: 3
第1个人出列, 密码: 5
第4个人出列, 密码: 2
第2个人出列, 密码: 4
第5个人出列, 密码: 9
***********************************************/

69,369

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧