约瑟夫环专题

约瑟夫环专题



前言

上次作业:

判断一个非空单向链表是否带环
在这里插入图片描述
分析:(3)和(4)都是在带环结点处会有两个后继,导致前驱结点存后继地址空间不够,所以(3)、(4)不存在,反观(1)、(2)是可以的。
(1)、(2)的链表结构如下:
在这里插入图片描述
如何检测带环:我们可以想到,如果链表带环,遍历链表则势必会对带环结构重复遍历,因此我们可以想到用大小指针来检测链表是否带环。
1.如果带环:大指针转n圈和小指针相遇;
2.如果不带环:大指针率先next->NULL。
代码实现:

int huan(ElemSN *h){
	int flag=0;//设置一个岗哨,如果带环,flag设置成1,不带环则为0
	ElemSN *p,*q;
	p=q=h;
	do{//当型结构用do while循环实现遍历
		p=p->next->next;//设置p为大指针
		q=q->next://设置q为小指针
		if(p==q){//如果带环大小指针总能相遇
			flag=1;//岗哨设置成1
			break}
	}while(p&&p->next);
	return flag;
}

一、约瑟夫环是什么?

示例:有n个小孩围成一个圈,制定从每个小孩开始,每s个小孩,该小孩出圈,问所有小孩出圈次序。

二、步骤

1.创建一个循环链表

设n=10,s=3;
在这里插入图片描述

2.新链表——小孩出圈顺序(尾插)

(1)找到需要出圈的小孩
(2)尾插到新链表
结束条件:t==t->next
算法实现如下:

while(t->next){
	//找出圈小孩
	//t跑s-1下
	for(int i=0;i<s*&&t=t->next;==i);
	//删
	p=t->next;
	t->next=p->next;
	//尾插
	if(!hn){
		hn=tn=p;
	}else{
		tn=tn->next=p;
	}
	tn=tn->next=t;
	tn->next=NULL;
}

代码实现:

//创建小孩图
ElemSN *GreateJosephusRing(int a[]){
	ElemSN *t=NULL;
	for(int i =0;i<n;++i){
		ElemSN *p=(ElemSN*)malloc(sizeof(ElemSN));
		p->data=a[i];
		if(!t){
			t=p->next=p;
		}else{
			p->next=t->next;
			t=t->next=p;
		}
    }
    return t;
}

//小孩出圈
//改进算法:while(t-t->next){
//				不够s-1次,跑t
//				够s-1次,删,插	        
//		   }
ElemSN *JosephusRing(ElemSN *t,int s){
	ElemSN *hn,*tn,*p;
	int i=1;
	while(t-t->next){
		if(i%s){
			t=t->next;
		}else{
			p=t->next;
			t->next=p->next;
		}
		if(!hn){
			hn=tn=p;
		}else{
			tn=tn->next=p;
		}
		i++;
	}
	return tn;
}
//输出
void print(ElemSN *hn){
	for(ElemSN *h=*hn;hn;hn=hn->next){
		printf("%5d",hn->data);
	}
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值