您的位置:首页 > 理论基础 > 数据结构算法

约瑟夫环问题

2011-09-06 22:51 120 查看
约瑟夫环问题描述:约瑟夫环是一个数学的应用问题:已知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实现

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息