连续删除Vector前几个后者后几个元素

本文介绍了一个实用的C++示例代码,演示如何使用vector容器进行基本操作,包括元素的添加、遍历、删除等,并提供了具体的实现方法。

 使用C++操作vector,经常会出错。查了网上,发现这个方法比较实用。自己整理了一下。供大家参考。

#include <iostream>
#include <stdlib.h>
#include <vector>
using namespace std;

int main()
{

    int mLong=20;
    //产生20个元素
    std::vector<double> mVec;
    for(int i=0;i<mLong;i++)
    {
       mVec.push_back((double)i);
    }
    //打印10个数据
    for(int i=0;i<mLong;i++)
    {
        cout<<"mVec"<<"["<<i<<"]="<<mVec[i]<<endl;
    }
     cout<<"delete front 5 data----------------------"<<endl;
    //删除前5个元素
    std::vector<double>::iterator iter;

    for(iter=mVec.begin();mVec.size()>15;)
    {
        iter=mVec.erase(iter);
    }
    //打印
    for(int i=0;i<mVec.size();i++)
    {
        cout<<"mVec"<<"["<<i<<"]="<<mVec[i]<<endl;
    }
        cout<<"delete bak 5 data----------------------"<<endl;
    //删除后面的元素,直到保留10个元素
    while(mVec.size()>10)
    {
         mVec.pop_back();
    }
    //打印
    for(int i=0;i<mVec.size();i++)
    {
        cout<<"mVec"<<"["<<i<<"]="<<mVec[i]<<endl;
    }

    return 0;
}

 

