C++ STL入门《算法入门经典》

一)C++基础

1.头文件:C++能编译大多数C语言程序。在C头文件之前加一个小写的c字母,然后去掉.h后缀。

2.引用:在参数名之前加一个“&”符号,就表示这个参数按照传引用(byreference)的方式传递

常引用:定义引用时,前面加const关键字,即为“常引用”
eg:int n;
const int & r = n;
r 的类型是 const int &
不能通过常引用去修改其引用的内容:
eg:int n = 100;
const int & r = n;
r = 200; //编译错
n = 300; // 没问题
T & 类型的引用或T类型的变量可以用来初始化const T & 类型的引用。
const T 类型的常变量和const T & 类型的引用则不能用来初始化T &类型的引用,除非进行强制类型转换。

把vector作为参数或者返回值时,应尽量改成用引用方式传递参数,以避免不必要的值被复制。

eg:

#include<iostream>
using namespace std;
void swap2(int& a, int& b) {
int t = a; a = b; b = t;
} i
nt main() {
int a = 3, b = 4;
swap2(a, b);
cout << a << " " << b << "\n";
return 0;
}

C++中的引用就是变量的“别名”,它可以在一定程度上代替C中的指针。 例如,可以用“传引用”的方式让函数内直接修改实参。

3.字符串:C++在string头文件里定义了string类型,直接支持流式读写。 string有很多方便的函数和运算符,但速度有些慢。

stringstream在sstream头文件中。 首先用getline函数读一行数据(相当于C语言中的fgets,但由于使用string类,无须指定字符串的最大长度),然后用这一行创建一个“字符串流”——ss。 接下来只需像读取cin那样读取ss即可。

二)STL

容器: 可容纳各种数据类型的通用数据结构,是类模板
迭代器: 可用于依次存取容器中元素,类似于指针
算法: 用来操作容器中的元素的函数模板(算法本身与他们操作的数据的类型无关,因此他们可以在从简单数组到高度复杂容器的任何数据结构上使用。)

eg:int array[100];
该数组就是容器,而 int * 类型的指针变量就可以作为迭代器, sort算法可以作用于该容器上,对其进行排序:
sort(array,array+70); //将前70个元素排序

1.容器:

可以用于存放各种类型的数据( 基本类型的变量,对象等)的数据结构,都是类模版,分为三种:

a.)顺序容器(vector, deque,list)

容器并非排序的,元素的插入位置同元素的值无关。
有vector,deque,list 三种
vector 头文件 <vector>
动态数组。元素在内存连续存放。随机存取任何元素都能在常数时间完成。在尾端增删元素具有较佳的性能(大部分情况下是常数时间)。支持随机访问迭代器,所有STL算法都能对vector操作
成员函数 作用
vector(); 无参构造函数, 将容器初始化成空的
vector(int n); 将容器初始化成有n个元素
vector(int n, const T & val); 假定元素类型是T, 将容器初始化成有n个元素, 每个元素的值都是val
vector(iterator first, iterator last); 将容器初始化为与别的容器上区间[first, last)一致的内容
void pop_back(); 删除容器末尾的元素
void push_back(const T & val); 将val添加到容器末尾
int size(); 返回容器中元素的个数
T & font(); 返回容器中第一个元素的引用
T & back(); 返回容器中最后一个元素的引用

deque 头文件 <deque>
双向队列。元素在内存连续存放。随机存取任何元素都能在常数时间完成(但次于vector)。在两端增删元素具有较佳的性能(大部分情况下是常数时间)。
所有适用于vector的操作,都适用于deque
deque还有 push_front (将元素插入到容器的头部)和 pop_front (删除头部的元素) 操作

list 头文件 <list>

http://www.cnblogs.com/scandy-yuan/archive/2013/01/08/2851324.html
双向链表。元素在内存不连续存放。在任何位置增删元素都能在常数时间完成。具有所有顺序容器都有的成员函数
还支持8个成员函数:
push_front 在链表最前面插入
pop_front 删除链表最前面的元素
sort 排序 (list 不支持 STL 的算法 sort)
remove 删除和指定值相等的所有元素
unique 删除所有和前一个元素相同的元素
merge 合并两个链表, 并清空被合并的链表
reverse 颠倒链表
splice 在指定位置前面插入另一链表中的一个或多个元素,并在另一链表中删除被插入的元素
不支持随机存取,list容器只能使用双向迭代器——>不支持大于/小于比较运算符, []运算符和随机移动(即类似 “list的迭代器+2” 的操作)
list容器的迭代器不支持完全随机访问——>不能用标准库中sort函数对它进行排序
list自己的sort成员函数
list<T> classname
classname.sort(compare); //compare函数可以自己定义
classname.sort(); //无参数版本, 按<排序

b.关联容器(set, multiset, map, multimap)

