#include <string> #include <list> # int main (void) { list<string> Milkshakes; Milkshakes.push_back("Chocolate"); Milkshakes.push_back("Strawberry"); Milkshakes.push_front("Lime"); Milkshakes.push_front("Vanilla"); } We now have a list with four strings in it. The list member function push_back () places an object onto the back of the list. The list member function push_front () puts one on the front. I often push_back() some error messages onto a list, and then push_front() a title on the list so it PRints before the error messages. 我們現在有個4個字符串在list中。list的成員函數push_back()把一個對象放到一個list的后面,而 push_front()把對象放到前面。我通常把一些錯誤信息push_back()到一個list中去,然后push_front()一個標題到list中, 這樣它就會在這個錯誤消息以前打印它了。
The list member function empty()list的成員函數empty() 知道一個list是否為空很重要。假如list為空,empty()這個成員函數返回真。 我通常會這樣使用它。通篇程序我都用 push_back()來把錯誤消息放到list中去。然后,通過調用empty() 我就可以說出這個程序是否報告了錯誤。假如我定義了一個list來放信息,一個放警告,一個放嚴重錯誤, 我就可以通過使用empty()輕易的說出到底有那種類型的錯誤發生了。 我可以整理這些list,然后在打印它們之前,用標題來整理它們,或者把它們排序成類。
這是我的意思:
/* Using a list to track and report program messages and status */ #include <iostream.h> #include <string> #include <list> # int main (void) { #define OK 0 #define INFO 1 #define WARNING 2 # int return_code; # list<string> InfoMessages; list<:string> WarningMessages; # // during a program these messages are loaded at various points InfoMessages.push_back("Info: Program started"); // do work... WarningMessages.push_back("Warning: No Customer records have been found"); // do work... # return_code = OK; # if (!InfoMessages.empty()) { // there were info messages InfoMessages.push_front("Informational Messages:"); // ... print the info messages list, we'll see how later return_code = INFO; } # if (!WarningMessages.empty()) { // there were warning messages WarningMessages.push_front("Warning Messages:"); // ... print the warning messages list, we'll see how later return_code = WARNING; } # // If there were no messages say so. if (InfoMessages.empty() && WarningMessages.empty()) { cout << "There were no messages " << endl; } # return return_code; }
用for循環來處理list中的元素 我們想要遍歷一個list,比如打印一個中的所有對象來看看list上不同操作的結果。要一個元素一個元素的遍歷一個list, 我們可以這樣做: /* How to print the contents of a simple STL list. Whew! */ #include <iostream.h> #include <string> #include <list> # int main (void) { list<string> Milkshakes; list<string>::iterator MilkshakeIterator; # Milkshakes.push_back("Chocolate"); Milkshakes.push_back("Strawberry"); Milkshakes.push_front("Lime"); Milkshakes.push_front("Vanilla"); # // print the milkshakes Milkshakes.push_front("The Milkshake Menu"); Milkshakes.push_back("*** Thats the end ***"); for (MilkshakeIterator=Milkshakes.begin(); MilkshakeIterator!=Milkshakes.end(); ++MilkshakeIterator) { // dereference the iterator to get the element cout << *MilkshakeIterator << endl; } } 這個程序定義了一個iterator,MilkshakeIterator。我們把它指向了這個list的第一個元素。 這可以調用 Milkshakes.begin()來作到,它會返回一個指向list開頭的iterator。然后我們把它和Milkshakes.end()的 返回值來做比較,當我們到了那兒的時候就停下來。 容器的end()函數會返回一個指向容器的最后一個位置的iterator。當我們到了那里,就停止操作。 我們不能不理容器的end()函數的返回值。我們僅知道它意味著已經處理到了這個容器的末尾,應該停止處理了。 所有的STL容器都要這樣做。
/* How to count objects in an STL list */ #include <list> #include <algorithm> # int main (void) { list<int> Scores; # Scores.push_back(100); Scores.push_back(80); Scores.push_back(45); Scores.push_back(75); Scores.push_back(99); Scores.push_back(100); # int NumberOf100Scores(0); count (Scores.begin(), Scores.end(), 100, NumberOf100Scores); # cout << "There were " << NumberOf100Scores << " scores of 100" << endl; } The count() algorithm counts the number of objects equal to a certain value. In the above example it checks each integer object in a list against 100. It increments the variable NumberOf100Scores each time a container object equals 100. The output of the program is count ()算法統計等于某個值的對象的個數。上面的例子它檢查list中的每個整型對象是不是100。每次容器中的對象等于100,它就給 NumberOf100Scores加1。這是程序的輸出: There were 2 scores of 100
/* How to find things in an STL list MkII */ #include <string> #include <list> #include <algorithm> # class EventIsIn1997 { public: bool operator () (string& EventRecord) { // year field is at position 12 for 4 characters in EventRecord return EventRecord.substr(12,4)=="1997"; } }; # int main (void) { list<string> Events; # // string positions 0123456789012345678901234567890123456789012345 Events.push_back("07 January 1995 Draft plan of house prepared"); Events.push_back("07 February 1996 Detailed plan of house prepared"); Events.push_back("10 January 1997 Client agrees to job"); Events.push_back("15 January 1997 Builder starts work on bedroom"); Events.push_back("30 April 1997 Builder finishes work"); # list<string>::iterator EventIterator = find_if (Events.begin(), Events.end(), EventIsIn1997()); # // find_if completes the first time EventIsIn1997()() returns true // for any object. It returns an iterator to that object which we // can dereference to get the object, or if EventIsIn1997()() never // returned true, find_if returns end() if (EventIterator==Events.end()) { cout << "Event not found in list" << endl;
int NumberOfNullCharacters(0); count(Characters.begin(), Characters.end(), '/0', NumberOfNullCharacters); cout << "We have " << NumberOfNullCharacters << endl; 讓我們找字符'1'
list<char>::iterator Iter; Iter = find(Characters.begin(), Characters.end(), '1'); cout << "We found " << *Iter << endl; 這個例子演示了STL容器答應你以更標準的方法來處理空字符?,F在讓我們用STL的search算法來搜索容器中 的兩個null。 就象你猜的一樣,STL通用算法search()用來搜索一個容器,但是是搜索一個元素串,不象find()和find_if() 只搜索單個的元素。
/* How to use the search algorithm in an STL list */ #include <string> #include <list> #include <algorithm> # int main ( void { # list<char> TargetCharacters; list<char> ListOfCharacters; # TargetCharacters.push_back('/0'); TargetCharacters.push_back('/0'); # ListOfCharacters.push_back('1'); ListOfCharacters.push_back('2'); ListOfCharacters.push_back('/0'); ListOfCharacters.push_back('/0'); # list<char>::iterator PositionOfNulls = search(ListOfCharacters.begin(), ListOfCharacters.end(), TargetCharacters.begin(), TargetCharacters.end()); # if (PositionOfNulls!=ListOfCharacters.end()) cout << "We found the nulls" << endl; } The output of the program will be 這是程序的輸出:
We found the nulls search算法在一個序列中找另一個序列的第一次出現的位置。在這個例子里我們在ListOfCharacters中 找TargetCharacters這個序列的第一次出現,TargetCharacters是包含兩個null字符的序列。 search的參數是兩個指著查找目標的iterator和兩個指著搜索范圍的iterators。 因此我們我們在整個的ListOfCharacters的范圍內查找TargetCharacters這個list的整個序列。
/* Using insert to insert elements into a list. */ #include <list> # int main (void) { list<int> list1; # /* Put integers 0 to 9 in the list */ for (int i = 0; i < 10; ++i) list1.push_back(i); # /* Insert -1 using the insert member function Our list will contain -1,0,1,2,3,4,5,6,7,8,9 */ list1.insert(list1.begin(), -1); # /* Insert an element at the end using insert Our list will contain -1,0,1,2,3,4,5,6,7,8,9,10 */ list1.insert(list1.end(), 10); # /* Inserting a range from another container Our list will contain -1,0,1,2,3,4,5,6,7,8,9,10,11,12 */ int IntArray[2] = {11,12}; list1.insert(list1.end(), &IntArray[0], &IntArray[2]); # /* As an exercise put the code in here to print the lists! Hint: use PrintIt and accept an interger */ } 注重,insert()函數把一個或若干個元素插入到你指出的iterator的位置。你的元素將出現在 iterator指出的位置以前。
List 構造函數 我們已經象這樣定義了list: list<int> Fred; 你也可以象這樣定義一個list,并同時初始化它的元素: // define a list of 10 elements and initialise them all to 0 list<int> Fred(10, 0); // list now contains 0,0,0,0,0,0,0,0,0,0 或者你可以定義一個list并用另一個STL容器的一個范圍來初始化它,這個STL容器不一定是一個list, 僅僅需要是元素類型相同的的容器就可以。
vector<int> Harry; Harry.push_back(1); Harry.push_back(2); # // define a list and initialise it with the elements in Harry list<int> Bill(Harry.begin(), Harry.end()); // Bill now contains 1,2
使用list成員函數從list中刪除元素 list成員函數pop_front()刪掉list中的第一個元素,pop_back()刪掉最后一個元素。 函數erase()刪掉由一個iterator指出的元素。還有另一個erase()函數可以刪掉一個范圍的元素。 /* Erasing objects from a list */ #include <list> # int main (void) { list<int> list1; // define a list of integers # /* Put some numbers in the list It now contains 0,1,2,3,4,5,6,7,8,9 */ for (int i = 0; i < 10; ++i) list1.push_back(i); # list1.pop_front(); // erase the first element 0 # list1.pop_back(); // erase the last element 9 # list1.erase(list1.begin()); // erase the first element (1) using an iterator # list1.erase(list1.begin(), list1.end()); // erase all the remaining elements # cout << "list contains " << list1.size() << " elements" << endl; } 輸出是: list contains 0 elements
/* Using the generic remove algorithm to remove list elements */ #include <string> #include <list>
#include <algorithm> # PrintIt(string& AString) { cout << AString << endl; } # int main (void) { list<string> Birds; list<string>::iterator NewEnd; # Birds.push_back("cockatoo"); Birds.push_back("galah"); Birds.push_back("cockatoo"); Birds.push_back("rosella"); Birds.push_back("king parrot"); # cout << "Original list" << endl; for_each(Birds.begin(), Birds.end(), PrintIt); # NewEnd = remove(Birds.begin(), Birds.end(), "cockatoo"); # cout << endl << "List according to new past the end iterator" << endl; for_each(Birds.begin(), NewEnd, PrintIt); # cout << endl << "Original list now. Care required!" << endl; for_each(Birds.begin(), Birds.end(), PrintIt); } The output will be Original list cockatoo galah cockatoo rosella king parrot
List according to new past the end iterator galah rosella king parrot
Original list now. Care required! galah rosella king parrot rosella king parrot 通用remove()算法返回一個指向新的list的結尾的iterator。從開始到這個新的結尾(不含新結尾元素)的范圍 包含了remove后剩下所有元素。你可以用list成員函數erase函數來刪除從新結尾到老結尾的部分。
/* Using the STL stable_partition algorithm Takes any number of flags on the command line and four filenames in order. */ #include <string> #include <list> #include <algorithm> # PrintIt ( string& AString { cout << AString << endl; } # class IsAFlag { public: bool operator () (string& PossibleFlag) { return PossibleFlag.substr(0,1)=="-"; } }; # class IsAFileName { public: bool operator () (string& StringToCheck) { return !IsAFlag()(StringToCheck); } }; # class IsHelpFlag { public: bool operator () (string& PossibleHelpFlag) { return PossibleHelpFlag=="-h"; } }; # int main (int argc, char *argv[]) {
# list<string> CmdLineParameters; // the command line parameters list<string>::iterator StartOfFiles; // start of filenames list<string> Flags; // list of flags list<string> FileNames; // list of filenames # for (int i = 0; i < argc; ++i) CmdLineParameters.push_back(argv[i]); # CmdLineParameters.pop_front(); // we don't want the program name # // make sure we have the four mandatory file names int NumberOfFiles(0); count_if(CmdLineParameters.begin(), CmdLineParameters.end(), IsAFileName(), NumberOfFiles); # cout << "The " << (NumberOfFiles == 4 ? "correct " : "wrong ") << "number (" << NumberOfFiles << ") of file names were specified" << endl; # // move any flags to the beginning StartOfFiles = stable_partition(CmdLineParameters.begin(), CmdLineParameters.end(), IsAFlag()); # cout << "Command line parameters after stable partition" << endl; for_each(CmdLineParameters.begin(), CmdLineParameters.end(), PrintIt); # // Splice any flags from the original CmdLineParameters list into Flags list. Flags.splice(Flags.begin(), CmdLineParameters, CmdLineParameters.begin(), StartOfFiles); # if (!Flags.empty()) { cout << "Flags specified were:" << endl; for_each(Flags.begin(), Flags.end(), PrintIt); } else { cout << "No flags were specified" << endl; } # // parameters list now contains only filenames. Splice them into FileNames list. FileNames.splice(FileNames.begin(), CmdLineParameters, CmdLineParameters.begin(), CmdLineParameters.end()); # if (!FileNames.empty()) { cout << "Files specified (in order) were:" << endl; for_each(FileNames.begin(), FileNames.end(), PrintIt); } else { cout << "No files were specified" << endl; } # // check if the help flag was specified if (find_if(Flags.begin(), Flags.end(), IsHelpFlag())!=Flags.end()) { cout << "The help flag was specified" << endl; } # // open the files and do whatever you do # } 給出這樣的命令行:
test17 -w linux -o is -w great 輸出是:
The wrong number (3) of file names were specified Command line parameters after stable partition -w -o -w linux is great Flags specified were: -w -o -w Files specified (in order) were: linux is great
參考書目 The STL Tutorial and Reference Guide, David Musser and Atul Saini. Addison Wesley 1996. 《STL教程和參考手冊》 The C++ Programming Language 3e, Bjarne Stroustrup. Addison Wesley 1997.