最后一个人站着,使用了圆形链表

Last man standing , used circular linked list

本文关键字:链表 最后一个人      更新时间:2023-10-16

问题:一家公司招聘候选人,会让他们坐成一圈。他们每隔一秒就选择一个候选人,然后他离开圆圈(因此圆圈越来越小(,直到只剩下1个。所以,如果有5个人,它会像:-

1 2 3 4 5
1 3 4 5    (2 is selected)
1 3 5      (4 is selected)
3 5        (1 is selected)
3          (3 is left, does'nt get the job!)

Jhon是一个过度精明的人,他不想成为这个恶意公司的一员。

如果他知道总共有560人,他会站在哪里。回答:我试着制作一个程序,输入n(候选人数量(它将打印一个将被取消选择的座位的值。

我使用了循环链表和删除。

请耐心等待,因为我对编码还很陌生。

我的程序适用于输入2、4、8、16、32、64等等,因为所有这些都是1。但任何其他输入都不起作用

#include <iostream>
using namespace std;
struct node
{
    node* ptr;
    int data;
}start;

int main()
{
    node *start=NULL;
    int n;
    cout<<"Enter the number of students : ";
    cin>>n;
   node *temp=new node;
   temp->data=1;
   temp->ptr=NULL;
   start=temp;
   for(int x=2;x<=n;x++)
   {
       node* temp1=new node;
       temp1->data=x;
       temp->ptr=temp1;
       temp1->ptr=start;
       temp=temp1;
   }
   node* temp2=start;
   do
   {
       cout<<temp2->data<<" ";
       temp2=temp2->ptr;
   }while(temp2!=start);
   cout<<endl;

   //delete bigins here
   temp2=start;
   node* temp3=temp2->ptr;
   do
   {
        temp2->ptr=temp3->ptr;
        temp3->ptr=NULL;
        delete temp3;
        temp2=temp2->ptr;
        temp3=temp2->ptr;

   }while(temp2->ptr!=start);
    temp2=start;
   do
   {
       cout<<temp2->data<<" ";
       temp2=temp2->ptr;
   }while(temp2!=temp3);
   cout<<endl;
}

我的程序适用于输入2、4、8、16、32、64等等,因为所有这些都是1。

这是一个很好的观察结果。事实上,答案离这里只有一小步之遥。

您有n个候选项,每次选择1个。如果nx + 2^k(具有最大可能的k(,则在x步之后,您还有2^k个候选者,行中的下一个候选者就是答案。所以答案是2x+1

1 2 3 4 5 6 7
  ^   ^   ^ |
   removed  |
       answer

注:此练习可在《具体数学:计算机科学基础》中找到。我强烈推荐它。

问题在于核心循环:

do {
    temp2->ptr=temp3->ptr;
    temp3->ptr=NULL;
    delete temp3;
    temp2=temp2->ptr;
    temp3=temp2->ptr;
    } while (temp2->ptr!=start);

这个循环只遍历数据一次:当它到达第一组删除的末尾时停止,因为它在第一次返回start时停止。这就是为什么你总是得到答案1,正如你所指出的,当列表长度是2的幂时,这个答案是正确的。

相反,它应该循环,直到只剩下一个node,它将指向自己作为下一个node。因此do ... while循环的最后一行应该是:

    } while (temp2->ptr != temp2)

很明显,世界已经发生了变化:我第一次听到这个谜题是关于海盗喝毒药来确定谁得到了宝藏!

要极大地简化您的解决方案,请实现"软删除"。在节点结构上放置一个名为"int deleted"的标志,并将其初始化为0。每次要删除节点时,只需将deleted=1设置即可。你的问题中的指针逻辑有问题,这消除了大部分问题。

在寻找下一个要删除的节点时,如果该节点已删除==1,则不要将其算作剩余节点之一,只需继续操作,直到找到第二个deleted=0的节点,并将其设置为1。

在这一点上,你甚至不需要一个循环列表,甚至不需要列表。您可以只使用值为0或1的int数组。如果你记下还有多少,那么只要你只剩下一个,你就可以停下来,否则你就必须遍历整个数组,以确保一个都没有。

这并没有那么快,因为你的列表永远不会变小,你会看到很多被删除的条目,但它要简单得多。

第二个do-while循环中有一个小错误(删除(。while语句在循环中迭代一次后强制终止循环,即,一旦循环回到起始节点,它就退出。您需要更改线路

while(temp2->ptr!=start);

while(temp2->ptr!=temp2);

另外,最后一个do-while循环似乎运行到了一个无限循环中,因为它上面的语句:

temp2 = start;

在删除过程中,您不会跟踪一旦删除元素1就会被删除的开始指针。因此temp2指向垃圾。拆下这根线也能解决这个问题。