C++迭代器简介与定制

C++迭代器详解

迭代器基础

算法中应用

创建迭代器

 

迭代器是C++中非常重要的概念,是STL工具集中的重要一环。迭代器有很多类型,各自有其局限性。

  • 输入迭代器:只能取指向的值,当迭代器自加后,之前指向的值就不可访问(不用此类迭代器在一个范围内遍历多次),典型的如std::istream_iterator。

  • 前向迭代器:类似输入迭代器只能前进,但在指定范围内可迭代多次,典型的如std::forward_list(只能前向遍历,但可以反复迭代)。

  • 输出迭代器:单纯用于写的迭代器,只能前进,且将内容写入对应容器(文件)中;读取的值是未定义的。

 

 

迭代器基础

每种容器都定义了自己的迭代器,可通过iterator获取(如vector::iterator)。通过begin与end函数可获取一对迭代器,表示范围(end不指向容器的任何元素,而是指向最后元素的下一个位置)以遍历容器元素。

vector<int> vec;
// ...
for(auto it=vec.begin(); it!=vec.end(); ++it){
  cout<<*it<<endl;
}

// C++11
for(auto it:vec){
  cout<<*it<<endl;
}

基本操作

迭代器可以像指针一样进行++与--操作,以及通过*解除引用,和比较操作等。此外还有三个函数模板:

  • advance(p,n):迭代器向前或向后(负数)移动n个元素;

  • distance(p,q):计算两个迭代器间的距离;

  • iter_swap(p,q):交换两个迭代器;

高级使用

迭代器与STL中的算法结合,可以产生强大的威力;通过插入迭代器,可方便插入数据至容器:

  • inserter(con,it):从容器con的it处开始插入

  • back_inserter(con):插入到容器尾部(需要容器支持push_back);

  • front_inserter(con):插入到容器头部(需要容器支持push_front);

通过copy输出容器内容:

template<typename T>
void toPrint(const T &con){
  copy(begin(con),end(con), ostream_iterator<T::value_type>{count, ", "});
  cout<<endl;
}

使用inserter创建容器

vector<int> vec{1,2,3,4,5};
deque<int> de;
copy_n(begin(vec), 3, inserter(de,begin(de))); // 从指定位置往后,依次插入内容
move(begin(vec),end(vec), front_inserter(de)); // 总是插入最前面,若是可移动类型(如string等)则vec中的内容将变为空
toPrint(de); // 5,4,3,2,1,1,2,3

算法中应用

在算法中会大量使用迭代器进行操作。

二分查找

对于已排序的容器,可通过查找算法获取对应位置迭代器:

  • binary_search(begin,end,foFind):查找到返回true,否则false;

  • equal_range(begin,end,foFind):返回一对迭代器(pair<lowerBound,UpperBound>),符合要求的元素为[lowerBound,UpperBound),若未查找到则lowerBound==UpperBound(即都指向符合要求元素插入的位置);

  • lower_bound(begin,end,foFind):返回第一个不小于(less)查找值的迭代器,若未找到返回end;

  • upper_bound(begin,end,foFind):返回大于查找值的第一个元素位置(即新元素插入位置);

排序

STL中有多个排序算法,满足不同用途:

  • sort:排序

  • stable_sort:稳定排序

  • partial_sort(first, middle, last):保证[first,middle)范围内容的元素是排序好的,且不大于后面的任何元素;

  • partition(first,last,pre):返回第一个不满足pre的迭代器it,保证[first,it)范围内元素满足pre,[it,last)范围内元素不满足pre;

  • nth_element(first, itN, last):把第N个元素放在位置N处,且前面的元素不大于它,后面的元素不小于它(但不排序);

vector<int> vec{1,2,3,4,5,6,7,8,9};
default_random_engine gbump;
shuffle(vec.begin(),vec.end(),g);

auto mid{next(vec.begin(), vec.size()/3)};
// partial_sort(vec.begin(), mid, vec.end()); // 保证前1/3元素有序
auto ret = parition(vec.begin(),vec.end(), [](auto i){return i<5}); // 所有小于5的排在前面,其他排在后面
cout *ret<<endl;
toPrint(vec);

创建迭代器

要实现一个前向迭代器,只需支持前缀加++,解引用*和比较操作!=即可(可用于enumeration-for语句中)。

class Num_iterator{
  int m_cur=0;

public:
  explicit Num_iterator{int nPos=0):m_cur(nPos){}

  int operator*() {return m_cur;}

  Num_iterator& operator++(){
    ++m_cur;
    return *this;
  }
  Num_iterator& operator--(){
    --m_cur;
    return *this;
  }

  bool operator!=(const Num_iterator& other){
    return m_cur != other.m_cur;
  }
  bool operator==(const Num_iterator& other){
    return !operator!=(other);
  }
};

为了使迭代器兼容STL算法,需要对标准模板进行特化:

  template<>
  struct iterator_traits<Num_iterator>{
    using iterator_category = std::forward_iterator_tag;
    using value_type = int;
    using difference_type = int;
    using pointer = const int*;
    using reference = int;
  }
}

有了迭代器,我们就可以定义自己的容器,如获取数字范围:

class Num_range{
  int m_nStart=0;
  int m_nEnd=0;

public:
  Num_range{int from, int to):m_nStart(from), m_nEnd(to) {}

  Num_iterator begin() const { return Num_iterator(m_nStart);}
  Num_iterator end() const {return Num_iterator(m_nEnd);}

  Num_iterator begin() { return Num_iterator(m_nStart);}
  Num_iterator end() {return Num_iterator(m_nEnd);}
};

使用自定义容器:

Num_range rg(1, 10);
vector<int> vec;
transform(rg.begin(), rg.end(), back_inserter(vec), [](auto i) {return i*i;});

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值