【数据结构】约瑟夫死亡游戏(C语言实现)

【数据结构】约瑟夫死亡游戏(C语言实现)

问题描述
每30个乘客同乘一艘船,因为严重超载,加上风高浪大,危险万分,因此船长告诉乘客,只有将全船一半乘客投入海中,其余人才能幸免于难。无奈,大家只得同意这种办法,并议定30个人围成一圈,由第1个人数起,依次报数,数到第9人,便把他投入大海中,然后再从他的下一个人数起,数到第9人,再将他扔到大海中,如此循环地进行,直到剩下15个乘客为止。问哪些位置是将被扔下大海的位置。
简单分析
从题目可以看出,需要满足这些特征:1、头尾相接,即最后一个结点的下一个结点是第一个结点。2、从第一个结点往后数到9,删除该结点,在从下一个结点开始重复上述过程。
基于上面的分析,循环单链表是比较容易实现的。
注意:创建的循环单链表有没有头结点,虽然基本上没有影响,为了方面不带头结点更好。
算法实现:
1、头文件

//定义枚举状态
typedef enum Status
{
	success,fail,fatal,range_error
}Status;
//定义循环单链表的结点
typedef struct Listnode {
	int person;/*数据域,整型数据1-30*/
	struct Listnode *next;/*指针域*/
}Listnode;
typedef Listnode *ListnodePtr;
typedef ListnodePtr List, *ListPtr;
#define MAXSIZE = 30;
Status ListInit (ListPtr L);//初始化函数
Status ListCreate (ListPtr L, ListPtr S, int persondata[], int n);//创建函数
Status ListRemove (ListPtr L,ListPtr S, ListPtr ptr);//删除函数
void Ptrshift(ListnodePtr p, ListPtr ptr);//结点移动函数

2、创建链表,删除结点函数

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "list_JosephDeathGame.h"
//链表的初始化
Status ListInit(ListPtr L) {
	Status status = fatal;
	*L = (ListnodePtr)malloc(sizeof(Listnode));/*分配空间*/
	if (*L) {
		(*L)->next = NULL;
		status = success;
	}
	return status;
}
//不带头结点循环链表的创建
Status ListCreate(ListPtr L,ListPtr S, int persondata[], int n) {/*L是头指针,S是尾指针*/
	Status status = fail;
	ListnodePtr p, q;
	p = (ListnodePtr)malloc(sizeof(Listnode));
	q = (ListnodePtr)malloc(sizeof(Listnode));
	int i = n - 1;/*指向最后一个数据元素*/
	while (i >= 0)
	{
		p = (ListnodePtr)malloc(sizeof(Listnode));
		if (!p) {
			status = fatal;
			break;
		}/*空间分配失败,退出*/
		p->person = persondata[i];
		p->next = NULL;
		if (i == n - 1) {
			q = p;
			*S = p;
		}
		else {
			p->next = q;
			q = p;
		}
		i--;
	}
	*L = p;
	(*S)->next = p;
	if ((*L)->person == persondata[0]) status = success;
	return status;
}
//删除算法,不同于一般的删除算法,结点从头结点依次往后移动9个
Status ListRemove(ListPtr L,ListPtr S, ListPtr ptr) {/*ptr为需要删除结点的指针*/
	Status status = success;
	ListnodePtr  q;
	q = (ListnodePtr)malloc(sizeof(Listnode));
	if ((*ptr)->next == *L) {
		q = (*ptr)->next;
		(*ptr)->next = q->next;
		*L = (*ptr)->next;
		free(q);
	}/*正好删除了第一个结点*/
	else if ((*ptr)->next == *S) {
		q = (*ptr)->next;
		(*ptr)->next = q->next;
		*S = (*ptr);//*ptr指向倒数第二个结点,删除最后一个结点自然就是尾指针了。
		free(q);
	}/*正好删除最后一个结点*/
	else {
		q = (*ptr)->next;
		(*ptr)->next = q->next;
		free(q);
	}
	return status;
}
//每次指针向后移动7步
void Ptrshift(ListnodePtr p,ListPtr ptr){
	int j = 0;
	while (p&&j <7) {
		p = p->next;
		j++;
	}
	if (p&& j ==7){
		*ptr = p;//这样,*ptr指向的删除的结点的前一个结点
	}
}

3、main函数

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "list_JosephDeathGame.h"
int main() {
	int person[30];	
	int i = 0;
	printf("\n---------------船上原有30人,标号分别为-----------------\n");
	while (i < 30) {
		person[i] = i + 1;
		i++;
		printf(" [%d]", i);
	}
	printf("\n");
//不带头结点的循环单链表的初始化和创建
	ListPtr L,S;
	L = (ListPtr)malloc(sizeof(List));
	S = (ListPtr)malloc(sizeof(List));/*初始化头,尾指针的指针*/
	Status status = range_error;
	status = ListInit(L);
	if (status == success) {
		status = ListCreate( L,S, person,30);
	}
	else {
		printf("\n---------------链表结点初始化失败!-----------------\n");
		return -1;
	}
	if (status == success)
	{
		printf("\n---------------带头指针和尾指针的循环单链表创建成功!-----------------\n");
	}
	else {
		printf("\n---------------链表创建失败!-----------------\n");
		return -1;
	}
//按照要求,循环依次下一个第9个人删去
	ListPtr ptr;
	ptr = (ListPtr)malloc(sizeof(List));
	status = ListInit(ptr);
	if (status == success) {	
		printf("\n---------------被推进海里的人的标号为-----------------\n");
		Ptrshift(*L, ptr);
		int m = 0;
		for (; m < 15; m++) {
			printf(" [%d]", ((*ptr)->next)->person);
			status = ListRemove(L, S, ptr);
			Ptrshift((*ptr)->next, ptr);//使得*ptr指向下一个删除结点的前一个结点
		}
		printf("\n");
		printf("\n---------------删除操作成功!-----------------\n");
	}
	else printf("\n---------------删除操作失败!-----------------\n");
	printf("\n---------------剩下的15人,标号依次为:-----------------\n");
	ListnodePtr r = *L;
	printf(" [%d]", r->person);
	r = r->next;
	while (r != *L) {
		printf(" [%d]", r->person);
		r = r->next;
	}
	printf("\n");
	system("pause");
	return 0;
}

结果展示

运行结果

  • 0
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值