Joseph问题

题目描述:

设编号分别为:1,2,…n 的 n 个人围坐一圈。约定序号为 k (1<= k <=n) 的人从 1 开始计数,数到 m 的那个人出列,他的下一位又从 1 开始计数,数到 m 的人又出列,依次类推,直到所有人出列为止。

例子:

假设 n=8, k=3, m=4:
则出列序列为:(6,2,7,4,3,5,1,8)

算法思路:
用一个不带头结点的循环链表来处理此问题,先构成一个有 n 个结点单循环链表,然后从第 k 个结点起从 1 计数,记到 m 时对应结点从链表中删除,然后再从被删除结点的下一个结点起又从1开始计数…直到所有结点都出列时算法结束。

头文件 list.h:

#ifndef _LIST_H_
#define _LIST_H_

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

//单项循环链表 
typedef struct node{
	int data;
	struct node *next;
}listnode,*linklist;


linklist list_create();		//创建一个单向循环单链表 
void list_show(linklist H);			//打印单向循环链表的内容 

void list_jose(linklist H,int k,int m);		//joseph问题实现
 


linklist list_create()		//创建一个单链表 
{
	linklist H,r,p;
	int i,n;
	
loop:
	printf("please input n:\n");
	scanf("%d",&n);
	if(n<0)
	{
		printf("n > 0\n");  
		goto loop;	//当输入为负数,跳转到 loop:处重新输入 
	}
	
	if((H = (linklist)malloc(sizeof(listnode))) == NULL)	
	{
		printf("malloc failed\n");
		return NULL;
	}
	
	H->data=1;
	H->next=H;
	r=H;	//r指向尾部
	
	for(i=2;i<=n;i++)
	{
		if((p = (linklist)malloc(sizeof(listnode))) == NULL)	
		{
			printf("malloc failed\n");
			return NULL;
		}
		p->data=i;
		r->next=p;
		r=p;
	}
	p->next=H;
	
	return H;
}


void list_show(linklist H)			//打印单链表的内容 
{
	linklist p=H;
	
	while(p->next!=H)
	{
		printf("%d ",p->data);
		p=p->next;	
	}	
	printf("%d\n",p->data);	//因为最后一个结点指向头结点,所以在循环中没有打印出来 
}


void list_jose(linklist H,int k,int m)		//joseph问题实现
{
	linklist r,p;
	int i;
	
	r=H;
	
	//找到第k个结点 
	while(r->next->data != k)
	{
		r=r->next;
	}
	printf("k=%d\n",k);
	
	
	while(r->next!=r)	//循环结束的条件是就一个结点了 
	{
		//循环结束后r指向m-1的位置 
		for(i=0;i<m-1;i++)
		{
			r=r->next;
		}
	
		p=r->next;   //p指向要删除的结点 
		r->next=p->next;
		printf("%d ",p->data); 
		free(p);
		p=NULL;
	}
	//删除最后一个结点 
	printf("%d ",r->data); 
	free(r);
	p=NULL;
		
}

#endif

测试文件 josephTest.c

#include "list.h"

int main()
{
	linklist H;
	int k,m;
	
	H=list_create();
	list_show(H);
	printf("=======================\n");
	printf("please input k and m:\n");
	scanf("%d%d",&k,&m);
	list_jose(H,k,m);
	
	
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值