反向迭代器(rbegin,rend)

http://blog.csdn.net/kjing/article/details/6936325

 

C++ primer (中文版第四版)第273頁

9.3.2 begin和end成員

        begin和end操作產生指向容器內第一個元素和最後一個元素的下一個位置的迭代器,如下所示。這兩個迭代器通常用於標記包含容器中所有元素的迭代範圍。

c.begin() 返回一個迭代器,它指向容器c的第一個元素

c.end() 返回一個迭代器,它指向容器c的最後一個元素的下一個位置

c.rbegin() 返回一個逆序迭代器,它指向容器c的最後一個元素

c.rend() 返回一個逆序迭代器,它指向容器c的第一個元素前面的位置

        上述每個操作都有兩個不同的版本:一個是const成員,另一個是非const成員。這些操作返回什麼類型取決於容器是否爲const。如果容器不是const,則這些操作返回iterator或reverse_iterator類型。如果容器是const,則其返回類型要加上const_前綴,也就是const_iterator和const_reverse_iterator類型。

 

第353頁

11.3.3 反向迭代器

        反向迭代器是一種反向遍歷容器的迭代器。也就是,從最後一個元素到第一個元素遍歷容器。反向迭代器將自增(和自減)的含義反過來了:對於反向迭代
器,++ 運算將訪問前一個元素,而 -- 運算則訪問下一個元素。

        回想一下,所有容器都定義了 begin 和 end 成員,分別返回指向容器首元素和尾元素下一位置的迭代器。容器還定義了 rbegin 和 rend 成員,分別返回指向容器尾元素和首元素前一位置的反向迭代器。與普通迭代器一樣,反向迭代器也有常量(const)和非常量(nonconst)類型。圖 11.1 使用一個假設名爲 vec 的 vector 類型對象闡明瞭這四種迭代器之間的關係。

圖 1 比較 begin/end 和 rbegin/rend 迭代器

      假設有一個 vector 容器對象,存儲 0-9 這 10 個以升序排列的數字:

  1. vector<int> vec;  
  2. for (vector<int>::size_type i = 0; i != 10; ++i)  
  3.       vec.push_back(i); // elements are 0,1,2,...9  
      vector<int> vec;
      for (vector<int>::size_type i = 0; i != 10; ++i)
            vec.push_back(i); // elements are 0,1,2,...9


 

下面的 for 循環將以逆序輸出這些元素:

  1. // reverse iterator of vector from back to front  
  2. vector<int>::reverse_iterator r_iter;  
  3. for (r_iter = vec.rbegin(); // binds r_iter to last element  
  4.       r_iter != vec.rend(); // rend refers 1 before 1st element  
  5.       ++r_iter) // decrements iterator one element  
  6.     cout << *r_iter << endl; // prints 9,8,7,...0  
      // reverse iterator of vector from back to front
      vector<int>::reverse_iterator r_iter;
      for (r_iter = vec.rbegin(); // binds r_iter to last element
            r_iter != vec.rend(); // rend refers 1 before 1st element
            ++r_iter) // decrements iterator one element
          cout << *r_iter << endl; // prints 9,8,7,...0


 

      雖然顛倒自增和自減這兩個操作符的意義似乎容易使人迷惑,但是它讓程序員可以透明地向前或向後處理容器。例如,爲了以降序排列 vector,只需向 sort傳遞一對反向迭代器:

  1. // sorts vec in "normal" order  
  2. sort(vec.begin(), vec.end());  
  3. // sorts in reverse: puts smallest element at the end of vec  
  4. sort(vec.rbegin(), vec.rend());  
      // sorts vec in "normal" order
      sort(vec.begin(), vec.end());
      // sorts in reverse: puts smallest element at the end of vec
      sort(vec.rbegin(), vec.rend());


 

      1.反向迭代器需要使用自減操作符
      從一個既支持 -- 也支持 ++ 的迭代器就可以定義反向迭代器,這不用感到吃驚。畢竟,反向迭代器的目的是移動迭代器反向遍歷序列。標準容器上的迭代器既支持自增運算,也支持自減運算。但是,流迭代器卻不然,由於不能反向遍歷流,因此流迭代器不能創建反向迭代器。
      2.反向迭代器與其他迭代器之間的關係
      假設有一個名爲 line 的 string 對象,存儲以逗號分隔的單詞列表。我們希望輸出 line 中的第一個單詞。使用 find 可很簡單地實現這個任務:

  1. // find first element in a comma-separated list  
  2. string::iterator comma = find(line.begin(), line.end(), ',');  
  3. cout << string(line.begin(), comma) << endl;  
      // find first element in a comma-separated list
      string::iterator comma = find(line.begin(), line.end(), ',');
      cout << string(line.begin(), comma) << endl;


 

