根据条件拆分STL列表
Splitting an STL list based on a condition
我有一个std::列表,看起来像这样(x标记表示小于500的数字)
x,x,x,x,503,x,x,x,510,x,x,x,502,x,x,x,x,x,x,600 - std::list<int> originallist
我希望将列表拆分为列表std::vector<std::list<int> >
的向量,如下所示
1st element of vector: x,x,x,x,503
2nd element of vector: x,x,x,510
...
...
last element of vector: x,x,x,x,x,x,600
我现在的代码如下:
list<int> templist; vector<list<int> > v;
for(list<int>::iterator lit=originallist.begin(); lit!=oriniallist.end(); ++lit) {
if (*lit > 500) {
templist.push_back(*lit);v.push_back(templist); templist.clear(); continue;
}
templist.push_back(*lit);
}
在c++中不使用templist实现上述任务的最有效方法是什么?
虽然此解决方案确实使用临时std::list
,但它不分配列表节点元素,并且在c++ 03情况下只分配1个内存(c++ 11情况下根据返回值的大小分配对数内存)
这是一个c++ 03的解决方案。c++ 11的解决方案可以一次完成。
bool big_as_500( int x ) {return x>=500;}
std::vector< std::list< int > > do_stuff( std::list<int>& original_list ) {
// we have to do this, because resizing the return value involves lots of allocations
// and stuff in C++03, so make sure we get the size right by precalculating it:
std::size_t count = std::count_if( originallist.begin(), originallist.end(), big_as_500 );
std::vector< std::list< int > > result;
result.reserve(count+1);
typedef std::list<int>::const_iterator const_iterator;
std::list< int > current;
for(const_iterator it= originallist.begin(); it!=originallist.end();/*nothing*/) {
++it; // about to invalidate it! (or move lists)
current.splice( current.end(), originallist, originallist.begin() ); // O(1) no memory allocation
if (big_as_500(current.back())) {
result.push_back( std::list<int>() );
current.swap( result.back() );
}
}
// original problem does not specify what to do if the original list does not end
// with an element "big_as_500", so I'll just drop them
return result; // rely on NRVO to eliminate the copy here, if your compiler does not
// support it, take result as a reference parameter.
}
c++ 11解决方案:
std::vector< std::list< int > > do_stuff( std::list<int>& original_list ) {
std::vector< std::list< int > > result;
typedef std::list<int>::const_iterator const_iterator;
std::list< int > current;
for(const_iterator it= originallist.begin(); it!=originallist.end();/*nothing*/) {
++it;// about to become invalid/in wrong list
current.splice( current.end(), originallist, originallist.begin() ); // O(1) no memory allocation
if (current.back() >= 500) {
result.emplace_back( std::move(current) );
}
}
// original problem does not specify what to do if the original list does not end
// with an element "big_as_500", so I'll just drop them
return result; // will NRVO, or move, so no worries
}
在c++ 11中,调整大小是相对便宜的,所以我们很好。
现在,我们可以在c++ 03中得到真正的幻想,并模仿c++ 11所做的一切,并一次完成所有这些。
template<typename T, typename A>
void efficient_grow_by_1( std::vector<T,A>& make_one_bigger ) {
if (make_one_bigger.size()+1 > make_one_bigger.capacity() )
{
std::vector<T, A> swap_vec;
swap_vec.reserve( (make_one_bigger.size()+1)*5/3 );
for (std::vector<T, A>::iterator it = make_one_bigger.begin(); it != make_one_bigger.end(); ++it ) {
using std::swap;
swap_vec.push_back();
std::swap( *it, swap_vec.back() );
}
swap_vec.swap( make_one_bigger );
}
make_one_bigger.push_back();
}
void do_stuff( std::list<int>& original_list, std::vector< std::list< int > >& result ) {
typedef std::list<int>::const_iterator const_iterator;
std::list< int > current;
for(const_iterator it= originallist.begin(); it!=originallist.end();) {
++it;
current.splice( current.end(), originallist, originallist.begin() ); // O(1) no memory allocation
if (current.back()>=500) {
efficient_grow_by_1(result);
current.swap( result.back() );
}
}
// original problem does not specify what to do if the original list does not end
// with an element "big_as_500", so I'll just drop them
}
这是相当疯狂的,所以我建议升级你的编译器。
这里的技巧是我们用每次一个元素的splice
填充"临时"列表。因为(最多?许多?)std::list::splice
的实现最终不得不遍历元素以对它们进行计数(这在c++ 11中是必需的,在c++ 03中很常见),当我们确定要将哪些元素放入下一个块时,一次执行一个,这是相当有效的。每个节点直接来自输入列表,并被收集到临时列表中(没有内存分配)。
一旦我们建立了这个列表,我们直接将其swap
放入 list
s的输出vector
中。这避免了任何内存分配,除了需要保存(相对较小的)list
的基本数据。
在c++ 03中,我们要么做一个两步解决方案并预先计算std::vector
的输出有多大,要么在包含的list
s上通过谨慎的增长和swap
机制模拟c++ 11 move
的效率。你的std
库实现可能已经做到了这一点,但我不确定swap
- resize
优化在旧库中有多常见。
将事情减少到一次传递可能值得第二个c++ 03和c++ 11解决方案使用的对数数量的分配:遍历std::list
是对缓存失败的练习。
第三版
此版本使用std::list::splice
并移动迭代器,直到找到delim
iter或到达end()
。
#include <iostream>
#include <list>
#include <vector>
std::vector< std::list<int> > & split( std::list<int> v,
int delim, std::vector< std::list<int> >& elems) {
auto it = v.begin();
while ( it != v.end()) {
std::list<int> l;
while ( it != v.end() && *it < delim) {
++it;
}
if( it != v.end()) {
l.splice( l.begin(), v, v.begin(), ++it);
it = v.begin();
} else {
l.splice( l.begin(), v, v.begin(), it);
}
elems.push_back( l);
}
return elems;
}
std::vector< std::list<int> > split( const std::list<int> &v, int delim) {
std::vector< std::list<int> > elems;
split( v, delim, elems);
return elems;
}
用法:
int main() {
std::list<int> v = { 1, 2, 3, 503, 5, 6, 502, 7, 510, 3, 500, 6, 7};
std::vector< std::list<int> > vl;
vl = split( v, 500);
int i = 0;
while( i < vl.size()) {
std::list<int>::const_iterator it = vl[ i].begin();
while( it != vl[ i].end())
std::cout << *it++;
std::cout << std::endl;
++i;
}
return 0;
}
http://ideone.com/VRpGft 打印:123503年
56502年7510年3500年67年第一个版本此版本使用std::list::splice
.
#include <iostream>
#include <list>
#include <vector>
std::vector< std::list<int> > & split( std::list<int> v,
int delim, std::vector< std::list<int> >& elems) {
auto it = v.begin();
while ( it != v.end()) {
std::list<int> l;
auto it3 = l.begin();
while ( it != v.end() && *it < delim) {
l.splice( it3, v, it);
it = v.begin();
}
if( it != v.end()) {
l.splice( it3, v, it);
it = v.begin();
}
elems.push_back( l);
}
return elems;
}
std::vector< std::list<int> > split( const std::list<int> &v, int delim) {
std::vector< std::list<int> > elems;
split( v, delim, elems);
return elems;
}
用法:
int main() {
std::list<int> v = { 1, 2, 3, 503, 5, 6, 502, 7, 510, 3, 500, 5, 9};
std::vector< std::list<int> > vl;
vl = split( v, 500);
int i = 0;
while( i < vl.size()) {
std::list<int>::const_iterator it = vl[ i].begin();
while( it != vl[ i].end())
std::cout << *it++;
++i;
}
return 0;
}
打印:
123503565027510350059
http://ideone.com/1xMehy 第二版这是简化版本,不使用std::list::splice
函数。该函数将元素放在迭代器前面,因此必须稍微改变循环。
#include <iostream>
#include <list>
#include <vector>
std::vector< std::list<int> > & split( const std::list<int> & v,
int delim, std::vector< std::list<int> >& elems) {
std::list<int>::const_iterator it = v.begin();
while ( it != v.end()) {
std::list<int> l;
while ( it != v.end() && *it < delim) {
l.push_back( *it++);
}
if( it != v.end()) l.push_back( *it++);
elems.push_back( l);
}
return elems;
}
std::vector< std::list<int> > split( const std::list<int> &v, int delim) {
std::vector< std::list<int> > elems;
split( v, delim, elems);
return elems;
}
用法:
int main() {
std::list<int> v = { 1, 2, 3, 503, 5, 6, 502, 7, 510, 3, 500, 5, 9};
std::vector< std::list<int> > vl;
vl = split( v, 500);
int i = 0;
while( i < vl.size()) {
std::list<int>::const_iterator it = vl[ i].begin();
while( it != vl[ i].end())
std::cout << *it++;
++i;
}
return 0;
}
打印:
123503565027510350059
http://ideone.com/MBmlLE试试下面的
#include <vector>
#include <list>
#include <algorithm>
#include <functional>
//...
auto first = YourList.begin();
while ( first != YourList.end() )
{
auto last = std::find_if( first, YourList.end(), std::bind2nd( std::greater<int>(), 500 ) );
if ( last != YourList.end() ) ++last;
YourVector.push_back( std::list<int>( first, last ) );
first = last;
}
-
循环遍历数字并获得需要拆分列表的位置之间的距离
-
使用List中的splice函数对每个分割位置:
http://www.cplusplus.com/reference/list/list/splice/lst.splice( newLst.begin(), newLst, lst.begin(), lst.begin() + sliceLength);
(注意,splice将破坏原始列表)
- 如何检查C ++ STL列表是否为回文?
- 清除 C++ 中的指针的 STL 列表
- 在Visual Studio 2013中编译的STL列表代码在Visual Studio 2019中给出了错误.想知道原
- 使用.txt文件填充 STL 列表不起作用
- 为 STL 列表编写选择排序
- 如何从 STL 列表中删除结构记录
- C++如何将 STL 列表传递给函数
- 漂亮的打印不适用于C ++ STL列表
- 在C++中,是否可以引用像C++中的stl列表这样的数据结构部分
- 如何根据STL列表中的元素数量分配内存
- 我怎么知道,如果我在 STL 列表中找到了我搜索的号码
- 打印列表列表C++ STL 列表
- 我们可以在穿越时插入STL列表吗?
- 使用 c++ 的 STL 列表 ..在传递列表指针的数组中
- 使用 C++11 迭代语法时从 STL 列表中删除
- 如何使用静态 stl 列表的迭代器
- 如何更改 stl 列表中项的值
- STL列表,删除所有奇数
- 如何将函数中的stl列表传递为C 中的参数
- 如何将结构添加到STL列表中