约瑟夫环问题:
(一)问题:
已知有n个人(编号为1,2,3...n)围坐在一个圆桌周围,从编号为k的人开始报数,数到m的那个人出队,出队的下一个位置的人继续从k开始数数,数到m的那个人继续出队,。。。,知道所有的人都出队了,求出队序列。
(二)方法一:循环链表。
(1)步骤:
1.构造一个有n个元素的循环链表,无头节点。
2.确定第一个报数人的位置;
3.不断从链表中删除节点;
(2)代码实现:
typedef struct linkNode{
DataType data;
linkNode* next;
}linkNode* creatLoopLink(int n){
static linkNode * pnode;
pnode=(linkNode*) malloc(sizeof(linkNode));//产生一个新节点;
pnode->data=1;
pnode->next=NULL; LinkNode* curNode,*lastNode=pnode;
for(int i=2;i<=n;i++){
curNode=(linkNode*) malloc(sizeof(linkNode));//产生一个新节点
curNode->data=i;
curNode->next=NULL; lastNode->next=curNode;//尾接法创建一个链表
lastNode=curNode;
} lastNode->next=pnode;//最后一个节点的尾部连接头。
return pnode;
} /*
从循环链表link中,不断删除编号为m的节点。
k表示起始读数;
m要删除的编号
n为节点个数
*/
deleteNode_m(linkNode* link, int k, int m ,int n){
linkNode* pre,cur=link;
for(int i=1;i<=k;i++){//定位到第k个节点,即第一个报数的人。
pre=cur;
cur=cur->next;
} for(int i=n;i>=1;i--){//计算出队序列
for(int j=k;j<=m;j++){//从k定位到m
pre=cur;
cur=cur->next;
} pre->next=cur->next;
visit(cur->data);
free(cur); cur=pre->next;//下一个从删除节点的下一个开始数数。
}
}
(三)方法二:循环队列
(1)步骤:
1.初始化队列:
将编号为1,2,3....n的人依次入队;
2.定位k:
依次出队,直到m,并且将出队的元素同时插入到队尾。
3.删除m:
从k到m-1,依次出队,并且入队到队尾,m直接出队,不再入队。
4.下一个k的位置,就是不再入队的m的下一个元素。循环3、直到全部删除。