关于#c++#的问题:猴子选大王代码解析:1.方法与思路 2.代码优缺点代码如下:#include using namespace std

猴子选大王代码解析: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代表猴子被踢
遍历寻找剩下的猴子