猴子选大王代码解析:1.方法与思路 2.代码优缺点
代码如下:
#include
using namespace std;
struct Monkey
{
int num; //猴子的编号
struct Monkey *next; //下一只猴子
};
int main()
{
int m,n,i,j,king;
Monkey *head, *p1,*p2;
cin>>m>>n;
if(n==1)
{
king=m;
}
else
{
//建立猴子围成的圆圈
p1=p2=new Monkey;
head = p1;
p1->num=1;
for(i=1; i//其余m-1只猴子
{
p1=new Monkey; //p1是新增加的
p1->num=i+1;
p2->next=p1;
p2=p1; //p2总是上一只
}
p2->next=head; //最后一只再指向第一只,成了一个圆圈
//下面要开始数了
p1=head;
for(i=1; i//循环m-1次,淘汰m-1只猴子
{
//从p1开始,数n-1只就找到第n只了
for(j=1; j1; j++) //实际先找到第n-1只,下一只将是被淘汰的
p1=p1->next; //围成圈的,可能再开始从第一只数,如果还未被淘汰的话
//找到了,
p2=p1->next; //p2将被删除
//cout<<"第"<"轮淘汰"<num<//可以这样观察中间结果
p1->next=p2->next; //p2就这样被“架空了”
p1=p2->next; //下一轮数数的新起点
delete p2; //将不在链表中的结点放弃掉
}
king=p1->num;
delete p1;
}
cout<0;
}
方法与思路:
1、首先输入猴子的总数 m 和报数的数字 n。
2、建立猴子围成的圆圈。首先创建第一个猴子结点,然后用循环来创建剩余的 m-1 个猴子结点,最后将最后一个猴子的 next 指向第一个猴子,使得所有的猴子形成了一个圆圈。
3、开始进行报数。从第一个猴子开始,每次报数到第 n 个猴子时,将该猴子从圆圈中淘汰,即将其从链表中删除。
4、循环上述过程 m-1 次,直到只剩下一只猴子。
5、输出最后剩余的猴子的编号,即为猴子大王的编号。
代码优缺点:
优点:
1、使用了链表的数据结构,在删除猴子时能很方便地实现。
2、对于特殊情况,即 n=1 的情况,特别进行了处理,使得代码不会出错。
缺点:
1、没有对输入的 m 和 n 进行合法性校验,如果输入的不是正整数,或者 m 和 n 太大,可能会导致程序出错。
2、在淘汰猴子时,需要使用两个指针来实现,代码结构较为复杂。
3、使用了动态内存分配,可能会导致内存泄露。
4、在删除猴子时,需要使用 delete 进行内存释放,但是如果程序异常退出,可能会导致内存泄露。
5、使用了循环,如果 m 和 n 较大,可能会导致程序运行较慢。
仅供参考,望采纳,谢谢。
1.方法与思路
这个程序的思路是使用链表模拟猴子围成的圆圈,然后每次按照要求淘汰一只猴子,最后剩下的猴子即为大王。
首先输入猴子的数量 $m$ 和淘汰编号的间隔 $n$。如果 $n=1$,则最后剩下的猴子就是大王,直接输出 $m$ 并结束程序。否则,使用循环建立猴子围成的圆圈,并设置指针 $p1$ 和 $p2$ 来指向第一只猴子和最后一只猴子。
然后使用双重循环,每次淘汰一只猴子。第一重循环按照要求淘汰 $m-1$ 只猴子,第二重循环每次从当前猴子开始,数 $n-1$ 只猴子,则下一只猴子就是要被淘汰的猴子。设置指针 $p2$ 来指向要被淘汰的猴子,将其从链表中删除,并将 $p1$ 设为下一个要数的猴子,进入下一轮循环。
最后剩下的猴子即为大王,输出其编号并结束程序。
2.代码优缺点
优点:
代码结构清晰,注释丰富,便于理解。
将猴子围成圆圈的方法较为巧妙,使用指针将最后一只猴子的指针指向第一只猴子,达到了模拟圆圈的效果。
缺点:
在淘汰猴子时,由于使用了指针,会有大量的指针操作,可能会使代码变得较为复杂。
如果猴子数量较多,在淘汰猴子时需要遍历整个链表,可能会导致时间复杂度较高。
那么可以考虑使用双向链表来优化这个程序。双向链表是一种特殊的链表,每个结点都有两个指针,一个指向下一个结点,一个指向上一个结点。这样,在淘汰猴子时,就可以直接使用上一个结点的指针来指向下一个结点,从而省去了遍历整个链表的时间。
可以使用双向链表的结构体来替换原来的单向链表的结构体,并修改相应的代码。例如,在建立猴子圆圈时,可以在每个结点中新增一个指向上一个结点的指针,在建立圆圈后,可以使用这个指针将最后一个结点的上一个结点指向第一个结点。在淘汰猴子时,可以直接使用当前结点的上一个结点的指针来指向下一个结点,将要被淘汰的结点从链表中删除。
这样的修改可以大大简化代码,并且减少了指针的使用,使程序的可读性和可维护性得到提升。此外,使用双向链表可以在一定程度上提高程序的运行效率。例如,在淘汰猴子时,可以直接使用当前结点的上一个结点的指针来指向下一个结点,而不用再次遍历整个链表。这样可以避免在大量数据的情况下出现时间复杂度过高的问题。
不过,使用双向链表的同时也要注意维护好链表的结构。例如,在淘汰猴子时,要同时修改被淘汰结点的上一个结点的指针和下一个结点的指针,以保证链表的连续性。此外,在删除结点时,要注意释放内存,避免内存泄漏的问题。
总的来说,使用双向链表来优化这个程序可以使代码结构更加清晰,提高程序的可读性和可维护性,并且在一定程度上提升程序的运行效率。
下面是使用双向链表优化后的代码实现:
#include <iostream>
using namespace std;
struct Monkey
{
int num; //猴子的编号
struct Monkey *prev; //上一只猴子
struct Monkey *next; //下一只猴子
};
int main()
{
int m,n,i;
Monkey *head, *p1,*p2;
cin>>m>>n;
if(n==1)
{
cout << m << endl;
}
else
{
//建立猴子围成的圆圈
p1=p2=new Monkey;
head = p1;
p1->num=1;
for(i=1; i<m; i++) //其余m-1只猴子
{
p1=new Monkey; //p1是新增加的
p1->num=i+1;
p2->next=p1;
p1->prev=p2; //新增的指向上一个结点的指针
p2=p1; //p2总是上一只
}
p2->next=head; //最后一只再指向第一只,成了一个圆圈
p1=head;
for(i=1; i<m; i++) //循环m-1次,淘汰m-1只猴子
{
//从p1开始,数n-1只就找到第n只了
for(int j=1; j<n-1; j++) //实际先找到第n-1只,下一只将是被淘汰的
p1=p1->next; //围成圈的,可能再开始从第一只数,如果还未被淘汰的话
//找到了,
p2=p1->next; //p2将被删除
//cout<<"第"<<i<<"轮淘汰"<<p2->num<<endl; //可以这样观察中间结果
p1->next=p2->next; //p2就这样被“架空了”
p2->next->prev=p1; //修改被淘汰结点的下一个结点的prev指针
p1=p2->next; //下一轮数数的新起点
delete p2; //将不在链表中的结点放弃掉
}
cout << p1->num << endl;
delete p1;
}
return 0;
}
这样就可以使用双向链表的方式来实现了。
方法与思路:输入猴子的总数 m 和报数的数字 n,然后建立猴子围成的圆圈。创建第一个猴子结点,然后用循环来创建剩余的 m-1 个猴子结点,最后将最后一个猴子的 next 指向第一个猴子,使得所有的猴子形成了一个圆圈。然后开始进行报数。从第一个猴子开始,每次报数到第 n 个猴子时,将该猴子从圆圈中淘汰,即将其从链表中删除。循环上述过程 m-1 次,直到只剩下一只猴子。输出最后剩余的猴子的编号,就是猴子大王的编号。
代码优缺点:
优点:
对于 n=1 的情况,特别进行了处理,使得代码不会出错。代码注释很多,很容易看懂。
缺点:
时间复杂度较高。
#include <iostream>
using namespace std;
// 函数king:猴子选大王
// 参数:a-猴子数组n-1个猴子分别占据下标为~n-1的位置,n-数组长度
// 返回值:新猴王的下标序号
int king(int a[], int n);
int main()
{
// 定义变量及数组,n-猴子数量,a-猴子数组
int n, a[1000], i;
// 输入猴子数量,n>0
cin >> n;
// 初始化猴子数组,n个猴子分别占据~n的位置
a[0] = 0; // 0号位置没有猴子
for (i = 1; i <= n; i++)
a[i] = i;
// 选大王啦
i = king(a, n);
cout << i << "号猴子是大王。" << endl;
return 0;
}
int king(int a[], int n)
{
int out = 0; // 出去了几个
int flag = 0; // 报数号
int next = 1; // 下一个
// 循环n-1次,每次出去一个
while (out < n - 1)//当out=n-1时停下来,只剩最后一个猴子,那个就是大王,这也就是停止条件
{
while (a[next] == 0)
{// 这个位置的猴子已经出去了
next++; // 看下一个位置的猴子
if (next == n + 1) // 到尾部了,再回到头部
next = 1;
}//这样写可以跳过全部为0的数组,且不加报数数
flag++; // 报数号加
if (flag == 3) // 要出去了
{
a[next] = 0;
next++;
if (next == n + 1)
next = 1;
flag = 0;//再重头来过
out++;//记录出去的猴子数
}
else
{
next++;
if (next == n + 1)
next = 1;
}
}
// 找唯一的猴子
int i;
for (i = 1; i < n + 1; i++)
if (a[i] != 0)
return i;
return 0;
}
https://blog.csdn.net/weixin_34125509/article/details/117052749
1.猴子数组初始化
2.判断条件,只要剩下的猴子大于1就执行此循环
3.如果这个猴子已经被踢出去了,就跳过这个(continue)继续看下一个
4.每有一个猴子说数,就++(注意如果这个猴子已经被踢,那么continue会直接到i++而不会经过count++)
5.当count=k时,说明这个猴子被踢了,那么猴子数number-1,重新说数故count=0,把这处数组定义为0代表猴子被踢
遍历寻找剩下的猴子