C语言单循环链表实现约瑟夫环
链表又被称为动态数组,是用一串不连续的地址来存储我们需要的数据。
所以想要解决这个案例,需要对C语言的指针和链表比较熟悉。
指针我们不再多说,简单讲述一下链表(以下纯属个人见解,如有不对请指正):
先贴一个普通的单链表存储结构代码:
typedef struct Node{
int data;//用于存放我们的数据
struct Node * next;//用于存放下一个结点的地址
}Node,* LinkList;
搞懂链表,首先要搞懂链表本身就是指针指向数据的思想,也就是说链表的每一个结点都是一个指针,这个指针的地址上放着两个东西----本身的数据(data)和下一个节点的地址(next)。
上面代码中,假如我们定义一个头结点:
LinkList L;//其实等价于Node * L;
/*
那为何多此一举?但是编程语言就是为了让人能读懂,
所以我们单独使用LinkList代表单循环链表头结点,
使用Node *代表链表中的元素结点
*/
接下来我们初始化一个单循环空链表:
void InitList(LinkList * L)
{
*L=(LinkList)malloc(sizeof(Node));
/*LinkList=Node * 所以这里的参数L实际上是一个指向地址的地址,需要配合malloc在堆区申请动态内存来存放我们的数据
*/
(*L)->next=(*L);
//表尾指向表头,构成单向循环
}
约瑟夫环简单描述:
假设有n个玩家,每个玩家持有一个密码(玩家自己想出来的一个数字),我们在设置一个初始密码password(一个数字),然后从从第一个玩家开始报数,每个玩家报一次,直到报到password的玩家出列,再将他手中的密码作为新的password,从他的下一位玩家开始报数…一次类推,直到所有玩家出列。
那么话不多说,了解了链表后,直接贴代码:
(代码比较粗糙,虽然能执行但是效率并不高,希望引用的话可以独立思考并加以改进)
#include<stdio.h>
#include<stdlib.h>
#define _CRT_SECURE_NO_WARNINGS
// 定义链表节点
typedef struct Node {
int sequence, password;
struct Node* next;
}Node, * LinkList;
// 初始化链表
void InitList(LinkList* L){
*L = (LinkList)malloc(sizeof(Node));
(*L)->next = (*L);
}
// 包装打印函数
int print(){
int a;
printf("请输入玩家密码:'0'代表结束\n");
scanf_s("%d", &a); return a;
}
// 创建链表
int CreateList(LinkList L){
Node* rear;
Node* s;
rear = L;
int num, i = 1, length = 0;//i作为链表序数持续增加,num作为密码记录,length作为链表长度
num = print();
if (num != 0)
{
L->password = num;
L->sequence = i;
length++;
i++;
}
num = print();
rear = L;
while (num != 0)
{
s = (Node*)malloc(sizeof(Node));
s->password = num;
s->sequence = i;
rear->next = s;
rear = s;
length++;
i++;
num = print();
}
rear->next = L;
return length;
}
// 分别接收密码,长度,链表头指针
void DeletePerson(int password, int length, LinkList L){
Node* p;//指向需要被删除的人的前驱节点
Node* r;//指向被删除的人
p = L;
int i;//每次删除人数时指针需要移动的次数
if(password==1)
{
p=p->next;
}
while (length)
{
for (i = 1; i < password - 1;i++)//找到被删除数据节点的前驱节点
p = p->next;
r = p->next;
printf("%d ", r->sequence);
password = r->password;
p->next = r->next;
p = r->next;
length--;
free(r);
}
}
void main(){
LinkList L;
int password1, length;//接收初始密码,length接收链表长度
printf("请输入初始密码:\n");
scanf_s("%d", &password1);
InitList(&L);
length = CreateList(L);
printf("链表长度为:%d\n",length);
for (int i = 0; i < length; i++)//输出链表查看数据存放是否有问题
{
printf("%d %d\n",L->sequence,L->password);
L = L->next;
}
DeletePerson(password1, length, L);
}