上一篇文章中(点击查看),我们自定义了一个迭代器line_iterator来封装cin,并借助vector的构造方法,隐式调用了while循环实现若干字符串的输入。示例程序使用了string类,效率不够高,因为构造vector的时候是简单的深拷贝,在sort过程中也是将string对象移动来移动去的,很消耗内存和CPU。现在,我们换一种方式,干脆不用string类,只用char来实现同样的功能。当然,改进的示例仍然用到STL的诸多特性,这正是学习STL的好机会。代码如下所示:
/* 使用迭代器 版本3
* created: ume
* date: 2011-12-17
* remarks:
* 本例定义了函数对象strtab_cmp及strtab_print
*/
#include<iostream>
#include<vector>
#include<iterator>
#include<algorithm>
using namespace std;
// functional: strtab_cmp
struct strtab_cmp
{
typedef vector<char>::iterator strtab_iterator;
bool operator()(pair<strtab_iterator,strtab_iterator>& lhs,
pair<strtab_iterator,strtab_iterator>& rhs)
{
return lexicographical_compare(lhs.first,lhs.second,rhs.first,rhs.second);
}
};
// functional: strtab_print
struct strtab_print
{
ostream* out;
strtab_print(ostream& os):out(&os)
{
}
typedef vector<char>::iterator strtab_iterator;
void operator()(pair<strtab_iterator,strtab_iterator>& line)
{
copy(line.first,line.second,ostream_iterator<char>(*out));
}
};
// main function
int main()
{
vector<char> strtab;
char ch;
while(cin.get(ch))
{
strtab.push_back(ch);
}
// 分析字符串表,并构造字符串行vector
typedef vector<char>::iterator strtab_iterator;
vector<pair<strtab_iterator,strtab_iterator> > lines;
strtab_iterator start = strtab.begin();
while(start != strtab.end())
{
strtab_iterator next = find(start,strtab.end(),'\n');
*next = ' ';
if(next != strtab.end())
next++;
lines.push_back(make_pair(start,next));
start = next;
}
// 排序并输出
sort(lines.begin(),lines.end(),strtab_cmp());
for_each(lines.begin(),lines.end(),strtab_print(cout));
system("pause");
return 0;
}
运行这个示例程序,结果为:
you
are
the
apple
of
my
eye
^Z
apple are eye my of the you 请按任意键继续. . .
与旧的示例程序比起来,运行结果是完全一样的,但实现方法却迥然不同了。
首先观察头文件,这里并没有包含string,因为本例直接用char来保存输入的数据。我们看main函数中的strtab变量,它保存着输入的所有字符。但排序的对象是字符串啊,于是这里用到了另外一个vector,它的元素类型是pair<>,记录的就是每个字符串在strtab中的“指针”,排序(sort)的时候传入sort的也是pair<>的“指针”。这时候不能用STL排序算法中自带的operator<了,需要针对pair<>类型编写专门的比较方法。struct strtab_cmp完成了这个任务,不过它却是一个结构体(struct),为什么能够给sort传入一个结构体临时对象呢?注意struct strtab_cmp的成员函数operator(),即括号操作符。这就使得一个对象能够像函数那样去工作,完全可以以假乱真。毕竟sort需要的不过是一个函数指针而已,我们给了它一个strtab_cmp对象的地址,它毫不怀疑的把它当作函数指针使用,假如在sort内部那个函数指针是_func,那么当它调用_func()的时候,strtab_cmp对象立马反应过来,调用自己的括号操作符方法,完成了相同的任务。
strtab_print(cout)与strtab_cmp的道理是一样的,也是函数对象。
此外,为了使得输出的字符串在同一行,每找一个回车字符时,就将它修改成了空格,*next = ' '做的就是这件事情。