约瑟夫环问题
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。
约瑟夫环问题采用的是典型的循环链表的数据结构,就是将一个链表的尾元素指针指向队首元素,把现实实际生活中的例子,抽像成数据结构中的链表来表示并求解
用循环队队实现的代码:
当碰到报的数字时,就free掉这个节点,当随着一个个数字删除后,节点越来越少,因为是循环队列,所以可以用p->next!=p来做终止条件,最后跳出后就是输出的最后一个数字
自己用vector实现的代码:
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实现
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实现