C++标准库
C++ Standard Library,一般安装C++编译器时都会安装。
标准模板库
Standard Template Library(STL),包含在C++标准库中(核心)。
泛型编程
Generic Programming,使用模板(Template)为主要编程手段来编写代码。
标准模板库就是用泛型编程的编码方式写的一套供程序员非常方便使用的库。
数据结构浅谈
数据结构,研究数据存取的学问。栈、队列、链表、散列表(哈希表)、树、图等,存取速度快慢,优劣势,具体使用场景等。
数据结构学习方法
(1)栈:后进先出。
(2)队列:先进先出。
(3)链表:多个节点链(串)在一起,每个节点都有数据部分和next指针部分。
(4)其它树、图、散列表等。
推荐书籍
《算法导论》
#include
#include
#include
#include
using namespace std;
容器
vetcor、map、list等。
迭代器
用于遍历或者访问容器中的元素,类似指针。
算法(函数)
STL提供的一些函数,用来实现一些功能,例如search(查找)、sort(排序)、copy(复制)等。
分配器
不太常用,针对频繁分配小块内存时,减少内存空间的浪费,具有一定的提升分配内存效率的作用(内存分配器)。一般使用默认分配器(allocator)。
其它
适配器、仿函数(函数对象)等。
容器,保存数据,用于管理一大群元素。
顺序容器
Sequence Containers,array、vector、deque、queue、stack、list、forward_list。
关联容器
Associative Containers,每一个元素都是一个键值(key/value)对。通过键来找元素,类似小数据库或小字典,查找快速。内部使用树的数据结构来存储数据,按照一定规则(比如根据key)自动存放元素位置,无法控制元素插入位置,只能控制插入内容。set、multiset、map、multimap。
hash_set、hash_multiset、hash_map、hash_multimap等(已过时,用unordered_set、unordered_multiset、unordered_map、unordered_multimap替代)。
无序容器
Unordered Contianers,属于关联容器的一种,只在意元素是否在容器内,内部用哈希表实现。
unordered_set、unordered_multiset、unordered_map、unordered_multimap等。
与内置数组比较:
(1)比内置数组更安全,内置数组不能直接使用拷贝和赋值,array数组可以。
(2)array下标必须是无符号类型,而数组则没有这个限制(可以负数)。
array<int, 10> ial1={0,1,2,3};
array<int, 10> copy=ial1;//只要保证两者的类型一致就可以(包括元素类型和大小)
#include
array<string, 5> mystring = {"I", "love", "china"};
cout <<mystring.size()<<endl;//5
cout <<sizeof(mystring)<<endl;//不等于5,array类的大小
mystring[0] = "long long long";
#include
#include
using namespace std;
class A
{
public:
int m_i;
A(int tmp = 0) : m_i(tmp)
{
cout << "A(int)\n";
}
A(const A &a)
{
m_i = a.m_i;
cout << "A(const A&) \n";
}
~A()
{
cout << "~A()\n";
}
};
#define N 3
int main()
{
{
//vector veca(N);
vector<A> veca;
veca.reverse(N);
for (int i = 0; i < N; i++)
{
cout << "size=" << veca.size() << endl;
cout << "capacity=" << veca.capacity() << endl;
// veca.push_back(A(1));//未提前分配空间,会多次调用构造函数和析构函数
// veca.emplace_back(A(1));//就地在尾部插入类,省去了拷贝或移动元素的过程。
veca[i] = A(i);
}
}
cout << "over";
return 0;
}
#include
#include
using namespace std;
class A
{
public:
A(int tmp) : m_i(tmp)
{
cout << "A(int)" << endl;
}
A(const A &tmpA)
{
m_i = tmpA.m_i;
cout << "A(const A&)" << endl;
}
~A()
{
cout << "~A()" << endl;
}
public:
int m_i;
};
int main()
{
{
deque<A> mydeque;
for (int i = 0; i < 2; i++)
{
cout << "begin" << endl;
mydeque.push_front(A(i));
mydeque.push_back(A(i));
cout << "end" << endl;
}
for (int i = 0; i < mydeque.size(); i++)
{
cout << i << ": " << mydeque[i].m_i << ", address: " << &mydeque[i] << endl;
}
}
cout << "main over" << endl;
return 0;
}
队列,先进先出,一端进,一端出。
双向链表,内存空间不连续。
沿链查找元素,查找效率不突出;任意位置插入和删除元素都非常迅速。
forward_list
单向链表,push_front,头部插入数据。无push_back。
map和set
关联容器,内部实现多为红黑树。
map容器,每个元素都是键值对(key/value),key不能重复,重复需使用multimap。
#include
#include
#include
using namespace std;
class A
{
public:
int m_i;
A(int tmp = 0) : m_i(tmp)
{
cout << "A(int)\n";
}
A(const A &a)
{
m_i = a.m_i;
cout << "A(const A&) \n";
}
~A()
{
cout << "~A()\n";
}
};
#define N 3
int main()
{
map<int, string> mymap = {
pair<int, string>(1, "java"),
pair<int, string>(2, "c++"),
{3, "python"},
make_pair(4, "go")};
cout << mymap[4] << endl;
mymap.insert({4, "matlab"}); // key,4存在,这行不执行
cout << mymap.at(4) << endl;
mymap[4] = "matlab"; // key,4存在,会被替换
cout << mymap.at(4) << endl;
mymap[5] = "ruby"; // key,5不存在,会赋值
cout << mymap.at(5) << endl;
cout << mymap.size() << endl;
cout << mymap[6] << endl; //生成一个{6, ""}
cout << mymap.size() << endl; //+1
auto iter = mymap.find(3);
if (iter != mymap.end())
{
cout << iter->first << endl;
cout << iter->second << endl;
}
cout << "over";
return 0;
}
set容器中,每个元素都是value,value不能重复,重复需使用multiset。
map、set等关联容器,插入速度慢一些(寻找合适位置),查找速度快。
#include
#include
#include
using namespace std;
int main()
{
unordered_set<int> myset;
cout << myset.bucket_count() << endl;
for (int i = 0; i < 8; i++)
myset.insert(i);
cout << myset.bucket_count() << endl;
cout << myset.max_bucket_count() << endl;
cout << myset.size() << endl;
for (int i = 0; i < myset.bucket_count(); i++)
cout << myset.bucket_size(i) << endl;
if (myset.find(5) != myset.end())
cout << "find\n";
if (find(myset.begin(), myset.end(), 5) != myset.end())
cout << "find\n";
cout << "over";
return 0;
}
vector<int> myvec;
vector<int, std::allocator<int>> myvec;
内存分配器扮演着内存池的角色,大量减少对malloc的调用以减少对内存分配的浪费。
list<int> mylist;
mylist.push_back(10);
mylist.push_back(20);
mylist.push_back(36);
for(auto iter = mylist.begin(); iter != mylist.end(); ++iter){
cout<<*iter<<endl;
int *p=&(*iter);
printf("%p\n", p);
}
//测试表明,默认分配器未使用内存池工作机制,原样调用底层malloc。
分配器分配内存,写入数据,释放内存。
allocator<int> aalloc;
int *p=aalloc.allocate(3);
int *q=p;
*q=1;q++;
*q=2;q++;
*q=3;
aalloc.deallocate(p, 3);
分配器就是一次分配一大块内存,每次使用一小块,用链表将这些内存块管理起来。通过内存池的内存分配机制,有效减少调用malloc次数,减少内存浪费,提高程序运行效率。
//分配器上不同编号对应不同大小的内存块,
//应对不同大小的内存分配申请
//3个list可能共用一个分配器
list<int, allocator<int>> mylist1;
list<double, allocator<double>> mylist2;
list<int, allocator<int>> mylist3;
可遍历STL容器全部或部分元素的对象(行为类似于指针对象,*iter获取迭代器所指向的内容)。
迭代器由容器提供(容器里面定义者迭代器的具体类型细节),用来表现容器中的某一个位置。
#include
#include
using namespace std;
int main()
{
vector<int> iv = {1, 2, 3};
for (vector<int>::iterator iter = iv.begin(); iter != iv.end(); ++iter)
{
*iter += 6;
cout << *iter << endl;
}
cout << "over";
return 0;
}
依据迭代器的移动特性和操作进行分类。
(1)输出型迭代器(Output iterator)
struct output_iterator_tag
(2)输入型迭代器(Input iterator)
struct input_iterator_tag
(3)前向型迭代器(Input iterator)
struct forward_iterator_tag
(4)双向迭代器(Bidirectional iterator)
struct bidirectional_iterator_tag
(5)随机访问迭代器(Random-access iterator)
struct random_access_iterator_tag
struct output_iterator_tag
继承关系:
struct input_iterator_tag
↓
struct forward_iterator_tag
↓
struct bidirectional_iterator_tag
↓
struct random_access_iterator_tag
多数容器有迭代器,stack、queue等容器不提供迭代器。
迭代器种类 | 迭代器能力 | 提供该迭代器的容器 |
---|---|---|
output_iterator_tag | 向前写入 | ostream |
input_iterator_tag | 向前读取一次 | istream |
forward_iterator_tag | 向前读取 | forward_list、nordered |
bidirectional_iterator_tag | 向前和向后读取 | list、set、multiset、map、multimap |
random_access_iterator_tag | 随机读取(跳过一定个数的元素) | array、vector、deque、string、C风格数组 |
#include
#include
#include
#include
#include
#include
using namespace std;
void _display_category(output_iterator_tag mytag)
{
cout << "output_iterator_tag" << endl;
}
void _display_category(input_iterator_tag mytag)
{
cout << "input_iterator_tag" << endl;
}
void _display_category(forward_iterator_tag mytag)
{
cout << "forward_iterator_tag" << endl;
}
void _display_category(bidirectional_iterator_tag mytag)
{
cout << "bidirectional_iterator_tag" << endl;
}
void _display_category(random_access_iterator_tag mytag)
{
cout << "random_access_iterator_tag" << endl;
}
template <typename T>
void display_category(T iter)
{
cout << "begin" << endl;
typename iterator_traits<T>::iterator_category cagy; //过滤器(萃取机),获取T迭代器类型的种类
_display_category(cagy);
cout << "typeid(iter).name()=" << typeid(iter).name() << endl;
cout << "end" << endl;
}
int main()
{
display_category(array<int, 100>::iterator()); //()用于产生临时对象
display_category(vector<int>::iterator());
display_category(list<int>::iterator());
display_category(map<int, int>::iterator());
display_category(set<int>::iterator());
cout << "over";
return 0;
}
迭代器功能整理:
(1)输出型迭代器(Output iterator)
struct output_iterator_tag
一步步往前走,通过这个迭代器往容器中写数据。
*iter = value,value写入迭代器指向的位置。
++iter
iter++
(2)输入型迭代器(Input iterator)
struct input_iterator_tag
一步步往前走,通过这个迭代器顺序返回元素值。
*iter,读取元素值
iter->member,读取元素成员
++iter
iter++
iter1 == iter2
iter1 != iter2
(3)前向型迭代器(Input iterator)
struct forward_iterator_tag
继承input_iterator_tag,同时支持写入操作
*iter,读取元素值
iter->member,读取元素成员
*iter = value,value写入迭代器指向的位置。
++iter
iter++
iter1 == iter2
iter1 != iter2
iter1 = iter2,迭代器赋值
(4)双向迭代器(Bidirectional iterator)
struct bidirectional_iterator_tag
继承forward_iterator_tag,增加向回(反向)迭代,即迭代位置可以往回退。
*iter,读取元素值
iter->member,读取元素成员
*iter = value,value写入迭代器指向的位置。
++iter
iter++
iter1 == iter2
iter1 != iter2
–iter
iter–
(5)随机访问迭代器(Random-access iterator)
struct random_access_iterator_tag
继承bidirectional_iterator_tag,增加随机访问能力,即增减偏移量,同时能够计算距离,支持一些关系运算等。
*iter,读取元素值
iter->member,读取元素成员
*iter = value,value写入迭代器指向的位置。
++iter
iter++
iter1 == iter2
iter1 != iter2
–iter
iter–
iter[n]
iter+=n
iter-=n
iter+n
iter-n
iter1-iter2,计算距离
iter1
iter1<=iter2, iter1>=iter2
算法是函数模板,接收各种类型的迭代器作为形参。算法内部根据迭代器类型,有不同处理,处于算法执行效率的考虑。
#include
void func(int i){
cout<<i<<endl;
}
vector<int> myvector = {10, 20, 30, 40, 50};
//两个形参迭代器,一个可调用对象,
//不断迭代两个迭代器间的元素,作为实参来调用myfunc函数。
for_each(myvector.begin(), myvector.end(), func);
template<class InputIterator, class Function>
Function for_each(InputIterator first, InputIterator last, Function f){
for(; first != last; ++first)
f(*first);
return f;
}
vector<int> myvector = {10, 20, 30, 40, 50};
vector<int>::iterator finditer = find(myvector.begin(), myvector.end(), 400);
if(finditer != myvector.end())
cout<<"find"<<endl;
else
cout<<"not find"<<endl;
//优先使用容器自带(若存在)的同名函数。
map<int, string> mymap;
mymap.insert(std::make_pair(1, "wang"));
mymap.insert(std::make_pair(2, "li"));
auto finditer = mymap.find(2);
if(finditer != mymap.end()){
cout<<"find"<<endl;
cout<<iter->first<<iter->second<<endl;
}
vector<int> myvector = {10, 20, 30, 40, 50};
auto finditer = find_if(myvector.begin(), myvector.end(), [](int val){ //可调用对象
if(val>15)
return true; //返回第一个满足规则的元素
return false;
});
if(finditer != myvector.end())
cout<<"find"<<*finditer<<endl;
else
cout<<"not find"<<endl;
vector<int> myvector = {10, 20, 30, 40, 50};
//sort(myvector.begin(), myvector.end());//默认升序
sort(myvector.begin(), myvector.begin()+3);//前三个元素升序
bool myfuncsort(int i, int j){
//return i
return i>j;//降序
}
sort(myvector.begin(), myvector.end(), myfuncsort);
class A{
public:
bool operator()(int i, int j){
//return i
return i>j;//降序
}
};
A a;
sort(myvector.begin(), myvector.end(), a);
list<int> mylist = {10, 20, 30, 40, 50};
//sort(mylist .begin(), mylist .end());//sort算法不适用于双向迭代器,只适用于随机访问迭代器
mylist.sort(myfuncsort);//list容器自带sort成员函数
顺序容器可以排序,关联容器(含无序容器)不适合排序。
map<int, string> mymap;
mymap.insert(make_pair(50, "wang"));
mymap.insert(make_pair(15, "li"));
mymap.insert(pair<int, string>(80, "zhao"));
//sort(mymap.begin(), mymap.end());//error
unordered_set<int> myset = {10, 20, 30, 40, 50};
//sort(myset .begin(), myset .end());//error
函数对象(function objects)或仿函数(functors),配合算法使用实现特定功能,调用方式很统一,即:名字(参数列表)。
函数对象形式整理
#include
表达式(函数对象) | 效果 |
---|---|
negate<类型>() | -param |
plus<类型>() | param1+param2 |
minus<类型>() | param1-param2 |
multiplies<类型>() | param1*param2 |
divides<类型>() | param1/param2 |
modulus<类型>() | param1%param2 |
表达式(函数对象) | 效果 |
---|---|
equal_to<类型>() | param1==param2 |
not_equal_to<类型>() | param1!=param2 |
less<类型>() | param1 |
greater<类型>() | param1>param2 |
less_equal<类型>() | param1<=param2 |
greater_equal<类型>() | param1>=param2 |
表达式(函数对象) | 效果 |
---|---|
logical_not<类型>() | !param |
logical_and<类型>() | param1&¶m2 |
logical_or<类型>() | param1||param2 |
表达式(函数对象) | 效果 |
---|---|
bit_xor<类型>() | param1^param2 |
bit_and<类型>() | param1¶m2 |
bit_or<类型>() | param1|param2 |
template<class _Ty = void>
struct plus{
constexpr _Ty operator()(const _Ty& _Left, const _Ty& _Right) const {
return _Left + _Right;
}
};
cout<<plus<int>()(4, 5)<<endl;
//plus实例化类
//plus()临时可调用对象(重载了operator())
//plus()(4, 5)函数调用
vector<int> myvector = {10, 20, 30, 40, 50};
sort(myvector.begin(), myvector.end(), greater<int>());
sort(myvector.begin(), myvector.end(), less<int>());
//greater()和less()产生临时的可调用对象
类似于转接头。将一个既有东西进行适当改造,增减一点东西,就会成为一个适配器。
stack和queue归类为容器适配器,将既有的deque进行适当的改造(阉割一点东西)。
template<class _Ty, class _Container = deque<_Ty>>
class queue {
public:
//...
void push(value_type && _Val){
c.push_back(_STD move(_Val));
}
protected:
_Container c;
};
算法是函数模板,算法适配器就是函数适配器,最典型的是绑定器(Binder)。
bind,函数模板,算法适配器中的绑定器。
vector<int> myvector = {50, 15, 80, 30, 46, 80};
int cishu = count(myvector.begin(), myvector.end(), 80);
cout << cishu <<endl;
class A{
public:
bool operator()(int i){
return i>40;
}
};
A a;
cishu = count_if(myvector.begin(), myvector.end(), a);
template<class _Ty = void>
struct less{
constexpr bool operator()(const _Ty& _Left, const _Ty& _Right) const {
return _Left < _Right;
}
};
class A{
public:
bool operator()(int i){
//return i>40;
return 40<i;
}
};
//less()中operator()第一个参数绑定了40
auto bf = bind(less<int>(), 40, placeholders::_1);
bf(19);//调用,第二个参数19
cishu = count_if(myvector.begin(), myvector.end(), bind(less<int>(), 40, placeholders::_1));
方向迭代器就是一个迭代器适配器。
vector<int> iv = {100, 200, 300};
for(vector<int>::reverse_iterator riter = iv.rbegin(); riter != iv.rend(); riter++)
cout<<*riter<<endl;