C++沉思錄__迭代器
(1)輸入迭代器
什麼是輸入迭代器呢,我們從一個例子出發進行說明.find函式看上去很簡單,但是已經足以說明輸入迭代器包含的基本要素了。如果一個物件p希望完全模擬指向序列的指標,那麼必須有如下操作:解引用(*) 自加(++) 不等於判斷(!=)以便實現取出序列某個元素值 並移動到下一個元素 也能夠判斷是否到達了最後一個元素的操作。為了完善起見 ++操作包括前++ 和後++以及==操作 。同時我們也能夠複製p。滿足這些需求之後 我們就能夠按照預先規定的順序讀(不能寫)序列中的元素。出於這樣的原因 ,我們將這樣的型別叫做輸入迭代器。這裡要強調一點就是輸入迭代器既不是某個特殊型別也不是物件,相反,其只是一個概念,指的是滿足上述要求的完整型別集合中的任意成員。換句話說 只要某個型別滿足這些條件,就可以叫做輸入迭代器。
/*
find函式的例子
*/
template<class P,class T>
P find(P start,P end,const T& x)
{
while(start !=end&& *start != x)
{
++start;
}
return start;
}
(2)輸出迭代器
如果我們可以讀取一個序列,那麼也有相應的型別進行寫操作,也就是所謂的輸出迭代器。所謂的輸出迭代器,和輸入迭代器唯一的區別就是*p對於輸出迭代器,希望是能夠寫*p,而不一定能夠讀,因為*p在被操作之前,可能是個無法被複制的有效值。
/*
該程式碼描述了輸出迭代器的基本行為
*/
template<class In,class Out>
void copy(In start, In end ,Out result)
{
while(start != end)
{
*result++ = *start++;
}
}
(3)前向迭代器
前向迭代器就是具有輸入迭代器和輸出迭代器功能的迭代器
/* 所謂的前向迭代器就是輸入迭代器和輸出迭代器的集合, f()是一個仿函式,長起來像函式的物件,其過載了()運算子 */ template <class Iter , class Function> void apply( Iter start ,Iter end,Function f) { while(start != end) { *start = f(*start); } }
(4)雙向迭代器
所謂的雙向迭代器,就是既能夠向前遍歷也能夠向後遍歷的迭代器,與前向迭代器的區別在於其增加了--的操作。
template<class P, class T>
void reverse(P start ,P end)
{
while(start !=end)
{
--end;
if(start != end)
{
T t = *start;
*start = *end;
*end =t;
++start;
}
}
}
(5)隨機迭代器
有些演算法必須高效的訪問資料結構中的任意元素 如二分查詢 為了支援二分查詢 必須增加 + 、-、+=、-=操作增加到雙向迭代器中,這樣就構成了所謂的隨機迭代器。
/*
二分查詢
*/
template<typename T, typename X>
T binaryserch(T start, T end ,X x)
{
T low =start;
T high = end;
while(low !=high)
{
T mid =(low + high) /2;
if(*mid == x)
return mid;
if(x <*mid)
high = mid;
else
low = mid +1;
}
return end;
}
所謂的泛型演算法,就是這樣的演算法,對於所操作的資料結構的細節資訊,只加入最低限度的瞭解。當然,理想的情況根本是不需要這樣的資訊,但是現實卻不是這樣的。作為一種折中,STL根據資料結構能夠支援的有效操作,將這些資料結構進行分類,然後根據每一個演算法,他會指出所需要的資料結構。
被分類的不是演算法,也不是資料結構,而是用來訪問資料結構的型別,這些型別的物件叫做迭代器,迭代器一共有5種,輸入 輸出迭代器 前向迭代器 雙向迭代器和隨機存取迭代器。概念繼承將這些種類聯絡在一起。
這一整套結構使得我們很容易判斷何種演算法應該作用於何種資料結構上面。該結構也提供了一種框架,其他人可以根據這個框架來補充程式庫之外的新演算法。
/*
對於陣列這種資料結構來說,遍歷可以採用的事雙向迭代器,因為對於其自身來說,支援自加和自減操作。
*/
void reverse(int * start ,int * beyond)
{
while(start != beyond)
{
int t = *start;
--beyond;
*start = *beyond;
*beyond = t;
++start;
}
}
/*
對於單向連結串列來說,本身不支援自減操作 或者說自減操作的代價太大 因而這樣的遍歷可以採用雙向迭代器
*/