C++自修入門實境秀、C++ Primer 5版研讀秀 17/ ~3.4. Introducing Iterators 迭代與迭代器-20190...
3.4. Introducing Iterators
迭代器
頁106
9:10
Like pointers (§ 2.3.2 , p. 52 ), iterators give us indirect access to an object.
iterator 和pointer指針(指標)有關
We can use an iterator to fetch an element and iterators have operations to move from one element to another.
二個主詞(we、iterators)、二件事
1. We can use an iterator to fetch an element
2.and iterators have operations to move from one element to another.迭代器(iterator)可以由原本指向的元素,移到指向另一個元素。也像指標可以換所指的對象object(參見頁107「Moving Iterators from One Element to Another 將迭代器從一個元素移向另一個」)
As with pointers, an iterator may be valid or invalid.
A valid iterator either denotes an element or denotes a position one past the last element in a container.
All other iterator values are invalid.
就像指標,一個迭代器可能是有效或無效的。
一個有效的迭代器可以代表一個元素,或一個容器中超出最後一個元素一個位置的位置。
其他所有的迭代器值都是無效的。
其句式是「超出……一個位置」 ①斷句
google翻譯的都比較好:
denotes a position one past the last element in a container.
表示一個位於容器中最後一個元素之後的位置。
意思就是說,假如一個interator 不是表示一個元素的話,那就是要是一個代表容器內最後元素的後面那個位置,才是有效的迭代器(iterator)
3.4.1. Using Iterators
types that have iterators have members that return iterators.
具有迭代器(iterator)的型別,這種型別內的成員會傳回相應的迭代器(iterator)
好像成員本身會自己上報、繳交出自己所屬的迭代器(iterator)一樣
In particular, these types have members named begin and end .
特別是,具有叫做begin和end成員的這樣的型別。這兩個其實就是container的成員函式,所以都要接個parentheses(圓括號)
也就是說具有迭代器(iterator)的型別都會有begin和end兩個成員,且此成員會傳回代表第1和最後一個元素的迭代器(iterator)
50:00
off-the-end iterator (尾端後迭代器)
52:00
迭代器(iterator)的型別(詳見頁108)
1:1:00
vector<int> ivec;// { 0, 2, 3, 4, 10, -1, -88 };
auto b{ ivec.begin() }, e{ ivec.end() };
if (b==e)
{
return -1;
}
return 0;
b、e的型別實際上應就是容器元素型別的指針,在此例中則是「int*」
1:4:50
Iterator Operations
頁107
1:31:00迭代器(iterator)也可以解參考(dereference)
If they are unequl, there is at least one character in s .
英文版「unequl」乃「unequal」敓文
表3.6
*iter 回傳迭代器iter所代表的元素的一個參考。
iter 1:12:00 就是iterator的縮寫;*就是解參考運算子
1:10:00可以說迭代器(iterator)也是一種特殊指標,所以也可以被解參考運算子運算。
所以如果我們要藉由一個迭代器(iterator)而去參考它所指向的元素的話,就可以用這個運算(解參考運算子*)來得到。
vector<int> ivec { 0, 2, 3, 4, 10, -1, -88 };
auto b{ ivec.begin() }, e{ ivec.end() };
int i;
if (b==e)
{
return -1;
}
i = *b;
if (i==0)
{
return 1;
}
return 0;
此時i就成了ivec中的第一個元素0的拷貝
Moving Iterators from One Element to Another 將迭代器從一個元素移向另一個
1:29:20 1:37:52
頁108
Using the increment operator, we can rewrite our program that changed the case of the first word in a string to use iterators instead:
「the first word in a string」參見頁94,是「change the first word in s to all uppercase」
Key Concept: Generic Programming
1:53:50
關鍵概念:泛型程式設計
2:2:10
By routinely using iterators and !=, we don’t have to worry about the precise type of container we’re processing.
藉由習慣性使用迭代器和!=,我們就不用擔心我們正在處理的容器之確切型別。
→我們就不用擔心我們正在處理的容器到底是什麼型別。(這才比較中文化嘛)
到底是什麼,就是precise、確切呀。
Iterator Types
2:5:40
2:7:00一如對於vector、string的size_type成員到底是什麼型別,我們無法確知;我們也的確不知、也沒必要知道iterator到底是個什麼型別
iterator與const_iterator的型別
這兩種型別就代表了實際的迭代器(iterator)的型別
2:17:00
A const_iterator behaves like a pointer to const pointer (§ 2.4.2 , p. 62 ).
一個指向常值的指標
就跟一個cons指標一樣, 一個const_iterator可讀取但不能寫入它所代表的元素
cons→const
頁109 2:22:00
The term iterator is used to refer to three different entities.
這個entities應該翻作「東西」就可以了,才合中文語境。
一個「iterator」指的有三樣東西。
1.iterator這個概念
2.一個容器所定義的iterator型別
3.作為iterator的物件
The begin and end Operations
cbegin和cend函式
c 是 const的意思
只讀不寫時,就用const_iterator型別就好,因此,可以適用上述2個函式來傳回對個別元素的const_iterator
Combining Dereference and Member Access
2:42:10這裡的優先順序(參頁136),就像斷句要斷對一樣嘛。像這個
(*it).empty()
(*it)就是叫complier要句讀成*it-empty(),而不是*-it.empty()
可見「.」點號運算子是較「*」解參考運算子有更優先的順序(更大的優先權)
頁110
2:49:30
The arrow operator combines dereference and member access into a single operation. That is, it->mem is a synonym for (* it).mem .
表3.6(頁107)就有了
Some vector Operations Invalidate Iterators
變動vector元素量(size()值)就會使該vector的迭代器(iterator)全面失效
3:10:40
練習3.21
練習3.16
3:30:00可見使用了未初始化的值會有什麼下場,也是一場災難也!
vector<int> v1;//size=0
vector<int> v2(10);//size=10,elements are 0。
vector<int>v3(10, 42); //size=10,elements are 42;
vector<int> v4{ 10 };//size=1,value is 10
vector<int> v5{ 10,42 };//list initialization :size=2,values are 10,42 respectively
vector<string> v6{ 10 };//size=10,values are "".because 10 and string are different type.
vector<string> v7{ 10,"hi" };//size=10,values are "hi".
vector<vector<int>> ivec{ v1,v2,v3,v4,v5 };
vector<vector<string>> svec{ v6,v7 };
for (decltype(ivec.cbegin()) itivec{ ivec.cbegin() };
itivec != ivec.cend();++itivec) {
cout << (*itivec).size() << "\t";
for (decltype(itivec->cbegin()) itv0{itivec->cbegin()}; itv0 != itivec->cend(); ++itv0)
cout << *itv0 << " ";
cout << endl;
}
for (decltype(svec.cbegin()) itv{svec.cbegin()}; itv != svec.cend(); ++itv)
{
cout << itv->size() << "\t";
for (decltype(itv->cbegin()) itv0{itv->cbegin()}; itv0 != itv->cend(); ++itv0)
cout << *itv0 << " ";
cout << endl;
}
0
10 0 0 0 0 0 0 0 0 0 0
10 42 42 42 42 42 42 42 42 42 42
1 10
2 10 42
10
10 hi hi hi hi hi hi hi hi hi hi
請按任意鍵繼續 . . .
練習3.22
3:41:00
vector<string>text;
string word{""};
while (cin>>word)
{
text.push_back(word);
}
for (decltype(text.begin()) it_text{text.begin()};it_text!=text.end()&&*it_text!="~";++it_text)
{
for (decltype(it_text->begin()) it_word {it_text->begin()} ; it_word!=it_text->end();++it_word)
{
*it_word= toupper(*it_word);
}
}
for (decltype(text.cbegin()) it_text{ text.begin() }; it_text != text.end() && *it_text != "~"; ++it_text)
cout << *it_text << " ";
A subscript or superscript is a character (number, letter or symbol) that is (respectively) set slightly below or above the normal line of type. It is usually smaller than the rest of the text. Subscripts appear at or below the baseline, while superscripts are above. Subscripts and superscripts are perhaps most often used in formulas, mathematical expressions, and specifications of chemical compounds and isotopes, but have many other uses as well. ~
In professional typography, subscript and superscript characters are not simply ordinary characters reduced in size; to keep them visually consistent with the rest of the font, typeface designers make them slightly heavier (i.e. medium or bold typography) than a reduced-size character would be. The vertical distance that sub- or superscripted text is moved from the original baseline varies by typeface and by use.
^Z
A SUBSCRIPT OR SUPERSCRIPT IS A CHARACTER (NUMBER, LETTER OR SYMBOL) THAT IS (RESPECTIVELY) SET SLIGHTLY BELOW OR ABOVE THE NORMAL LINE OF TYPE. IT IS USUALLY SMALLER THAN THE REST OF THE TEXT. SUBSCRIPTS APPEAR AT OR BELOW THE BASELINE, WHILE SUPERSCRIPTS ARE ABOVE. SUBSCRIPTS AND SUPERSCRIPTS ARE PERHAPS MOST OFTEN USED IN FORMULAS, MATHEMATICAL EXPRESSIONS, AND SPECIFICATIONS OF CHEMICAL COMPOUNDS AND ISOTOPES, BUT HAVE MANY OTHER USES AS WELL. 請按任意鍵繼續 . . .
練習3.23
4:18:00
vector<int>ivec{0,3,4,8,11,332,-23,8,10,31};
for (decltype(ivec.begin()) it_ivec{ ivec.begin() }; it_ivec != ivec.end(); ++it_ivec)
*it_ivec = *it_ivec * 2;
for (decltype(ivec.begin()) it_ivec{ ivec.begin() }; it_ivec != ivec.end(); ++it_ivec)
cout << *it_ivec << " ";
cout << endl;
練習3.23 :寫一個程式來建立帶有十個int元素的一個vector。使用一個迭代器將每個元素的指定為目前值的兩倍。印出這個vector來測試你的程式。
「元素的指定」之「的」字衍。
頁111
3.4.2. Iterator Arithmetic
4:19:40
4:28:00
Incrementing an iterator moves the iterator one element at a time.
遞增一個迭代器會使那個迭代器一次往前一個元素。
「遞增一個迭代器」翻成「迭代器的遞增運算」在中文語境才比較不會造成誤會。
「會使那個迭代器」加個「位置」才比較不易誤解→「會使那個迭代器所指的位置」
(對)迭代器的遞增運算會使那個迭代器所指的位置一次往前挪一個元素。
Similarly, we can use == and != to compare two valid iterators (§ 3.4 , p. 106 ) into any of the library container types.
同樣地,我們可以使用==和!=來比較兩個有效的程式庫容器型別迭代器(§3.4)。
意思好像是說不同型別容器的迭代器(iterator)也能夠相互比較呢
4:39:00
表3.7
The iterators must denote elements in, or one past the end of, the same container
超出其最後一個元素一個位置的位置。
超出其最後元素一個位置的那個位置。
後於最後元素一個位置的那個位置。
在最後元素後面一個位置的那個位置。
4:49:00
Arithmetic Operations on Iterators 迭代器上的算術運算
5:11:30
頁112
The result type is a signed integral type named difference_type .
結果的型別是一個有效的整數型別,名為difference_ type。
結果的型別是一個有號的整數型別,名為difference_ type。
signed就是有負號,可以是負值的意思。
Using Iterator Arithmetic
A classic algorithm that uses iterator arithmetic is binary search.
用到迭代器算術的一個經典演算法是二元捜尋(binary search)。
二元捜尋(binary search)。恐怕翻成「二分法搜尋」會比較適當
5:41:00
頁113
練習3.24
5:45:00
練習3.20
vector<int> ivec;
vector<int> isumvec;
int i = 0;
while (cin >> i)
{
ivec.push_back(i);
}
i = 1; int j = 0;
if (ivec.size()<2)
{
return -1;
}
vector<int>::const_iterator it1_ivec{ ivec.cbegin() };
vector<int>::const_iterator it2_ivec{ it1_ivec+1};
while (it2_ivec != ivec.cend())
{
isumvec.push_back(*it1_ivec + *it2_ivec);
++it1_ivec;
++it2_ivec;
}
for (vector<int>::const_iterator it_isumvec{isumvec.cbegin()};it_isumvec!=isumvec.cend();++it_isumvec)
cout << *it_isumvec<< " ";
改寫後:
vector<int> ivec;
vector<int> isumvec;
int i = 0;
while (cin >> i)
{
ivec.push_back(i);
}
i = 1; int j = 0;
if (ivec.size()<2)
{
return -1;
}
vector<int>::const_iterator it1_ivec{ ivec.cbegin() };
vector<int>::const_iterator it2_ivec{ivec.cend()-1};
while (it2_ivec > it1_ivec)
{
isumvec.push_back(*it1_ivec + *it2_ivec);
++it1_ivec;
--it2_ivec;
}
for (vector<int>::const_iterator it_isumvec{isumvec.cbegin()};it_isumvec!=isumvec.cend();++it_isumvec)
cout << *it_isumvec<< " ";
練習3.25
vector<int> ivec(11,0);
int score=0;
vector<int>::iterator it_ivec{ivec.begin()};
//vector<int> isumvec;
while (cin>>score)
{
if (score<=100&&score>=0)
{
++*(it_ivec + score / 10);
//it_ivec = it_ivec + score / 10;
//++* it_ivec;
it_ivec = ivec.begin();
}
}
for (vector<int>::const_iterator it_ivec{ivec.cbegin()};it_ivec!=ivec.cend();++it_ivec)
cout << *it_ivec<< " ";
練習3.26
vector<int> ivec{11, 0, 2, 4, -5, 6 };
vector<int>::const_iterator beg{ ivec.cbegin() },
end{ ivec.cend() },
mid{ beg+(end-beg)/2 };//意思是mid用beg初始化再移動(end-beg)/2個位置
//mid{ (beg + end) / 2 };//+號的兩邊沒有這種型別的運算元;且迭代器(iterator)相加是何什麼意思?表3.7(頁111)也沒有兩個迭代器相加的運算
//mid{ (end - beg) / 2 };//(end - beg) / 2 算出來是個整個型別,怎麼可以指定為迭代器(iterator)型別
6:58:00
3.5. Arrays 陣列
留言