C语言单循环链表实现约瑟夫环

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);
}
  • 6
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值