元素是排序的
插入任何元素,都按相应的排序规则来确定其位置
在查找时具有非常好的性能
通常以平衡二叉树方式实现, 插入和检索的时间都是 O(log(N))
除了各容器都有的函数外,还支持以下成员函数:
find: 查找等于某个值 的元素(x小于y和y小于x同时不成立即为相等)
lower_bound : 查找某个下界
upper_bound : 查找某个上界
equal_range : 同时查找上界和下界
count :计算等于某个值的元素个数(x小于y和y小于x同时不成立即为相等)
insert: 用以插入一个元素或一个区间

set/multiset 头文件 <set>
set 即集合。 set中不允许相同元素, multiset中允许存在相同的元素。
iterator find(const T & val);在容器中查找值为val的元素,返回其迭代器。如果找不到,返回end()。
iterator insert(const T & val); 将val插入到容器中并返回其迭代器。
void insert( iterator first,iterator last); 将区间[first,last)插入容器。
int count(const T & val); 统计有多少个元素的值和val相等。
iterator lower_bound(const T & val);查找一个最大的位置 it,使得[begin(),it) 中所有的元素都比 val 小。
iterator upper_bound(const T & val);查找一个最小的位置 it,使得[it,end()) 中所有的元素都比 val 大。
pair<iterator,iterator> equal_range(const T & val);同时求得lower_bound和upper_bound。
iterator erase(iterator it);删除it指向的元素,返回其后面的元素的迭代器(Visual studio 2010上如此,但是在C++标准和Dev C++中,返回值不是这样)。


map/multimap 头文件 <map>
map与set的不同在于map中存放的元素有且仅有两个成员变量,一个名为first,另一个名为second, map根据first值对元素进行从小到大排序,并可快速地根据first来检索元素。map同multimap的不同在于是否允许相同first值的元素。

c.容器适配器(stack, queue, priority_queue)
都有3个成员函数:
• push: 添加一个元素;
• top: 返回栈顶部或队头元素的引用
• pop: 删除一个元素
容器适配器上没有迭代器——>STL中各种排序, 查找, 变序等算法都不适合容器适配器

stack 头文件 <stack>
栈。是项的有限序列,并满足序列中被删除、检索和修改的项只能是最近插入序列的项(栈顶的项)。 后进先出。

queue 头文件 <queue>
队列。插入只可以在尾部进行,删除、检索和修改只允许从头部进行。 先进先出。

priority_queue 头文件 <queue>
优先级队列。最高优先级元素总是第一个出列

顺序容器和关联容器中都有的成员函数:

begin 返回指向容器中第一个元素的迭代器
end 返回指向容器中最后一个元素后面的位置的迭代器
rbegin 返回指向容器中最后一个元素的迭代器
rend 返回指向容器中第一个元素前面的位置的迭代器
erase 从容器中删除一个或几个元素
clear 从容器中删除所有元素

顺序容器的常用成员函数:

front :返回容器中第一个元素的引用
back : 返回容器中最后一个元素的引用
push_back : 在容器末尾增加新元素
pop_back : 删除容器末尾的元素
erase :删除迭代器指向的元素(可能会使该迭代器失效),或删除一个区间,返回被删除元素后面的那个元素的迭代器

2.迭代器

用于指向顺序容器和关联容器中的元素
迭代器用法和指针类似
有const 和非 const两种
通过迭代器可以读取它指向的元素
通过非const迭代器还能修改其指向的元素

定义一个容器类的迭代器的方法可以是:
容器类名::iterator 变量名;
或:
容器类名::const_iterator 变量名;
访问一个迭代器指向的元素:
* 迭代器变量名

迭代器上可以执行 ++ 操作, 以使其指向容器中的下一个元素。如果迭代器到达了容器中的最后一个元素的后面,此时再使用它,就会出错,类似于使用NULL或未初始化的指针一样。

a.双向迭代器

若p和p1都是双向迭代器,则可对p、 p1可进行以下操作:
++p, p++ 使p指向容器中下一个元素
--p, p-- 使p指向容器中上一个元素
* p 取p指向的元素
p = p1 赋值
p == p1 , p!= p1 判断是否相等、不等

b.随机访问迭代器

若p和p1都是随机访问迭代器,则可对p、 p1可进行以下操作:
 双向迭代器的所有操作
 p += i 将p向后移动i个元素
 p -= i 将p向向前移动i个元素
 p + i 值为: 指向 p 后面的第i个元素的迭代器
 p - i 值为: 指向 p 前面的第i个元素的迭代器
 p[i] 值为: p后面的第i个元素的引用
 p < p1, p <= p1, p > p1, p>= p1

3.算法

容器 容器上的迭代器类别
vector 随机访问
deque 随机访问
list 双向
set/multiset 双向
map/multimap 双向
stack 不支持迭代器
queue 不支持迭代器
priority_queue 不支持迭代器

