STL学习笔记之STL介绍(下)

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中删除元素

ist 成员函数 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

list成员函数remove()list中删除元素

/* 
|| Using the list member function remove to remove elements 
*/ 
#include <string> 
#include <list> 
#include <algorithm> 
 
PrintIt (const string& StringToPrint) { 
    cout << StringToPrint << endl; 
} 
 
int main (void) { 
    list<string> Birds; 
 
    Birds.push_back("cockatoo"); 
    Birds.push_back("galah"); 
    Birds.push_back("cockatoo"); 
    Birds.push_back("rosella"); 
    Birds.push_back("corella"); 
 
    cout << "Original list with cockatoos" << endl; 
    for_each(Birds.begin(), Birds.end(), PrintIt); 
 
    Birds.remove("cockatoo"); 
 
    cout << "Now no cockatoos" << endl; 
    for_each(Birds.begin(), Birds.end(), PrintIt); 
} 

输出是:

Original list withcockatoos
cockatoo
galah
cockatoo
rosella
corella
Now no cockatoos
galah
rosella
corella

使用STL通用算法remove()list中删除元素
通用算法 remove() 使用和 list 的成员函数不同的方式工作。一般情况下不改变容器的大小。  

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

输出结果将为:
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 函数来删除从新结尾到老结尾的部分。
使用STL通用算法stable_partition()list成员函数splice()来划分一个list

我们将完成一个稍微有点复杂的例子。它演示 STL 通用算法 stable_partition() 算法和一个 list 成员函数 splice() 的变化。注意函数对象的使用和没有使用循环。 通过简单的语句调用 STL 算法来控制。
stable_partition()
是一个有趣的函数。它重新排列元素,使得满足指定条件的元素排在 不满足条件的元素前面。它维持着两组元素的顺序关系。

splice
把另一个 list 中的元素结合到一个 list 中。它从源 list 中删除元素。

在这个例子中,我们想从命令行接收一些标志和四个文件名。文件名必须 按顺序出现。通过使用 stable_partition() 我们可以接收和文件名混为任何位置的标志,并且不打乱文件名的顺序就把它们放到一起。

由于记数和查找算法都很易用,我们调用这些算法来决定哪个标志被设置而哪个标志未被设置。 我发现容器用来管理少量的象这样的动态数据。
 /* 
|| 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


结论
  我们仅仅简单的谈了谈你可以用 list 做的事情。我们没有说明一个对象的用户定义类,虽然这个不难。
  如果你懂了刚才说的这些算法背后的概念,那么你使用剩下的那些算法就应该没有问题了。使用 STL 最重要的东西就是得到基本理论。

STL 的关键实际上是 iterator STL 算法作为参数使用 iterator ,他们指出一个范围,有时是一个范围, 有时是两个。 STL 容器支持 iterator ,这就是为什么我们说 list<int>::iterator, list<char>::iterator, list<string>::iterator.

iterator 有很好的定义继承性。它们非常有用。某些 iterator 仅支持对一个容器只读,某些 仅支持写,还有一些仅能向前指,有一些是双向的。有一些 iterator 支持对一个容器的随机存取。

STL 算法需要某个 iterator 作为 动力 如果一个容器不提供 iterator 作为 动力 ,那么这个算法将无法编译。例如, list 容器仅提供双向的 iterator 。通常的 sort() 算法需要随机存取的 iterator 。这就是为什么我们需要一个特别的 list 成员函数 sort()

  要合适的实际使用 STL ,你需要仔细学习各种不同的 iterator 。你需要知道每种容器都支持那类 iterator 你还需要知道算法需要那种 iterator ,你当然也需要懂得你可以有那种 iterator
field中使用STL
  去年,我曾用 STL 写过几个商业程序。它在很多方面减少了我的工作量,也排除了很多逻辑错误。
  最大的一个程序有大约 5000 行。可能最惊人的事情就是它的速度。它读入并处理一个 1-2 兆的 报告文件仅花大约 20 秒。我是在 linux 上用 gcc2.7.2 开发的,现在运行在 HP-UX 机器上。 它一共用了大约 50 和函数对象和很多容器,这些容器的大小从小 list 到一个有 14,000 个元素的 map 都有。

  一个程序中的函数对象是处于一个继承树中,顶层的函数对象调用低层的函数对象。我大量的使用 STL 算法 for_each() ,find(),find_if(),count() count_if() ,我尽量减少使用程序内部的函数,而使用 STL 的算法调用。

STL 倾向于自动的把代码组织成清晰的控制和支持模块。通过小心使用函数对象并给它们 起有意义的名字,我使它们在我的软件的控制流中流动。

  还有很多关于 STL 编程要知道的东西,我希望你通过这些例子可以愉快的工作。

  参考数目中的两本书在 web 上都有勘误表,你可以自己改正它们。

Stroustrup 在每一章后面都有个建议栏,特别是对于出学者有用。正本书比早期的版本更加健谈。 它也更大了。书店里还可以找到其他几本关于 STL 的教科书。去看看,也许你能发现什么。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值