C++ c++;迭代器的stl兼容迭代器
我想做什么 我有一个划分事物的方法。此方法不会对数组进行完全排序;它只是简单地对数组进行分区,使一侧的所有元素(某些预先确定的“中心”或“中点值”-不必导致均匀分割)小于“中心”,而另一侧的所有元素都大于中心。要点:它不是传统意义上的“排序”;这是一个分区 当我划分事物时,我需要保留一把钥匙;这样,当事物被交换时,钥匙被交换;如果将来某个时候我想撤销分区,我可以根据密钥重新安排 显然,要根据键值重新安排事情,我可以这样做C++ c++;迭代器的stl兼容迭代器,c++,stl,iterator,C++,Stl,Iterator,我想做什么 我有一个划分事物的方法。此方法不会对数组进行完全排序;它只是简单地对数组进行分区,使一侧的所有元素(某些预先确定的“中心”或“中点值”-不必导致均匀分割)小于“中心”,而另一侧的所有元素都大于中心。要点:它不是传统意义上的“排序”;这是一个分区 当我划分事物时,我需要保留一把钥匙;这样,当事物被交换时,钥匙被交换;如果将来某个时候我想撤销分区,我可以根据密钥重新安排 显然,要根据键值重新安排事情,我可以这样做 std::vector< std::pair< std::si
std::vector< std::pair< std::size_t , my::thingie > > vp;
std::vector< std::size_t >::iterator itKey( key.begin() );
// itThingie_begin and itThingie_end exist; I don't have direct access to the container
my::thingie::iterator itThingie( itThingie_begin );
for (; itKey != key.end(); ++itKey; ++itThingie ) vp.push_back( *itKey, *itThingie );
std::sort( vp.begin() , vp.end() , &comp_pair_first );
itThingie = itThingie_begin;
for ( std::vector< std::pair< std::size_t , my::thingie > >::const_iterator p=vp.begin(); p!=vp.end(); ++p, ++itThingie ) *itThingie = p->second;
std::vector>vp;
std::vector::迭代器itKey(key.begin());
//它开始和结束都存在;我无法直接进入集装箱
my::thingie::迭代器itThingie(itThingie_begin);
对于(;itKey!=key.end();++itKey;++itThingie)vp.push_back(*itKey,*itThingie);
std::sort(vp.begin()、vp.end()、&comp\u pair\u first);
itThingie=itThingie\u begin;
对于(std::vector>::常量迭代器p=vp.begin();p!=vp.end();++p,++itThingie)*itThingie=p->second;
也就是说,我可以将所有密钥和数据复制成一对;并使用自定义比较谓词(或使用boost::bind)按其第一个值(键)对该对进行排序;然后再次复制所有数据。我明白。这并不理想,因为我可能有几百兆的内容,上面的方法包括将其复制到临时文件,对临时文件进行排序,然后将其复制回来
这也是不理想的,因为我的分区方法(正如它目前存在的那样)需要键和thingie的开始和结束迭代器(因为它每次交换时都必须交换这两个迭代器)。此外,-这里是关键-如果有两组东西,我必须重写我的分区方法;我有一个密钥,一个决定分区侧面的东西,还有另一个行李东西,它有我想用于其他算法的其他信息
现在,很明显,我不想每次都重写分区方法,我想包括一些其他迭代器来与分区交换“in-tandom”。
所以,像以前一样,我可以将所有这些内容复制到一个临时的std::pair(或者嵌套对,如果我需要串联交换更多内容),然后通过查看std::pair::first对其进行分区,然后将临时数据复制回来。。。
但这是非常浪费的,因为我添加的每一个额外的“行李”内容也可能是数百兆字节
我知道我可以那样做。我不想那样做,因为它太占用内存了
我想要的方式
我上面描述的问题仅仅是在迭代器上串联操作的问题之一。因此,我希望有一个迭代器集合,可以抽象出该集合的内容
我想要一个迭代器集合。我将该集合称为piter(它是一对迭代器)。当交换两个piter时,实际上是在第一个迭代器(以及第二个迭代器)上进行std::iter_交换
我想要一个piter迭代器(称为piter迭代器),它具有迭代器的所有特性,但是当它递增和递减时,它会递增和递减piter的第一个和第二个迭代器。当piter取消引用时,它应该返回对piter的引用,piter是迭代器的集合。所有的距离都可以通过第一个piter组件来测量。或者更一般地说,如果有任何问题需要回答,并且不清楚迭代器应该回答什么,那么piter的第一个迭代器应该回答它
如果我想创建一个可以在多个迭代器上使用tandom迭代器的piterator,我可以创建一个piterator,其piter包含一个迭代器(第一个)和另一个piterator(第二个)
下面是我尝试过的(我也尝试过使用boost::iterator_facade,但最终遇到了相同的问题,如下所述)
#包括
#包括
#包括
#包括
#包括
//
//迭代器对
//
模板
结构piter:public std::pair
{
piter():std::pair(){};
piter(T常数和l,U常数和r):std::pair(l,r){;
piter(std::pair const&p){this->first=p.first;this->second=p.second;};
//piter(std::pair const p){this->first=p.first;this->second=p.second;};
模板
piter(piter const&p):std::pair::first(p.first),std::pair::second(p.second){
piter和operator=(piter const和rhs)
{
如果(&rhs!=this){*this->first=*rhs.first;*this->second=*rhs.second;}
归还*这个;
};
好友无效交换(piter&lhs、piter&rhs)
{
使用std::swap;
std::cout mp.first=rhs.first;this->mp.second=rhs.second;};
piterator(value_type const rhs){this->mp.first=rhs.first;this->mp.second=rhs.second;};
iter和操作员=(iter常量和rhs)
{
如果(&rhs!=this){this->mp.first=rhs.mp.first;this->mp.second=rhs.mp.second;};
归还*这个;
}
朋友无效交换(iter和lhs、iter和rhs)
{
使用std::swap;
std::cout首先,您应该意识到,std::nth_元素
已经完成了您描述的分区。它找到了第n个元素,正如您所期望的那样,但它也将数据分为两部分——所有比您找到的元素小的元素都将位于集合中较低的位置,所有较大的元素都将位于集合中较低的位置右边是r元素
就我个人而言,我认为我会做一些不同的事情:如果你仍然需要数据的原始顺序,但也需要以其他顺序对其进行排序,那么创建一个排序索引,并保留原始数据
#include <vector>
#include <iostream>
#include <algorithm>
#include <utility>
#include <iterator>
//
// pair of iterators
//
template <typename T,typename U>
struct piter : public std::pair<T,U>
{
piter() : std::pair<T,U>() {};
piter( T const & l , U const & r ) : std::pair<T,U>(l,r) {};
piter( std::pair<T,U> const & p ) { this->first = p.first; this->second = p.second; };
//piter( std::pair<T,U> const p ) { this->first = p.first; this->second = p.second; };
template <typename OT, typename OU>
piter( piter<OT,OU> const & p ) : std::pair<T,U>::first(p.first), std::pair<T,U>::second(p.second) {}
piter<T,U> & operator=( piter<T,U> const & rhs )
{
if( &rhs != this ) { *this->first = *rhs.first; *this->second = *rhs.second; }
return *this;
};
friend void swap( piter<T,U> & lhs, piter<T,U> & rhs )
{
using std::swap;
std::cout << "piter::swap; WAS: " << *lhs.first << " <-> " << *rhs.first << std::endl;
std::iter_swap(lhs.first,rhs.first);
std::iter_swap(lhs.second,rhs.second);
std::cout << "piter::swap; NOW: " << *lhs.first << " <-> " << *rhs.first << std::endl;
};
};
//
// iterator of pair of iterators
//
template <typename T, typename U>
class piterator : public std::iterator< std::random_access_iterator_tag,
piter<T,U>,
std::ptrdiff_t,
piter<T,U> *,
piter<T,U> & >
{
typedef piterator<T,U> iter;
public: // Traits typedefs, which make this class usable with algorithms which need a random access iterator.
typedef std::random_access_iterator_tag iterator_category;
typedef piter<T,U> value_type;
typedef std::ptrdiff_t difference_type;
typedef piter<T,U> * pointer;
typedef piter<T,U> & reference;
public:
piterator() {};
piterator( iter const & rhs ) { this->mp.first = rhs.mp.first; this->mp.second = rhs.mp.second;};
piterator( pointer rhs ) { this->mp.first = rhs->first; this->mp.second = rhs->second; };
//piterator( reference const rhs ) { this->mp.first = rhs.first; this->mp.second = rhs.second; };
piterator( value_type const rhs ) { this->mp.first = rhs.first; this->mp.second = rhs.second; };
iter & operator=( iter const & rhs )
{
if ( &rhs != this ){ this->mp.first = rhs.mp.first; this->mp.second = rhs.mp.second; };
return *this;
}
friend void swap( iter & lhs , iter & rhs )
{
using std::swap;
std::cout << "piterator::swap; WAS: lhs " << *lhs->first << " rhs " << *rhs->first << std::endl;
swap(lhs.mp,rhs.mp);
std::cout << "piterator::swap; NOW: lhs " << *lhs->first << " rhs " << *rhs->first << std::endl;
}
public: // Comparison
// Note: it's an error to compare iterators over different files.
bool operator< ( iter const & rhs ) const { return mp.first < rhs.mp.first; }
bool operator> ( iter const & rhs ) const { return mp.first > rhs.mp.first; }
bool operator==( iter const & rhs ) const { return mp.first == rhs.mp.first; }
bool operator!=( iter const & rhs ) const { return mp.first != rhs.mp.first; }
public: // Iteration
iter & operator++() { ++mp.first; ++mp.second; return *this; }
iter & operator--() { --mp.first; --mp.second; return *this; }
iter operator++(int) { iter tmp(*this); ++(*this); return tmp; }
iter operator--(int) { iter tmp(*this); --(*this); return tmp; }
public: // Step
iter & operator+=( difference_type n ) { mp.first += n; mp.second += n; return *this; }
iter & operator-=( difference_type n ) { mp.first -= n; mp.second -= n; return *this; }
iter operator+ ( difference_type n ) { iter result(*this); return result += n; }
iter operator- ( difference_type n ) { iter result(*this); return result -= n; }
public: // Distance
difference_type operator-( iter & rhs ) { return mp.first - rhs.mp.first; }
public: // Access
reference operator*() { return mp; }
reference operator[]( difference_type n ) { return *(*this+n); }
pointer operator->() { return ∓ };
private: // State
value_type mp;
};
template<class T,class U>
bool proxy_comp( piter<T,U> left, piter<T,U> right )
{
std::cout << "proxy_comp: " << *(left.first) << " > " << *(right.first) << " ?=? " << ( *(left.first) > *(right.first) ) << std::endl;
return *left.first > *right.first;
}
int main()
{
std::vector<double> dv(3);
std::vector<int> iv(3);
dv[0] = -0.5; dv[1] = -1.5; dv[2] = -2.5;
iv[0] = 10; iv[1] = 20; iv[2] = 3;
typedef piterator< std::vector<int>::iterator , std::vector<double>::iterator > PAIR_ITER;
typedef PAIR_ITER::value_type PAIR_REF;
PAIR_ITER pair_begin( PAIR_REF( iv.begin() , dv.begin() ) );
PAIR_ITER pair_end( PAIR_REF( iv.end() , dv.end() ) );
std::cout << "paired arrays now:" << std::endl;
for ( PAIR_ITER p = pair_begin; p != pair_end; ++p )
std::cout << *p->first << " " << *p->second << std::endl;
std::cout << "swap 1st and 3rd elements..." << std::endl;
swap(*pair_begin,*(pair_begin+2));
std::cout << "paired arrays now:" << std::endl;
for ( PAIR_ITER p = pair_begin; p != pair_end; ++p )
std::cout << *p->first << " " << *p->second << std::endl;
std::cout << "calling sort..." << std::endl;
std::sort( pair_begin , pair_end , &proxy_comp<std::vector<int>::iterator , std::vector<double>::iterator> );
std::cout << "paired arrays now:" << std::endl;
for ( PAIR_ITER p = pair_begin; p != pair_end; ++p )
std::cout << *p->first << " " << *p->second << std::endl;
return 0;
}
paired arrays now:
10 -0.5
20 -1.5
3 -2.5
swap 1st and 3rd elements...
piter::swap; WAS: 10 <-> 3
piter::swap; NOW: 3 <-> 10
paired arrays now:
3 -2.5
20 -1.5
10 -0.5
calling sort...
proxy_comp: 20 > 3 ?=? 1
proxy_comp: 10 > 3 ?=? 1
paired arrays now:
3 -2.5
3 -2.5
3 -2.5
std::vector<int> index(data.size());
template <class T>
struct cmp {
T const &data;
public:
cmp(T const &array) : data(array) {}
bool operator()(int a, int b) { return data[a] < data[b]; }
};
for (int i=0; i<index.size(); i++)
index[i] = i;
std::sort(index.begin(), index.end(), cmp(your_data));
if (__comp(*__i, *__first))
{
// COPY VALUE INTO TEMPORARY MEMORY
typename iterator_traits<_RandomAccessIterator>::value_type __val = _GLIBCXX_MOVE(*__i);
// MOVE MEMORY AROUND
_GLIBCXX_MOVE_BACKWARD3(__first, __i, __i + 1);
// COPY TEMPORARY VALUE BACK
*__first = _GLIBCXX_MOVE(__val);
}
value_type operator*() const { return helper_class_value_collection_ctor( _args_ ); };
*piterator_a = *piterator_b
reference operator*() { return private_reftype_variable; };
#include <vector>
#include <iostream>
#include <utility>
#include <iterator>
#include <algorithm>
// forward decl
template <typename T,typename U> struct piterator_iterators;
template <typename T,typename U>
struct piterator_values
{
// This class holds memory; it is a value_type
// It only serves the purpose of
// allowing the stl to hold temporary values when moving memory around.
// If the stl called sort(), then this class wouldn't be necessary.
//
// Note that the memory may be set by a piterator_iterators class,
// which is a pseudo-value_type that points at memory, instead of holding memory.
//
// YOU NEED THIS SO THAT
// typename piterator<T,U>::value_type Tmp = *piterator_a
// PLACES THE VALUES INTO SOME (ACTUAL) TEMPORARY MEMORY, AS OPPOSED
// TO CREATING A NEW POINTER TO EXISTING MEMORY.
typedef typename T::value_type first_value;
typedef typename U::value_type second_value;
first_value first;
second_value second;
piterator_values() {};
piterator_values( first_value const & first , second_value const & second ) : first(first), second(second) {};
piterator_values( piterator_values<T,U> const & rhs ) : first(rhs.first), second(rhs.second) { };
piterator_values( piterator_iterators<T,U> const & rhs ) : first(*rhs.first), second(*rhs.second) { };
piterator_values<T,U> & operator=( piterator_values<T,U> const & rhs )
{
if( &rhs != this )
{
first = rhs.first;
second = rhs.second;
}
return *this;
};
piterator_values<T,U> & operator=( piterator_iterators<T,U> const & rhs )
{
if( &rhs != this )
{
first = *rhs.first;
second = *rhs.second;
}
return *this;
};
friend void swap( piterator_values<T,U> & lhs, piterator_values<T,U> & rhs )
{
using std::swap;
swap(lhs.first,rhs.first);
swap(lhs.second,rhs.second);
};
};
template <typename T,typename U>
struct piterator_iterators
{
T first;
U second;
// This class does not hold memory; it points at existing memory.
// It is a pseudo-value_type. When the piterator dereferences, it
// will return a piterator_iterators object IF it is a nonconst reference.
// This class is used as a "reference" for an actual iterator,
// so assignment operators change the value of the thing pointed at,
// as opposed to reseting the address of what is being pointed at.
//
// YOU NEED THIS SO THAT
// *piterator_a = *piterator_b
// MAKES SENSE.
// IF THE DEREFERENCE PASSED A piterator_values,
// THEN IT WOULD ONLY MODIFY A TEMPORARY, NOT THE ACTUAL THING
//
piterator_iterators() {};
piterator_iterators( T const & first , U const & second ) : first(first), second(second) {};
piterator_iterators( piterator_iterators<T,U> const & rhs ) : first(rhs.first), second(rhs.second) {};
piterator_iterators<T,U> & operator=( piterator_iterators<T,U> const & rhs )
{
if( &rhs != this )
{
*first = *rhs.first;
*second = *rhs.second;
}
return *this;
};
piterator_iterators<T,U> & operator=( piterator_values<T,U> const & rhs )
{
*first = rhs.first;
*second = rhs.second;
return *this;
};
friend void swap( piterator_iterators<T,U> & lhs, piterator_iterators<T,U> & rhs )
{
using std::swap;
std::iter_swap(lhs.first,rhs.first);
std::iter_swap(lhs.second,rhs.second);
};
};
//
// iterator of pair of iterators
//
template <typename T, typename U>
class piterator : public std::iterator< std::random_access_iterator_tag, piterator_values<T,U>, std::ptrdiff_t, piterator_iterators<T,U> *, piterator_iterators<T,U> & >
{
typedef piterator<T,U> iter;
public:
typedef std::random_access_iterator_tag iterator_catagory;
typedef typename piterator<T,U>::value_type value_type;
typedef typename piterator<T,U>::difference_type difference_type;
typedef typename piterator<T,U>::pointer pointer;
typedef typename piterator<T,U>::reference reference;
typedef piterator_iterators<T,U> value_of_reference;
//typedef typename piterator_iterators<T,U> & reference;
public:
piterator() {};
piterator( iter const & rhs ) { mp.first = rhs.mp.first; mp.second = rhs.mp.second; };
piterator( value_of_reference const rhs ) { mp.first = rhs.first; mp.second = rhs.second; };
piterator( T const first, U const second ) { mp.first = first; mp.second = second; };
iter & operator=( iter const & rhs )
{
if ( &rhs != this )
{
mp.first = rhs.mp.first;
mp.second = rhs.mp.second;
};
return *this;
}
friend void swap( iter & lhs , iter & rhs )
{
using std::swap;
swap(lhs.mp,rhs.mp);
}
public: // Comparison
bool operator< ( iter const & rhs ) const { return mp.first < rhs.mp.first; }
bool operator> ( iter const & rhs ) const { return mp.first > rhs.mp.first; }
bool operator==( iter const & rhs ) const { return mp.first == rhs.mp.first; }
bool operator!=( iter const & rhs ) const { return mp.first != rhs.mp.first; }
public: // Iteration
iter & operator++() { ++(mp.first); ++(mp.second); return *this; }
iter & operator--() { --(mp.first); --(mp.second); return *this; }
iter operator++(int) { iter tmp(*this); ++(*this); return tmp; }
iter operator--(int) { iter tmp(*this); --(*this); return tmp; }
public: // Step
iter & operator+=( difference_type n ) { mp.first += n; mp.second += n; return *this; }
iter & operator-=( difference_type n ) { mp.first -= n; mp.second -= n; return *this; }
iter operator+ ( difference_type n ) { iter result(*this); return result += n; }
iter operator- ( difference_type n ) { iter result(*this); return result -= n; }
difference_type operator+ ( iter const & rhs ) { return mp.first + rhs.mp.first; }
difference_type operator- ( iter const & rhs ) { return mp.first - rhs.mp.first; }
public: // Distance
difference_type operator-( iter & rhs ) { return mp.first - rhs.mp.first; }
public: // Access
// reference if on the lhs of the eq.
reference operator*() { return mp; }
// value if on the rhs of the eq.
value_type operator*() const { return value_type(*mp.first,*mp.second); }
reference operator[]( difference_type n ) { return *( (*this) + n ); }
pointer operator->() { return ∓ };
private: // State
value_of_reference mp;
};
////////////////////////////////////////////////////////////////
template<class T,class U>
bool proxy_comp( piterator_values<T,U> left, piterator_values<T,U> right )
{
return left.first < right.first;
}
///////////////////////////////////////////////////////////////
int main()
{
std::vector<double> dv1(3);
std::vector<double> dv2(3);
std::vector<int> iv(3);
dv1[0] = -0.5; dv1[1] = -1.5; dv1[2] = -2.5;
dv2[0] = 10.5; dv2[1] = 11.5; dv2[2] = 12.5;
iv[0] = 10; iv[1] = 20; iv[2] = 3;
//
// EXAMPLE 1: PAIR OF ITERATORS
//
typedef piterator< std::vector<int>::iterator , std::vector<double>::iterator > PAIR_ITER;
PAIR_ITER pair_begin( iv.begin() , dv1.begin() );
PAIR_ITER pair_end( iv.end() , dv1.end() );
std::cout << "paired arrays now:" << std::endl;
for ( PAIR_ITER p = pair_begin; p != pair_end; ++p )
std::cout << *p->first << " " << *p->second << std::endl;
std::cout << "swap 1st and 3rd elements..." << std::endl;
swap(*pair_begin,*(pair_begin+2));
std::cout << "paired arrays now:" << std::endl;
for ( PAIR_ITER p = pair_begin; p != pair_end; ++p )
std::cout << *p->first << " " << *p->second << std::endl;
std::cout << "calling sort..." << std::endl;
std::sort( pair_begin , pair_end , &proxy_comp<std::vector<int>::iterator , std::vector<double>::iterator> );
std::cout << "paired arrays now:" << std::endl;
for ( PAIR_ITER p = pair_begin; p != pair_end; ++p )
std::cout << *p->first << " " << *p->second << std::endl;
//
// EXAMPLE 2: TRIPLET (PAIR OF PAIR)
//
typedef piterator< std::vector<double>::iterator , std::vector<double>::iterator > DOUBLET_ITER;
typedef piterator< std::vector<int>::iterator , DOUBLET_ITER > TRIPLET_ITER;
TRIPLET_ITER triplet_begin( iv.begin(), DOUBLET_ITER( dv1.begin() , dv2.begin() ) );
TRIPLET_ITER triplet_end( iv.end(), DOUBLET_ITER( dv1.end() , dv2.end() ) );
std::cout << "tripleted arrays now:" << std::endl;
for ( TRIPLET_ITER p = triplet_begin; p != triplet_end; ++p )
std::cout << *p->first << " "
<< *p->second->first << " "
<< *p->second->second << std::endl;
std::cout << "iter_swap 1st and second elements..." << std::endl;
std::iter_swap( triplet_begin , triplet_begin+1 );
std::cout << "tripleted arrays now:" << std::endl;
for ( TRIPLET_ITER p = triplet_begin; p != triplet_end; ++p )
std::cout << *p->first << " "
<< *p->second->first << " "
<< *p->second->second << std::endl;
std::cout << "calling sort..." << std::endl;
std::sort( triplet_begin, triplet_end, &proxy_comp< std::vector<int>::iterator , piterator< std::vector<double>::iterator , std::vector<double>::iterator > > );
std::cout << "tripleted arrays now:" << std::endl;
for ( TRIPLET_ITER p = triplet_begin; p != triplet_end; ++p )
std::cout << *p->first << " "
<< *p->second->first << " "
<< *p->second->second << std::endl;
return 0;
}
paired arrays now:
10 -0.5
20 -1.5
3 -2.5
swap 1st and 3rd elements...
paired arrays now:
3 -2.5
20 -1.5
10 -0.5
calling sort...
paired arrays now:
3 -2.5
10 -0.5
20 -1.5
tripleted arrays now:
3 -2.5 10.5
10 -0.5 11.5
20 -1.5 12.5
iter_swap 1st and second elements...
tripleted arrays now:
10 -0.5 11.5
3 -2.5 10.5
20 -1.5 12.5
calling sort...
tripleted arrays now:
3 -2.5 10.5
10 -0.5 11.5
20 -1.5 12.5