如果在 line 中有一個逗號,則 comma 指向這個逗號;否則,comma 的值爲 line.end()。在輸出 string 對象中從 line.begin() 到 comma 的內容時,從頭開始輸出字符直到遇到逗號爲止。如果該 string 對象中沒有逗號,則輸出整個 string 字符串。
      如果要輸出列表中最後一個單詞,可使用反向迭代器:

  1. // find last element in a comma-separated list  
  2. string::reverse_iterator rcomma = find(line.rbegin(), line.rend(), ',');  
      // find last element in a comma-separated list
      string::reverse_iterator rcomma = find(line.rbegin(), line.rend(), ',');


 

因爲此時傳遞的是 rbegin() 和 rend(),這個函數調用從 line 的最後一個字符開始往回搜索。當 find 完成時,如果列表中有逗號,那麼 rcomma 指向其最後一個逗號,即指向反向搜索找到的第一個逗號。如果沒有逗號,則 rcomma 的值爲 line.rend()。
      在嘗試輸出所找到的單詞時,有趣的事情發生了。直接嘗試:

  1. // wrong: will generate the word in reverse order  
  2. cout << string(line.rbegin(), rcomma) << endl;  
      // wrong: will generate the word in reverse order
      cout << string(line.rbegin(), rcomma) << endl;


 

會產生假的輸出。例如,如果輸入是:
      FIRST,MIDDLE,LAST
則將輸出 TSAL!

      圖 2 闡明瞭這個問題:使用反向迭代器時,以逆序從後向前處理 string對象。爲了得到正確的輸出,必須將反向迭代器 line.rbegin() 和 rcomma 轉換爲從前向後移動的普通迭代器。其實沒必要轉換 line.rbegin(),因爲我們知道轉換的結果必定是 line.end()。只需調用所有反向迭代器類型都提供的成員
函數 base 轉換 rcomma 即可:
 

  1. // ok: get a forward iterator and read to end of line  
  2.  cout << string(rcomma.base(), line.end()) << endl;  
     // ok: get a forward iterator and read to end of line
      cout << string(rcomma.base(), line.end()) << endl;


 

假設還是前面給出的輸入,該語句將如願輸出 LAST。

圖 2. 反向迭代器與普通迭代器之間的區別



      圖 2 顯示的對象直觀地解釋了普通迭代器與反向迭代器之間的關係。例如,正如 line_rbegin() 和 line.end() 一樣,rcomma 和 rcomma.base() 也指向不同的元素。爲了確保正向和反向處理元素的範圍相同,這些區別必要的。從技術上來說,設計普通迭代器與反向迭代器之間的關係是爲了適應左閉合範圍
(第 9.2.1 節)這個性質的,所以,[line.rbegin(), rcomma) 和[rcomma.base(), line.end()) 標記的是 line 中的相同元素。
      反向迭代器用於表示範圍,而所表示的範圍是不對稱的,這個事實可推導出一個重要的結論:使用普通的迭代器對反向迭代器進行初始化或賦值時,所得到的迭代器並不是指向原迭代器所指向的元素。

 

=======================

記錄一下,以供自己參考。

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