Joseph 问题 :
有 10 个小朋友按编号顺序 1,2,。。。,10
顺时针方向围成一圈。从 1 号开 始顺时针方向 1,2,。。。,9
报数,凡报数 9 者出列(显然,第一个出圈为 编号 9 者)。
最后一个出圈者的编号是多少?第 5 个出圈者的编号是多少?
#include<iostream>
#include<Windows.h>
#include<stdlib.h>
using namespace std;
typedef struct LinkNode {
int id;
struct LinkNode* next;
}LinkList, LinkNode;
bool initLink(LinkList*& L) {
L = new LinkList;
L->id = -1;
L->next = L;
return true;
}
bool LinkInserct(LinkList*& L, int e) {
LinkList* last, * s;
s = new LinkList;
last = L;
s->id = e;
if (L->next == L) {
last->next = s;
s->next = L;
}
else {
while (last->next != L) last = last->next;
last->next = s;
s->next = L;
}
return true;
}
bool LinkList_ptint(LinkList*& L) {
LinkList* p;
if (L->next == L)return false;
p = L->next;
while (p != L) {
cout << p->id << " ";
p = p->next;
}
cout << endl;
return true;
}
void Josrph(LinkList* &L,int num) {
int count = 0;//第几个出来的
LinkList* p = L,*k;
int i = 0;
int temp; //用来存放小朋友id的
do {
i = 0;
while (1) {
if (p->next != L) i++; //如果下一个不指向头结点,先+1,先不指向
if (i == num)break; //判断第i个是否为报数为9的,如果是跳出
p = p->next; //如果不是9那么就指向下一个
}
count++;
k = p->next;
temp = k->id;
p ->next= k->next;
if (count == 5) {
cout << "第五个出圈的小朋友是:" << temp << endl;
}
/*
注意此处让p->next指向k->next,
千万不要写成p=k->next,那样的意思就是
p指向这个地址,再把k删除,这个链表就断了!
*/
delete k;
} while(p->next != p);
cout << "最后一个出圈的小朋友是" << temp << endl;
}
int main() {
LinkList* L;
//1.初始化
initLink(L);
//2.添加小朋友
for (int i = 1;i <= 10;i++) {
LinkInserct(L, i);
}
//3.输出
LinkList_ptint(L);
//4.出圈
Josrph(L,9);
system("pause");
return 0;
}
思路:
本题可以通过循环链表实现,先在链表上添加小朋友。
首先是题目要求所有的小朋友都要出圈,那么写一个循环,因为有个头结点,是不存放小朋友的,所以直到节点指向自己为结束。
再在循环里面套一个循环,用来判断是否报数报道9了。
如果报道了跳出循环,就删除这个小朋友(这里有个小细节:因为链表删除是需要知道前一个节点的。
所以从一开始遍历的时候,都是先指向前一个节点,判断下一个节点是不是要删除的,不是再指向这个节点)然后就是每删除一个count++。
而最后一个出圈的小朋友数据已经在temp中了,就可以再循环结束后在输出