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;});

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章