有的算法,例如sort,binary_search需要通过
随机访问迭代器来访问容器中的元素,那么list以及关联容器就不支持该算法!

算法就是一个个函数模板, 大多数在<algorithm> 中定义STL中提供能在各种容器中通用的算法,比如查找,排序等
算法通过迭代器来操纵容器中的元素。许多算法可以对容器中的一个局部区间进行操作,因此需要两个参数,一个是起始元素的迭代器,一个是终止元素的后面一个元素的迭代器。比如,排序和查找
有的算法返回一个迭代器。比如 find() 算法,在容器中查找一个元素,并返回一个指向该元素的迭代器
算法可以处理容器,也可以处理普通数组

STL中的算法大致可以分为以下七类:
• 不变序列算法
该类算法不会修改算法所作用的容器或对象
适用于顺序容器和关联容器
时间复杂度都是O(n)
find:
template<class InIt, class T>
InIt find(InIt first, InIt last, const T& val);
返回区间 [first,last) 中的迭代器 i ,使得 * i == val
find_if:
template<class InIt, class Pred>
InIt find_if(InIt first, InIt last, Pred pr);
返回区间 [first,last) 中的迭代器 i, 使得 pr(*i) == true
for_each:
template<class InIt, class Fun>
Fun for_each(InIt first, InIt last, Fun f);
对[first, last)中的每个元素e, 执行f(e), 要求 f(e)不能改变e
count:
template<class InIt, class T>
size_t count(InIt first, InIt last, const T& val);
计算[first, last) 中等于val的元素个数(x==y为true算等于)
count_if:
template<class InIt, class Pred>
size_t count_if(InIt first, InIt last, Pred pr);
计算[first, last) 中符合pr(e) == true 的元素e的个数
min_element:
template<class FwdIt>
FwdIt min_element(FwdIt first, FwdIt last);
返回[first,last) 中最小元素的迭代器, 以 “<” 作比较器,最小指没有元素比它小, 而不是它比别的不同元素都小,因为即便a!= b, a<b 和b<a有可能都不成立
max_element:
template<class FwdIt>
FwdIt max_element(FwdIt first, FwdIt last);
返回[first,last) 中最大元素(不小于任何其他元素)的迭代器以 “<” 作比较器


• 变值算法
此类算法会修改源区间或目标区间元素的值,值被修改的那个区间, 不可以是属于关联容器的
for_each 对区间中的每个元素都做某种操作
copy 复制一个区间到别处
template<class InIt, class OutIt>
OutIt copy(InIt first, InIt last, OutIt x);
本函数对每个在区间[0, last - first)中的N执行一次
*(x+N) = *(first + N), 返回 x + N
对于copy(v.begin(),v.end(),output);
first 和 last 的类型是 vector<int>::const_iterator
output 的类型是 ostream_iterator<int>
copy_backward 复制一个区间到别处, 但目标区前是从后往前被修改的
transform 将一个区间的元素变形后拷贝到另一个区间
template<class InIt, class OutIt, class Unop>
OutIt transform(InIt first, InIt last, OutIt x, Unop uop);
对[first,last)中的每个迭代器I,
• 执行 uop( * I ); 并将结果依次放入从 x 开始的地方
• 要求 uop( * I ) 不得改变 * I 的值,本模板返回值是个迭代器, 即 x + (last-first)
• x可以和 first相等
swap_ranges 交换两个区间内容
fill 用某个值填充区间
fill_n 用某个值替换区间中的n个元素
generate 用某个操作的结果填充区间
generate_n 用某个操作的结果替换区间中的n个元素
replace 将区间中的某个值替换为另一个值
replace_if 将区间中符合某种条件的值替换成另一个值
replace_copy 将一个区间拷贝到另一个区间,拷贝时某个值要换成新值拷过去
replace_copy_if 将一个区间拷贝到另一个区间,拷贝时符合某条件的值要换成新值拷过去

• 删除算法
删除一个容器里的某些元素
删除 -- 不会使容器里的元素减少
• 将所有应该被删除的元素看做空位子
• 用留下的元素从后往前移, 依次去填空位子
• 元素往前移后, 它原来的位置也就算是空位子
• 也应由后面的留下的元素来填上
• 最后, 没有被填上的空位子, 维持其原来的值不变删除,算法不应作用于关联容器
remove 删除区间中等于某个值的元素
remove_if 删除区间中满足某种条件的元素
remove_copy 拷贝区间到另一个区间. 等于某个值的元素不拷贝
remove_copy_if 拷贝区间到另一个区间. 符合某种条件的元素不拷贝
unique 删除区间中连续相等的元素, 只留下一个(可自定义比较器)
template<class FwdIt>
FwdIt unique(FwdIt first, FwdIt last);
用 == 比较是否等
template<class FwdIt, class Pred>
FwdIt unique(FwdIt first, FwdIt last, Pred pr);
用 pr (x,y)为 true说明x和y相等
对[first,last) 这个序列中连续相等的元素, 只留下第一个返回值是迭代器, 指向元素删除后的区间的最后一个元
素的后面
unique_copy 拷贝区间到另一个区间. 连续相等的元素, 只拷贝第一个到目标区间 (可自定义比较器)


