约瑟夫环问题

本文详细解析了约瑟夫环问题,通过链表和vector两种数据结构实现问题的求解,并提供了完整的代码示例。

约瑟夫环问题描述:约瑟夫环是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。--详见百度百科解释

n = 9, k = 1, m = 5

【解答】

出局人的顺序为5, 1, 7, 4, 3, 6, 9, 2, 8。

 

约瑟夫环问题采用的是典型的循环链表的数据结构,就是将一个链表的尾元素指针指向队首元素,把现实实际生活中的例子,抽像成数据结构中的链表来表示并求解

用循环队队实现的代码:

#include "stdio.h"
#include "stdlib.h"

struct node
{
    int num;
    struct node *next;
};

typedef struct node NODE;

NODE *createlinklist(int n)
{
    NODE *head,*p,*q;
    int i=1;
    head=p=(struct node*)malloc(sizeof(struct node));
    p->num=i;
    for(i=2;i<=n;i++)
    {
        q=(struct node*)malloc(sizeof(struct node));
        if(q==0) return(0);
        p->next=q;
        p=q;
        p->num=i;
    }
    p->next=head;          /*使链表尾指向链表头 形成循环链表*/
 

   return head;
}
void printlinklist(NODE *p,int n)
{
    int i;
 NODE *q = p;
    if(NULL == q->next){
  printf("the list is NULL!");
  return;
 }
    printf("所有玩家的信息列表:\n");
    for(i=1;i<=n;i++)
    {   
  if(NULL == q){
   printf("the list is NULL!");
   return;
  }
        printf("%d  ",p->num);
        p=p->next;
    }
 printf("\n");
}
void joseph(NODE *p,int k,int m)
{
 int j;
 NODE *r;
 // 把当前指针移动到第一个报数的人
 for(j=0;j<k;j++){
	 r=p;
	 p=p->next;
 }
 // 循环删除队列结点
 while(p->next!=p){
  for(j=0;j<m-1;j++)
  {
	  r=p;
	  p=p->next;
  }
  r->next=p->next;
  printf("%d  ",p->num);
  free(p);
  p=r->next;
 }
 printf("\n最后剩余的是第%d号.\n",p->num);
 p->next=NULL;
}
void main()
{
    NODE *head;
    int n,m;
 printf("请输入人数N:\n");
 scanf("%d",&n);
 printf("输入K:\n");
 scanf("%d",&m);
    head=createlinklist(n);
    printlinklist(head,n);
 printf("依次被选出的是:\n");
    joseph(head,n,m);
}

当碰到报的数字时,就free掉这个节点,当随着一个个数字删除后,节点越来越少,因为是循环队列,所以可以用p->next!=p来做终止条件,最后跳出后就是输出的最后一个数字

自己用vector实现的代码:

#include <iostream>
#include <vector>
using namespace std;

void jose(vector<int> &dat,int k){
	vector<int>::iterator iter=dat.begin();
	int j;
	while(iter!=dat.end()){
		for(j=0;j<k-1;j++){
			iter++;
			if(iter==dat.end()){
				iter=dat.begin();
			}
		}
		cout<<*iter<<endl;
		iter=dat.erase(iter);
		if(iter==dat.end()){
			iter=dat.begin();
		}
	}
}

void main(){
	int i,n,k,x;
	cout<<"input n value:";
	cin>>n;
	cout<<"input k value:";
	cin>>k;
	vector<int> data;
	for(i=0;i<n;i++){
		cout<<"input data "<<i<<" value:";
		cin>>x;
		data.push_back(x);
	}
	jose(data,k);
}


 vector是动态容器,可以方便实现删除,主要的问题它不是循环队列,所以当循环指针指向容器末端时,手动将指针指向头,这样就实现了循环队列。其实C++中有专门的队列容器deque(双端队列)和queue(先进先出队列),还有栈容器stack,C语言中没有这样的动态容器,只能用malloc来动态分配

 

参考资料:

1.http://baike.baidu.com/view/717633.htm    //百度百科对约瑟夫环的解释

2.http://zhidao.baidu.com/question/126119582.html?fr=qrl&cid=866&index=1   //链表实现

3.http://zhidao.baidu.com/question/56518088.html?fr=qrl&cid=866&index=5&fr2=query   //链表实现

4.http://zhidao.baidu.com/question/126988654.html?fr=qrl&cid=93&index=2    ////数组实现

5.http://www.iteye.com/topic/840884    //java实现

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值