16.6.4 函数和容器方法
STL方法更适用于特定的容器(非通用方法)。作为成员函数,它可以使用模板类的内存管理工具,从而在需要时调整容器的长度。
例如:
list<int la>
la.remove(4);//删除链表所有为4的元素,同时改变链表长度
last = remove(la.begin(),la.end(),4);//它将没被删除的元素放在链表的开始位置,并返回一个指向新超尾的迭代器。
la.erase(last,lb.end);//删除末尾元素
#include<iostream>
#include<list>
#include<algorithm>
const int LIM = 10;
void Show(int v)
{
std::cout << v << " ";
}
int main()
{
using namespace std;
list<int> la = { 4,5,4,2,2,3,4,8,1,4 };
list<int> lb(la);
cout << "Original list contents:\n\t";
for_each(la.begin(), la.end(), Show);
cout << endl;
la.remove(4);
cout << "After using remove method:\n";
cout << "la:\t";
for_each(la.begin(), la.end(), Show);
cout << endl;
list<int>::iterator last;
last = remove(lb.begin(), lb.end(), 4); //返回的是指向新超尾的迭代器
cout << "After using the remove function:\n";
cout << "lb:\t";
for_each(lb.begin(), lb.end(), Show);
cout << endl;
lb.erase(last, lb.end());
cout << "After using erase method:\n";
cout << "lb:\t";
for_each(lb.begin(), lb.end(), Show);
cout << endl;
system("pause");
return 0;
}
16.6.5 使用STL
程序:用户输入单词,返回一个按字母排序的单词列表,并记录每个单词被输入的次数。
通过transform()完成字符串大小写转化。
string& ToLower(string& st)
{
transform(st.begin(),st.end(),tolower);
return st;
}
transform(words.begin(),words.end(),insert_iterator<<set>string>(wordset,wordset.begin()),ToLower);
//<<set>string>不加则缺少类模板类型,wrong
对于map,如果键无效,则对应值为0。
对于字符串函数参数参数传递,需要引用。
#include<iostream>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<iterator>
#include<algorithm>
#include<cctype>
using namespace std;
char toLower(char ch)
{
return tolower(ch);
}
string& ToLower(string& st)
{
transform(st.begin(), st.end(), st.begin(), tolower);
return st;
}
void display(const string& s)
{
cout << s << " ";
}
int main()
{
vector<string> words;
cout << "Enter words(enter quit to quit):\n";
string input;
while (cin >> input && input != "quit")
words.push_back(input);
cout << "You enter the following words:\n";
for_each(words.begin(), words.end(), display);
cout << endl;
// place words in set, converting to lowercase
set<string>wordset;
transform(words.begin(), words.end(), insert_iterator<set<string>>(wordset, wordset.begin()), ToLower);
cout << "\nAlphabetic list of words:\n";
for_each(wordset.begin(), wordset.end(), display);
cout << endl;
//place word and frequency in map
map<string, int> wordmap;
set<string>::iterator si;
for (si = wordset.begin();si != wordset.end();si++)
wordmap[*si] = count(words.begin(), words.end(), *si);
//display map contents
cout << "\nWord frequency:\n";
for (si = wordset.begin();si != wordset.end();si++)
cout << *si <<": "<< wordmap[*si] << endl;
system("pause");
return 0;
}
16.7 其他库
C++提供了三个数组模板:vector,valarray,array.
vector是一个容器类和算法系统一部分,支持面向容器的操作,如排序,插入,搜索,转移到其它容器等。
valarray是面向数值计算的,支持数值计算。
array是替代内置数组而设计的,提供了多个STL方法,包括begin(),end(),rbegin(),rend()
#include<iostream>
#include<valarray>
#include<vector>
#include<algorithm>
int main()
{
using namespace std;
vector<double> data;
double temp;
cout << "Enter numbers (<=0 to quit):\n";
while (cin >> temp && temp > 0)
data.push_back(temp);
sort(data.begin(), data.end());
int size = data.size();
valarray<double> numbers(size);
int i;
for (i = 0;i < size;i++)
numbers[i] = data[i];
valarray<double> sq_rts(size);
sq_rts = sqrt(numbers);
valarray<double> results(size);
results = numbers + 2.0*sq_rts;
cout.setf(ios_base::fixed);
cout.precision(4);
for (i = 0;i < size;i++)
{
cout.width(8);
cout.setf(ios_base::left);
cout << numbers[i] << ": ";
cout.width(8);
cout.unsetf(ios_base::left);
cout << results[i] << endl;
}
cout << "done";
system("pause");
return 0;
}
Enter numbers (<=0 to quit):
3.3 4 5.5 6 7 8 2 -1
2.0000 : 4.8284
3.3000 : 6.9332
4.0000 : 8.0000
5.5000 : 10.1904
6.0000 : 10.8990
7.0000 : 12.2915
8.0000 : 13.6569
done请按任意键继续. . .
vector 和 valarray的对比:
注意functional库内嵌bind1st和bind2nd分别表示将常数赋给第一个参数和第二个参数。
#include<iostream>
#include<vector>
#include<array>
#include<valarray>
#include<functional>
using namespace std;
double COS(double x)
{
return cos(x);
}
int main()
{
vector<double> ved1(10), ved2(10), ved3(10);
array<double, 3> vod1,vod2,vod3;
valarray<double>vad1(10), vad2(10), vad3(10);
vad3 = 10.0*((vad1 + vad2) / 2.0 + vad1*cos(vad2));
cout << vad3.size()<<" "<<vad3[0] << endl;//size=10,content=0
transform(ved2.begin(), ved2.end(), ved3.begin(), COS);
transform(ved1.begin(), ved1.end(), ved3.begin(), ved3.begin(), multiplies<double>());
transform(ved1.begin(), ved1.end(), ved2.begin(), ved1.begin(), plus<double>());
//位于functional库中
transform(ved1.begin(), ved1.end(), ved1.begin(), bind2nd(divides<double>(), 2.0));
transform(ved1.begin(), ved1.end(), ved3.begin(), ved3.begin(), plus<double>());
transform(ved3.begin(), ved3.end(), ved3.begin(), bind1st(multiplies<double>(), 10.0));
cout << vad3.size() << " " << vad3[0] << endl;//size=10,content=0
system("pause");
return 0;
}
slice切片:
slice对象被初始化为三个整数值,分别为起始索引、索引数、跨距,与python类似。
#include<iostream>
#include<valarray>
#include<cstdlib>
#include<vector>
using namespace std;
const int SIZE = 12;
typedef std::valarray<int> vint;//predefined
void show(const vint& v, int cols)
{
int lim = v.size();
//cout << size(v) << endl;
for (int i = 0;i < lim;i++)
{
cout.width(3);
cout << v[i];
if (i%cols == cols - 1)
cout << endl;
else
cout << ' ';
}
if (lim%cols != 0)
cout << endl;
}
int main()
{
vint valint(SIZE);
int i;
for (i = 0;i < SIZE;i++)
valint[i] = rand() % 10;
cout << "Original array:\n";
show(valint, 3);
vint vcol(valint[slice(1, 4, 3)]);
cout << "second column:\n";
show(vcol, 1);
vint vrow(valint[slice(3, 3, 1)]);
cout << "second row:\n";
show(vrow, 3);
valint[slice(2, 4, 3)] = 10;
cout << "new assigned" << endl;
show(valint, 3);
cout << "common:\n";
valint[slice(0, 4, 3)] = vint(valint[slice(1, 4, 3)]) + vint(valint[slice(2, 4, 3)]);
//wrong for valint[slice(1,4,3)]并没有定义运算符+。因此程序使用slice指定的元素创建一个完整的vint对象,以便能够加法运算
//valint[slice(0, 4, 3)] = valint[slice(1, 4, 3)] + valint[slice(2, 4, 3)];
show(valint, 3);
system("pause");
return 0;
}
Original array:
1 7 4
0 9 4
8 8 2
4 5 5
second column:
7
9
8
5
second row:
0 9 4
new assigned
1 7 10
0 9 10
8 8 10
4 5 10
common:
17 7 10
19 9 10
18 8 10
15 5 10
请按任意键继续. . .
模板initializer_list
initializer_list类的初衷旨在让您能够将一系列值传递给构造函数或其他函数。
std::vector<int> values = {10,8,5.5};会报错,不允许窄带转换
std::vector<double> values = {10,5.5};但是这样可以
#include<iostream>
#include<initializer_list>
using namespace std;
double sum(initializer_list<double> il)
{
double tot = 0;
for (auto p = il.begin();p != il.end();p++)
tot += *p;
return tot;
}
double average(const initializer_list<double>& ril)
{
double tot = 0;
int n = ril.size();
double ave = 0.0;
if (n > 0)
{
for (auto p = ril.begin();p != ril.end();p++)
tot += *p;
ave = tot / n;
}
return ave;
}
int main()
{
cout << "List 1: sum= " << sum({ 2,3,4 }) << ", ave= " << average({ 2,3,4 }) << endl;
initializer_list<double> dl = { 1.1,2.2,3.3,4.4,5.5 };
cout << "List 2: sum= " << sum(dl) << ", ave= " << average(dl) << endl;
dl = { 19.0,2.1,33.4,5.9 };
cout << "List 3: sum= " << sum(dl) << ", ave= " << average(dl) << endl;
system("pause");
return 0;
}
List 1: sum= 9, ave= 3
List 2: sum= 16.5, ave= 3.3
List 3: sum= 60.4, ave= 15.1
请按任意键继续. . .