【问题标题】:cpp move some elements before position after this position at std::listcpp 在 std::list 的这个位置之后移动位置之前的一些元素
【发布时间】:2012-05-27 11:09:56
【问题描述】:

我有std::list 例如。带整数:9 10 8 25 70 75 30 14 80

我想在some_position_number 元素之后移动小于10 的所有元素,例如。 = 5。移动对象的初始顺序很重要,必须与移动后的初始顺序相同。

换句话说,最后需要接收some_position_number元素falsetrue之后的元素

就像第一个例子一样:10 25 70 75 30 9 *8* 14 80

第二个首字母:9 3 8 25 70 75 30 14 80 第二个结果:10 25 70 75 30 9 *3* 8 14 80

第三个首字母:25 70 75 30 14 9 3 8 80 第三个结果:25 70 75 30 14 9 3 8 80(开头已经是5)

4 首字母:3 4 1 2 3 9 3 8 80 4 结果:9 3 8 80 3 4 1 2 3(类似这样)似乎在这里some_position_number 必须用作阈值或80 3 4 1 2 3 9 3 8 也接受,但似乎需要检查 end() 和无限循环?

如何做到这一点最有效,也许不需要额外的list 以避免不必要的对象创建和擦除?因为在真正的应用程序中,std::list 没有整数,而是对象。也许 std::splice?以某种方式选择需要移动的对象,而不是找到新位置并将每个元素 std::splice 到它。

【问题讨论】:

  • list::splice 可以帮助移动列表节点而无需销毁和重新创建。
  • 谢谢,是的,我知道,并且已经添加了这个标签,但是我的尝试是错误的。我在拼接迭代器以及当它们去invalid 时对迭代器感到困惑。以及如何选择 9 和 8 来计算没有它们的新位置...已经在上一个问题中发布了我的 attemts 代码,但它增加了混乱,我将其删除并创建新的。

标签: c++ list std splice


【解决方案1】:

It's ugly, but it works 我相信它可以正确处理所有迭代器失效情况:

#include <iostream>
#include <list>

using namespace std;

list<int> l;

// prototypes for various helpers of no consequence to the question
void  init();
bool my_pred( list<int>::value_type val);
void dump_list( list<int> const& l);


typedef list<int>::iterator iter_t;

int main() 
{
    init();
    dump_list(l);

    // we want to remove elements that meet the predicate until
    // there are `some_position_number` elements that didn't meet 
    // the predicate

    int some_position_number = 5;
    list<int> tmp_list;

    iter_t i = l.begin();
    for (int count = 0; count < some_position_number && i != l.end(); ) {
        iter_t tmp(i);
        ++i;
        if (my_pred(*tmp)) {
            tmp_list.splice( tmp_list.end(), l, tmp); // remove an element
        }
        else {
            ++count;
        }
    }

    // now i points at the position we want to insert the elements we removed:

    l.splice( i, tmp_list);

    dump_list(l);
}




bool my_pred( list<int>::value_type val)
{
    return val < 10;
}

void  init()
{
    l.push_back(9);
    l.push_back(10);
    l.push_back(8);
    l.push_back(25);
    l.push_back(70);
    l.push_back(75);
    l.push_back(30);
    l.push_back(14);
    l.push_back(80);
}

void dump_list( list<int> const& l)
{
    for (list<int>::const_iterator i = l.begin(); i != l.end(); ++i) {
        cout << *i << " ";
    }

    cout << endl;
}

关键是:

  • 用于遍历可能被移动的元素范围的迭代器i 在调用splice() 之前必须被复制然后递增。当splice()被调用时,原来的i(现在的tmp)就失效了。
  • 我们将要移动的元素拼接到一个临时列表中。虽然这需要第二个列表,但它仍然不涉及元素的副本 - 我们只是将它们移动到其他地方以方便记账。
  • 记录不满足谓词的元素的数量 - 这让我们可以在移动时找出插入点,以检查要移动的元素。

【讨论】:

  • 谢谢,是的,它几乎正是我所需要的,但似乎是我的描述错误。 (这是我的英语技能,抱歉 :( )但 new_position 不是固定的,它的5 不是7 例如。得到my_pred(*tmp)= 5 个整数表示错误,然后移动真正的元素。如果初始:9 **3** 8 25 70 75 30 14 80 新列表必须是25 70 75 30 14 9 3 8 80(5 false,然后是新的)。似乎您的示例可以修改,但不知何故需要避免范围太低以获取请求范围的情况。(例如,如果从一开始所有 emements = true 就不要在之前insert_point)
  • 我坐着,思考和尝试。换句话说,这个问题似乎可以描述为:'用最接近的假代替真整数,而它们不会在position',但也很丑:(
  • @abrahab 你想要什么还不是很清楚。 some_position_number 是否取决于需要移动的 多少 元素? (你也应该编辑你的问题)
  • @abrahab:我已经修改了示例以遵循我认为您明确的意图。它确实使用了第二个列表,但由于所有移动操作仍然是拼接,因此没有复制元素,只是更新列表指针。
  • @abrahab:我认为更新后的答案符合那些额外的测试(它为测试#4 产生了“替代”可接受的输出)。对于测试#4,我认为提出一个产生9 3 8 80 3 4 1 2 3 输出的解决方案会增加很多复杂性,但我没有考虑太多。
猜你喜欢
  • 2012-05-22
  • 1970-01-01
  • 2022-01-12
  • 2017-10-19
  • 1970-01-01
  • 1970-01-01
  • 2017-06-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多