• 变序算法
变序算法改变容器中元素的顺序,但是不改变元素的值,变序算法不适用于关联容器,算法复杂度都是O(n)的
reverse
template<class BidIt>
void reverse(BidIt first, BidIt last);
颠倒区间[first,last)顺序
next_permutation
template<class InIt>
bool next_permutaion (Init first,Init last);
求下一个排列
stable_patition
把区间内满足某个条件的元素移到前面
不满足该条件的移到后面
而对这两部分元素, 分别保持它们原来的先后次序不变
random_shuffle
template<class RanIt>
void random_shuffle(RanIt first, RanIt last);
随机打乱[first,last) 中的元素, 适用于能随机访问的容器


• 排序算法
不适用于关联容器和list
sort 快速排序
template<class RanIt>
void sort(RanIt first, RanIt last);
按升序排序,判断x是否应比y靠前, 就看 x < y 是否为true
template<class RanIt, class Pred>
void sort(RanIt first, RanIt last, Pred pr);
按升序排序,判断x是否应比y靠前, 就看 pr(x,y) 是否为true
sort 实际上是快速排序, 时间复杂度 O(n*log(n))
• 平均性能最优
• 但是最坏的情况下, 性能可能非常差
如果要保证 “最坏情况下” 的性能, 那么可以使用
• stable_sort
• stable_sort 实际上是归并排序, 特点是能保持相等元素之间的先后次序
• 在有足够存储空间的情况下, 复杂度为 n * log(n), 否则复杂度为 n * log(n) * log(n)
• stable_sort 用法和 sort相同。
排序算法要求随机存取迭代器的支持, 所以list不能使用排序算法, 要使用list::sort

• 有序区间算法
要求所操作的区间是已经从小到大排好序的,需要随机访问迭代器的支持,有序区间算法不能用于关联容器和list
binary_search
折半查找
要求容器已经有序且支持随机访问迭代器, 返回是否找到
template<class FwdIt, class T>
bool binary_search(FwdIt first, FwdIt last, const T& val);
上面这个版本, 比较两个元素x, y 大小时, 看 x < y
template<class FwdIt, class T, class Pred>
bool binary_search(FwdIt first, FwdIt last, const T& val, Pred pr);
上面这个版本, 比较两个元素x, y 大小时, 若 pr(x,y) 为true, 则认为x小于y
lower_bound
template<class FwdIt, class T>
FwdIt lower_bound(FwdIt first, FwdIt last, const T& val);
要求[first,last)是有序的,查找[first,last)中的, 最大的位置 FwdIt, 使得[first,FwdIt)中所有的元素都比 val 小
upper_bound
template<class FwdIt, class T>
FwdIt upper_bound(FwdIt first, FwdIt last, const T& val);
要求[first,last)是有序的,查找[first,last)中的, 最小的位置 FwdIt, 使得[FwdIt,last)中所有的元素都比 val 大
equal_range
template<class FwdIt, class T>
pair<FwdIt, FwdIt> equal_range(FwdIt first, FwdIt last,
const T& val);
要求[first,last)是有序的,返回值是一个pair, 假设为 p, 则:
• [first,p.first) 中的元素都比 val 小
• [p.second,last)中的所有元素都比 val 大
• p.first 就是lower_bound的结果
• p.last 就是 upper_bound的结果
merge
template<class InIt1, class InIt2, class OutIt>
OutIt merge(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2,OutIt x);
用 < 作比较器
template<class InIt1, class InIt2, class OutIt, class Pred>
OutIt merge(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2,OutIt x, Pred pr);
用 pr 作比较器,把[first1,last1), [ first2,last2) 两个升序序列合并, 形成第3 个升序序列, 第3个升序序列以 x 开头


• 数值算法

4.测试STL

随机数发生器: 核心函数是cstdlib中的rand( ),如果不调用srand而直接使用rand( ),相当于调用过一次srand(1),因此程序每次执行时,将得到同一套随机数。为了得到不同的随机数,请只在程序开头调用一次srand,而不要在同一个程序中多次调用。

“assert(表达式)”,作用是:当表达式为真时无变化,但当表达式为假时强行终止程序,并且给出错误提示。

eg:

void test_sort(vector<int>& v)
 {
sort(v.begin(), v.end());
for(int i = 0; i < v.size()-1; i++)
assert(v[i] <= v[i+1]);
}


  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值