约瑟夫环问题的数组解法与单链表解法

来源:互联网 发布:外商投资网络支付机构 编辑:程序博客网 时间:2024/04/25 18:08

Johsph问题为n个人犯人围成一圈,从第i个人开始报数,每次报数报到编号为m的人即被杀死,直到n个人还剩一个人活着

1.该问题首先不管使用哪种办法,都得使得数组和单链表成环;

(数组成环可以在循环中用一个值,如k一直进行自加,知道k值等于或大于规定人数时,将k值直接置为0,即达到数组成环要求;而链表直接构造循环链表即可)

2其次考虑数组和单链表内该存放的数据是什么;

(数组解法中,数组初始化时直接全部置0,当每杀一个人时,将对应数组下标已经死的人的值置为1表示该人为死亡;而链表解法中将链表中的数据域依次存入n个犯人编号1~n)

3再者考虑m个人一杀如何去实现;

(数组解法 可以使用一个for循环,循环m次,循环结束将该杀的犯人的数值置为1;链表解法  先通过for循环找到要杀之人的前驱,然后通过删除要杀之人对应节点的方式间接达到“杀掉该犯人的效果”)

4最后将活着的那个人打印出来;

(数组解法直接通过for循环加上if判断打印出数组值为0的即可;链表直接打印链表即可,通过循环删除节点最后只剩下活着的那个犯人的节点)

数组解法:

#include <stdio.h>

#define START 0
#define ALIVE 0
#define DEAD 1
#define MAX 7
#define SIZE 33
int main(int argc, const char *argv[])

{
int a[SIZE]={0};
int i,j,k;
k=START-1;
//进入第二for循环时k会自加一次,所以k得从开始-1的地方开始
for (i=0;i<SIZE-1;i++)//控制杀人数,保证有一个人活下来;
{
for (j=0;j<MAX;j++)//控制隔多少个杀一人;
{
k++;
if(k>=SIZE)
//当k值大于或等于SIZE时,使k值回到初始值,使数组成环;
{
k=0;
}
if(a[k]==DEAD)//当a[k]所对应的为死掉的人时,j--相当于内层for()循环多循环一次,避开无效的j值得累加;
{
j--;
}
}
a[k]=DEAD;//将死掉的人数值置为1;
printf("a[%d] dead! number is %d\n",k,k+1);
}
for (k=0;k<SIZE;k++)//通过一次循环打印出活着的人编号;
{
if(a[k]==ALIVE)
{
printf("a[%d] alive! number is %d\n",k,k+1);//k为活着的人的下标,k+1为实际活着的人的编号;
}    //由于数组与数字的报数开始值不一样,数组从下标从0开始,数字从1开始;
}
return 0;

}






单链表解法如下:

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

typedef int data_t;

/* use a cycle linked list without header node */
typedef struct node_t
{
data_t data;
struct node_t *next;
} linknode_t, *linklist_t;
//注意:使用的为不带头结点的循环链表
int main()
{
int i, n, m, k;
linklist_t p, q;
printf("total N people will join this suicide game, please input N:");
scanf("%d", &n);
printf( "people stand in a circle, assume everyone is assigned\n"
"a sequence number from 1 to %d.\n"\
"which one would you like to start the number off (1~%d):", n, n);
scanf("%d", &k);
printf("every Xth people should kill himself, please decide the X:");
scanf("%d", &m);


if (n < 1 || k > n || m < 1)

 {
printf("input error!\n");
return -1;
}


printf("game is starting ...\n");


/* added the first one */
//第一部分:创建n个人的循环链表

p = q = (linklist_t)malloc(sizeof(linknode_t));
p->data = 1;


/* added other left people */
for (i = 2; i <= n; i++) {
q->next = (linklist_t)malloc(sizeof(linknode_t));
q = q->next;
q->data = i;
}
/* complete the circle */
q->next = p;
/* find the people ahead of #k */
//第二部分:寻找起始位置

q = p;
while (q->next != p) {
if (q->next->data == k)
//寻找起始位置k的前驱节点
break;
q = q->next;

}
//第三部分:开始Johsph环逻辑
while (q->next != q) /* till the last one */


/* every m people */
for (i = 0; i < m - 1; i++)//删除m号节点需要寻找它的前驱(m-1号)节点
{
q = q->next;
}


/* kill the m-th people */
p = q->next;
q->next = p->next;
printf("%-2d was killed\n", p->data);
free(p);

}

/* kill the last one */
printf("%-2d was alive\n", q->data);
free(q);

return 0;

}