主要包含以下内容:
- 算法分类
- 函数与容器方法
- 常用函数简介
- 案例:统计单词个数
算法分类
算法函数设计两个主要的通用部分:
- 使用模板来提供泛型
- 使用迭代器来访问容器中数据的通用表示
STL将算法分为4组:
- 非修改式序列操作
- find()
- for_each()
- 修改式序列操作
- transform()
- random_shuffle()
- copy()
- 排序和相关操作
- sort()
- 通用数字运算
- 单独的头文件 < numeric >
算法的通用特征:
- 就地算法:函数完成后,在原数据上存放;
- 复制算法:函数完成后,输出到指定位置;
- 返回类型为迭代器,迭代器指向复制后的end()
函数与容器方法
两者显著区别如下:
- 函数为通用,但操作步骤可能较为繁琐;
- 部分容器方法因为容器数据结构的特殊性,执行速度优于函数方法;
对比remove函数与list容器方法:
#include <iostream>
#include <algorithm>
#include <list>
/*
** 内联函数,定义时必须要inline
*/
void Show(int);
const int SIZE = 10;
int main(){
using namespace std;
/*
** 定义、初始化两个链表la、lb
*/
int arr[SIZE] = {4, 5, 4, 2, 2,
3, 4, 8, 1, 4};
list<int> la(arr, arr + SIZE);
list<int> lb(la);
/*
** 输出两个链表内容: for_each()
*/
cout << "la:\n\t";
for_each(la.begin(), la.end(), Show);
cout << endl;
cout << "lb:\n\t";
for_each(lb.begin(), lb.end(), Show);
cout << endl;
/*
** 利用容器方法,删除 la 中所有的元素 4, 并输出
*/
la.remove(4);
cout << "la.remove:\n\t";
for_each(la.begin(), la.end(), Show);
cout << endl;
/*
** 利用函数方法,删除 lb 中所有的元素 4, 并输出
** 因为函数无法修改list长度,所以需要两步:
** 1.先remove(),remove()后list元素位置被改变(注意remove的返回类型)
** 2.利用erase()容器方法擦除所有的元素 4
*/
auto last = remove(lb.begin(), lb.end(), 4);
cout << "remove:\n\t";
for_each(lb.begin(), lb.end(), Show);
cout << endl;
lb.erase(last, lb.end());
cout << "lb.erase:\n\t";
for_each(lb.begin(), lb.end(), Show);
cout << endl;
return 0;
}
inline void Show(int v){
std::cout << v << " ";
}
程序输出为:
la:
4 5 4 2 2 3 4 8 1 4
lb:
4 5 4 2 2 3 4 8 1 4
la.remove:
5 2 2 3 8 1
remove:
5 2 2 3 8 1 4 8 1 4
lb.erase:
5 2 2 3 8 1
对比发现:
- 通常来说,函数方法可以进行容器内部元素位置的交换等工作,但无法修改容器的长度(删除元素等操作);
函数简介:
简要介绍几个函数的用法:
- next_permutation
- copy
- replace
- transform
next_permutation
主要是对元素进行排列组合;
- 将当前序列置换为此集合的下一个序列。
- 如果要生成更多序列,则返回true。
- 如果序列是集合中的最大序列,则生成最小值并返回false。
- 有点拗口,给个例子
- ABC 执行一次next_permutation后,返回值为true,原数据变为 ACB;
- CBA 执行一次next_permutation后,返回值false,数据变为 ABC;
- 会自动跳过重复的排列;
- 所以使用前最好进行排序;
给个例子,看一下输出:
#include <iostream>
#include <algorithm>
#include <vector>
inline void Show(const char & ch){
std::cout << ch << " ";
}
int main(){
using namespace std;
// 初始化向量
vector<char> vch = {'A', 'C', 'B', 'A'};
cout << "vch:\n\t";
for_each(vch.begin(), vch.end(), Show);
cout << endl;
// 排序
sort(vch.begin(), vch.end());
cout << "sort:\n\t";
for_each(vch.begin(), vch.end(), Show);
cout << endl;
// 输出排列组合
cout << "permutation:\n\t";
while (next_permutation(vch.begin(), vch.end())) {
for_each(vch.begin(), vch.end(), Show);
cout << "\n\t";
}
return 0;
}
程序结果为:
vch:
A C B A
sort:
A A B C
permutation:
A A C B // 稍微思考一下,为什么这里少了一个 A A B C
A B A C
A B C A
A C A B
A C B A
B A A C
B A C A
B C A A
C A A B
C A B A
C B A A
copy
- 利用copy输出到ostream
- 利用copy拷贝(插入)
输出/拷贝的示例:
#include <iostream>
#include <algorithm>
#include <iterator>
#include <vector>
#include <string>
int main(){
using namespace std;
// 利用copy输出:
vector<string> vch{"cat", "dog", "monkey", "mouse"};
cout << "old_vch:\n\t";
copy(vch.begin(), vch.end(),
ostream_iterator<string, char>(cout, "\n\t"));
// 利用copy拷贝插入:
// 相当于把vch[begin, end) 插入到vch_new的begin之前
vector<string> vch_new;
copy(vch.begin(), vch.end(),
insert_iterator<vector<string> >(vch_new, vch_new.begin()));
// 再次输出:
cout << "\nvch_new:\n\t";
copy(vch_new.begin(), vch_new.end(),
ostream_iterator<string, char>(cout, "\n\t"));
return 0;
}
程序输出:
old_vch:
cat
dog
monkey
mouse
vch_new:
cat
dog
monkey
mouse
replace
- 将容器中的所有的 A 替换成 B
- eg:下面例子将所有的 “old” 替换成了 “new”
示例程序:
#include <iostream>
#include <algorithm>
#include <iterator>
#include <vector>
#include <string>
int main(){
using namespace std;
// 利用copy输出:
vector<string> vch{"cat", "old", "monkey", "old"};
cout << "old_vch:\n\t";
copy(vch.begin(), vch.end(),
ostream_iterator<string, char>(cout, "\n\t"));
// 将容器中的 "old" 替换成 "new" :
replace(vch.begin(), vch.end(), "old", "new");
cout << "\nreplace:\n\t";
copy(vch.begin(), vch.end(),
ostream_iterator<string, char>(cout, "\n\t"));
return 0;
}
程序输出:
old_vch:
cat
old
monkey
old
replace:
cat
new
monkey
new
transform
- 两个容器之间的数学运算,容器长度必须相等;
- eg:varr1 = [ 1,2,3,4 ],varr2 = [ 1,2,3,4 ];
- 计算两个向量的和,积(对应位置计算,不是向量积);
- 基本都是用于数值计算,需要用到< functional >中的函数符;
- 可以将结果传送到任意位置(原、新位置);
示例程序:
#include <iostream>
#include <algorithm>
#include <iterator>
#include <vector>
#include <cmath>
#include <functional>
int main(){
using namespace std;
vector<double> varr1 = {1.0, 2.0, 3.0, 4.0};
vector<double> varr2(varr1);
ostream_iterator<double, char> out(cout, " ");
// 输出varr1 与 varr2
cout << "varr1:\n\t";
copy(varr1.begin(), varr1.end(), out);
cout << endl;
cout << "varr2:\n\t";
copy(varr2.begin(), varr2.end(), out);
cout << endl;
// 将varr1 + varr2传送到out输出;
cout << "1 + 2:\n\t";
transform(varr1.begin(), varr1.end(), varr2.begin(), out, plus<double>());
cout << endl;
// 将varr1 * varr2传送回varr1,并输出
transform(varr1.begin(), varr1.end(), varr2.begin(), varr1.begin(), multiplies<double>() );
cout << "1 * 2:\n\t";
copy(varr1.begin(), varr1.end(), out);
cout << endl;
return 0;
}
程序结果:
varr1:
1 2 3 4
varr2:
1 2 3 4
1 + 2:
2 4 6 8
1 * 2:
1 4 9 16
案例:统计一串文字中单词出现的个数
具体要求如下:
- 输入一串无标点符号的英文;
- 将所有单词大写转换成小写并存储;
- 统计每个单词出现的次数;
- 按照字典序输出单词、次数;
- 按照出现频率由高到低输出单词、次数;
测试案例:
The dog saw the cat and thought the cat fat
The cat saw the cat perfect
quit
示例程序:
#include <iostream>
#include <algorithm>
#include <iterator>
#include <vector>
#include <string>
#include <set>
#include <map>
#include <functional>
#include <cctype>
using namespace std;
typedef struct{
string word;
int times;
}Sword;
inline char toLower(char ch) { return tolower(ch); }
inline bool lessthanWord(Sword & swa, Sword & swb) { return swa.word < swb.word; }
inline bool morethanTimes(Sword & swa, Sword & swb) { return swa.times > swb.times; }
string & ToLower(string & st);
void output(Sword & s);
int main(){
// 输入words
vector<string> words;
cout <<"Enter words(quit to quit):\n";
string input;
while (cin >> input && input != "quit")
words.push_back(input);
// 输出words内容
cout << endl;
ostream_iterator<string, char> out(cout, " ");
cout << "You entered woeds:\n";
copy(words.begin(), words.end(), out);
cout << endl << endl;
// 转换大小写,并将其放入set中
set<string> wordset;
transform(words.begin(), words.end(),
insert_iterator<set<string> >(wordset, wordset.begin()), ToLower);
cout << "List of words:\n";
copy(wordset.begin(), wordset.end(), out);
cout << endl << endl;
// 统计次数,并放入struct中,需要用到count函数
vector<Sword> vSword;
Sword temp;
for (auto i = wordset.begin(); i != wordset.end(); ++i) {
temp.word = *i;
temp.times = count(words.begin(), words.end(), *i);
vSword.push_back(temp);
}
// 按照word排序输出:(字典序)
sort(vSword.begin(), vSword.end(), lessthanWord);
cout << "Sort by words:\n";
for_each(vSword.begin(), vSword.end(), output);
cout << endl;
// 按照times排序输出:(由高到底)
sort(vSword.begin(), vSword.end(), morethanTimes);
cout << "Sort by times:\n";
for_each(vSword.begin(), vSword.end(), output);
cout << endl;
return 0;
}
string & ToLower(string & st) {
transform(st.begin(), st.end(), st.begin(), toLower);
return st;
}
void output(Sword & s) {
cout << s.word << '\t' << s.times << endl;
}
程序输出:
You entered woeds:
The dog saw the cat and thought the cat fat The cat saw the cat perfect
List of words:
and cat dog fat perfect saw the thought
Sort by words:
and 1
cat 4
dog 1
fat 1
perfect 1
saw 2
the 5
thought 1
Sort by times:
the 5
cat 4
saw 2
and 1
dog 1
fat 1
perfect 1
thought 1