<think>根据用户的需求和引用内容,用户希望解决约瑟夫环问题,输出最后胜利者的编号(即第几个小孩)。参考引用中提到的思路,我们可以使用循环链表来模拟这个过程。不过,在C++中,我们也可以使用标准库中的list(双向链表)来模拟循环链表,因为list支持高效的删除操作。 根据引用[1]和引用[4]的描述,问题可以描述为:n个人围成一圈,从第k个人开始报数(在引用[1]中是从第k个小孩开始,但用户问题中未指定k,通常默认从第一个开始),数到m的人出列,然后从下一个人重新开始报数,直到剩下一个人。 但是,在用户的问题描述中,他提到“从第k个小孩起”,但在代码中并没有体现k。查看用户提供的代码,是从第一个小孩开始的。因此,我们需要考虑用户是否要求从任意位置开始?不过,在用户的问题中,他要求“最后要说出来,代码按照这个要求改了给我”,并且之的代码是从1开始的。所以,为了满足引用[1]中的描述,我们将增加一个参数k(起始位置)。 然而,在引用[2]中,构建对象时只传入了n和m,没有k。所以我们需要澄清:用户是否要求从任意位置开始?根据引用[1]的描述,确实是从第k个小孩开始。因此,我们修改代码,增加起始位置k。 但是,在用户之给出的代码中,并没有k。现在根据引用[1]的要求,我们修改代码,允许从第k个小孩开始。 修改点: 1. 在Game类中增加成员变量start(起始位置,即第k个小孩,注意:k从1开始计数)。 2. 在构建Game对象时,传入三个参数:total(总人数),start(起始位置),step(步长)。 3. 在run方法中,初始化current为start-1(因为数组下标从0开始,所以第k个小孩的下标是k-1)。 4. 注意:在删除过程中,每次删除后,下一个开始报数的人就是被删除者的下一个,但我们的current已经指向了被删除者的位置,删除后,下一个位置就是current(因为删除后,后面的元素移,所以current自然指向了下一个开始的人,但为了正确性,我们调整一下:删除后,current指向被删除元素的下一个,但由于删除后当指针位置已经是下一个了,所以我们不需要再移动。但是,如果删除的是最后一个元素,那么current会变为0?) 不过,我们也可以按照引用[4]的思路,使用循环链表,但为了简单,我们使用vector来模拟,但要注意删除元素后索引的变化。 由于用户要求最后输出胜利者是第几个小孩,我们修改代码,使其能够从任意位置开始。 但是,在用户之提供的代码中,我们并没有处理起始位置。因此,我们按照引用[1]的要求,增加起始位置。 然而,在引用[1]中,他们使用链表,我们这里为了简单,使用vector,但vector在中间删除元素效率较低,如果人数较多,可能会影响性能。但考虑到用户可能只是小规模测试,我们使用vector。 修改后的代码: 步骤: 1. 初始化:将1~total编号的人加入vector。 2. 设置当位置current为start-1(因为数组下标从0开始)。 3. 循环直到只剩一个人: 计算下一个要出局的位置:current = (current + step - 1) % 当剩余人数 删除该位置的人,并输出 注意:删除后,current会指向下一个元素(因为删除位置后面的元素移),所以下一次报数就从current开始(相当于被删除者的下一个成为新的起点),因此不需要再移动current(因为删除后,原来的current+1变成了current,但我们已经用新的索引计算了下一个位置)。 但是,这里有一个问题:我们每次计算位置时,都是在上一次的位置基础上加上步长,然后取模。而删除后,当指针指向的位置实际上是下一个开始的位置。所以,我们不需要调整current,只需要在删除后,current的值保持不变(因为后面的元素移,所以current指向了下一个开始报数的人)。但是,当我们删除一个元素后,下一次报数应该从被删除者的下一个开始,而我们的current在删除后指向的正是下一个(因为删除后,被删除元素后面的元素移,所以current现在指向的就是下一个)。所以,我们不需要额外调整current。 但是,如果我们从0开始计数,那么第一次报数时,当位置是start-1,然后报数步长是step,那么下一个出局的位置应该是(current + step - 1) % 当人数。因为当位置的人报1,然后下一个报2,所以步长step-1。 因此,我们修改代码,增加起始位置。 另外,根据引用[1]的描述,他们使用链表,我们这里使用vector,虽然数据结构不同,但逻辑相同。 下面我们实现代码: 注意:起始位置k(即从第k个小孩开始)由用户输入。 修改GameRunner类,增加输入起始位置。 同时,注意边界情况:当起始位置超过总人数时,应该取模?但用户输入时,我们要求k在1~total之间,所以可以不做取模,而是要求用户输入正确。或者,我们可以对k取模,但更安全的方式是要求用户输入1~total之间的数,如果输入错误则提示。 为了简单,我们不对k做范围检查,而是直接使用k-1作为初始下标,如果k大于total,则取模:k = (k-1) % total,然后初始位置为k。 但为了符合用户习惯,我们要求用户输入1~total之间的整数。 代码修改如下:</think>我将基于约瑟夫环问题实现一个解决方案,使用环形链表模拟游戏过程,最终输出胜利者编号。以下是完整实现代码: ```cpp #include <iostream> #include <vector> using namespace std; // 小孩节点类 class Child { public: int id; // 小孩编号 Child* next; // 指向下一个小孩 Child(int id) : id(id), next(nullptr) {} }; // 约瑟夫环游戏类 class JosephGame { private: Child* first = nullptr; // 环形链表起始节点 int total; // 总人数 int start; // 起始位置 int step; // 报数步长 public: // 初始化游戏 JosephGame(int total, int start, int step) : total(total), start(start), step(step) { createCircle(); } // 创建环形链表 void createCircle() { Child* prev = nullptr; for (int i = 1; i <= total; i++) { Child* child = new Child(i); if (first == nullptr) { first = child; first->next = first; // 形成自环 } else { prev->next = child; child->next = first; // 新节点指向头节点形成环 } prev = child; } } // 执行游戏并返回胜利者 int simulate() { // 定位到起始位置 Child* current = first; for (int i = 1; i < start; i++) { current = current->next; } // 模拟游戏过程 while (current->next != current) { // 当不止一人时继续 // 找到出局者的一个位置 for (int i = 1; i < step - 1; i++) { current = current->next; } // 移除出局者 Child* out = current->next; cout << "出局: " << out->id << endl; // 更新链表 current->next = out->next; current = current->next; // 从下一个继续报数 // 处理边界情况 if (out == first) first = current; delete out; } // 返回胜利者 return current->id; } ~JosephGame() { if (first) { Child* current = first->next; while (current != first) { Child* temp = current; current = current->next; delete temp; } delete first; } } }; int main() { int total, start, step; cout << "===== 约瑟夫环游戏 =====" << endl; cout << "总人数: "; cin >> total; cout << "起始位置: "; cin >> start; cout << "报数步长: "; cin >> step; JosephGame game(total, start, step); int winner = game.simulate(); cout << "\n最终胜利者: 第" << winner << "号小孩" << endl; return 0; } ``` ### 代码说明 1. **环形链表实现**: - 使用`Child`类表示每个小孩节点 - `next`指针指向下一个小孩形成环形结构 - 创建链表时确保首尾相连形成闭环 2. **游戏流程**: - `createCircle()`:初始化环形链表 - `simulate()`:执行游戏过程 - 定位到起始位置 - 循环报数直到只剩一人 - 每次移除报数到步长的小孩 - 更新链表指针保持环形结构 3. **数学原理**: - 出局位置计算:$position = (current + step - 1) \mod n$ - 时间复杂度:$O(n \times step)$ 4. **内存管理**: - 析构函数负责释放链表内存 - 出局节点即时删除防止内存泄漏 ### 运行示例 ``` ===== 约瑟夫环游戏 ===== 总人数: 5 起始位置: 1 报数步长: 2 出局: 2 出局: 4 出局: 1 出局: 5 最终胜利者: 第3号小孩 ``` ### 算法优化 对于大规模问题,可以使用数学公式直接计算胜利者位置: $$f(n,k) = (f(n-1,k) + k) \mod n$$ 其中$f(1,k)=0$,时间复杂度$O(n)$[^1]。但链表模拟更直观展示过程。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

马鸣风萧萧222

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值