STL(Standard Template Library)、容器(container)、仿函数(functor)、算法(algorithm)、迭代器(iterator)、容器适配器(adapter)、空间配置器(allocator)、STL总结、关于Boost库、多线程、推荐基本C++的书籍。
容器用于存放数据;STL的容器分为两大类:
struct Display
{
void operator()(int i)
{
cout << i << " ";
}
};
int main()
{
int iArr[] = { 1, 2,3,4,5 };
//序列式容器
vector<int> iVector(iArr, iArr + 4);
list<int> iList(iArr, iArr + 4);
deque<int> iDeque(iArr, iArr + 4);
//容器适配器
queue<int> iQueue(iDeque); // 队列 先进先出
stack<int> iStack(iDeque); // 栈 先进后出
priority_queue<int> iPQueue(iArr, iArr + 4); // 优先队列,按优先权
//序列式容器遍历——3种方法
//序列式容器遍历 迭代器+仿函数遍历
for_each( iVector.begin(), iVector.end(), Display() );
cout << endl;
//序列式容器遍历 迭代器+循环遍历
for (auto it = iList.begin(); it != iList.end(); it++)
{
cout << *it << " ";
}
cout << endl;
//序列式容器遍历 for (auto i : s)
for (auto i:iDeque)
{
cout <<i<< " ";
}
//容器适配器遍历
while ( !iQueue.empty() )
{
cout << iQueue.front() << " "; // 1 2 3 4
iQueue.pop();
}
cout << endl;
while (!iStack.empty())
{
cout << iStack.top() << " "; // 4 3 2 1
iStack.pop();
}
cout << endl;
while (!iPQueue.empty())
{
cout << iPQueue.top() << " "; // 4 3 2 1
iPQueue.pop();
}
cout << endl;
return 0;
}
注:容器的遍历可参考 c++ vector容器遍历方式 、 for(auto &i:s)和for(auto i:s)区别 ,仿函数参考 c++仿函数 functor 。
struct Display
{
void operator()(pair<string, double> info)
{
cout << info.first << ": " << info.second << endl;
}
};
int main()
{
map<string, double> studentSocres;
// []运算符作用:查找与Key匹配的元素(不存在则使用默认映射插入),返回的是Value的引用(意味着外部可以更新Value)
studentSocres["LiMing"] = 95.0;
//insert逻辑:如果存在则不插入
studentSocres.insert(pair<string, double>("zhangsan", 100.0) );
studentSocres.insert(map<string, double>::value_type("zhaoliu", 95.5) );
for_each(studentSocres.begin(), studentSocres.end(), Display());
cout << endl;
//查找值
map<string, double>::iterator iter;
iter = studentSocres.find("zhaoliu");
if (iter != studentSocres.end())
{
cout << "Found the score is: " << iter->second << endl;
}
else
{
cout << "Didn't find the key." << endl;
}
// 使用迭代器完成遍历查找的过程
iter = studentSocres.begin();
while (iter != studentSocres.end())
{
if (iter->second < 98.0) // 去除不是优秀的同学
{
studentSocres.erase(iter++); // 注意:迭代器失效问题
}
else
{
iter++;
}
}
for_each(studentSocres.begin(), studentSocres.end(), Display());
cout << endl;
for (iter = studentSocres.begin(); iter != studentSocres.end(); iter++)
{
if (iter->second <= 98.5)
{
iter = studentSocres.erase(iter); // 注意:迭代器失效问题
}
}
for_each(studentSocres.begin(), studentSocres.end(), Display());
cout << endl;
studentSocres.erase(studentSocres.begin(), studentSocres.end());
for_each(studentSocres.begin(), studentSocres.end(), Display());
cout << endl;
return 0;
}
bool MySort(int a, int b) { return a < b; }
void Display(int a) { cout << a << " "; }
template<class T>
inline bool MySortT(T const& a, T const& b) { return a < b; }
template<class T>
inline void DisplayT(T const& a) { cout << a << " "; }
struct SortF
{
bool operator() (int a, int b) { return a < b; }
};
struct DisplayF
{
void operator() (int a) { cout << a << " "; }
};
// C++仿函数模板
template<class T>
struct SortTF
{
inline bool operator() (T const& a, T const& b) const { return a < b; }
};
template<class T>
struct DisplayTF
{
inline void operator() (T const& a) const { cout << a << " "; }
};
int main()
{
// C++方式
int arr[] = { 4, 3, 2, 1, 7 };
sort(arr, arr + 5, MySort);
for_each(arr, arr + 5, Display);
cout << endl;
// C++泛型
int arr2[] = { 4, 3, 2, 1, 7 };
sort(arr2, arr2 + 5, MySortT<int>);
for_each(arr2, arr2 + 5, DisplayT<int>);
cout << endl;
// C++仿函数
int arr3[] = { 4, 3, 2, 1, 7 };
sort(arr3, arr3 + 5, SortTF<int>() );
for_each(arr3, arr3 + 5, DisplayTF<int>());
cout << endl;
// C++仿函数模板
int arr4[] = { 4, 3, 2, 1, 7 };
sort(arr4, arr4 + 5, SortF());
for_each(arr4, arr4 + 5, DisplayF());
cout << endl;
return 0;
}
STL 中算法大致分为四类(包含于<algorithm>、<numeric>、<functional>):
最常见的算法包括:查找、排序和通用算法、排列组合算法、数值算法、集合算法等算法。
transform函数的作用是将某操作应用于指定范围的每个元素,参考 C++学习transform函数的应用 ,示例如下:
int main()
{
// transform和lambda表达式
int ones[] = { 1, 2, 3, 4, 5 };
int twos[] = { 10, 20, 30, 40, 50 };
int results[5];
transform(ones, ones + 5, twos, results, std::plus<int>()); // 数组元素依次相加并返回
for_each(results, results + 5, [ ](int a)->void { cout << a << endl; } ); // lambda表达式(匿名函数)
cout << endl;
return 0;
}
查找、统计相关的算法如下:
int main()
{
int arr[] = { 0, 1, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 7, 8 };
int len = sizeof(arr) / sizeof(arr[0]);
vector<int> iA(arr + 2, arr + 6); // {2,3,3,4}
// 统计6的个数
cout << count(arr, arr + len, 6) << endl;
// 统计<7的个数, bind2nd已经启用
cout << count_if(arr, arr + len, bind2nd(less<int>(), 7) ) << endl;
// 9找不到,二分法查找
cout << binary_search(arr, arr + len, 9) << endl;
// 查找子序列,不存在时返回负值
cout << *search(arr, arr + len, iA.begin(), iA.end()) << endl;
cout << endl;
return 0;
}
上面使用了“arr + len”,但数组名不是指针,只是可以转换为指向其指代实体的指针,参考 C/C++中数组名退化为指针的情况。
注:binder1st、binder2nd在 c + + 11 中已弃用,在 c + + 17 中删除。
输入一个不存在重复字符的字符串,打印出字符串中字符的全排列,比如:
输入: "123" 321 = 3!
输出: 123 132 213 231 321 312
//f(123) = 1+f(23), f(23) = 2+f(3), f(3) = 3 递归
void swap(char* a, char* b)
{
char temp = *a;
*a = *b;
*b = temp;
}
void Permutation(char* pStr, char* pPostion)
{
// 基准点
if (*pPostion == '\0')
{
cout << pStr << endl;
}
else
{
for (char* pChar = pPostion; *pChar != '\0'; pChar++)
{
// 依次和后面的字符交换
swap(*pChar, *pPostion);
Permutation(pStr, pPostion + 1);
// 换回来
swap(*pChar, *pPostion);
}
}
}
int main()
{
char test[] = "132";
Permutation(test, test);
cout << endl;
// 用STL输出全排列
// 注意:必须要保证数组顺序,从小到大
do
{
cout << test[0] << test[1] << test[2] << endl;
} while (next_permutation(test, test + 3));
cout << endl;
char test2[] = "321";
// 注意:必须要保证数组顺序,从大到小
do
{
cout << test2[0] << test2[1] << test2[2] << endl;
} while (prev_permutation(test2, test2 + 3));
return 0;
}
迭代器是一种smart pointer,用于访问顺序容器和关联容器中的元素,相当于容器和操纵容器的算法之间的中介。
迭代器按照定义方式分成以下四种:
int main()
{
list<int> v;
v.push_back(3);
v.push_back(4);
v.push_front(2);
v.push_front(1); // 1, 2, 3, 4
list<int>::const_iterator it;
for (it = v.begin(); it != v.end(); it++)
{
//*it += 1;
cout << *it << " ";
}
cout << endl;
// 注意:迭代器不支持<
//for (it = v.begin(); it < v.end(); it++)
//{
// cout << *it << " ";
//}
cout <<v.front() << endl;
v.pop_front(); // 从顶部去除
list<int>::reverse_iterator it2;
for (it2 = v.rbegin(); it2 != v.rend(); it2++)
{
*it2 += 1;
cout << *it2 << " "; // 5 4 3
}
cout << endl;
return 0;
}
#include<stack>//定义栈所需的头文件
using namespace std;
stack<int> s;//定义一个元素为int型的栈
int a=10;
s.push(a);//将a入栈
s.pop();//出栈一个元素
s.empty();//返回栈是否为空
s.size();//返回栈的大小
s.top();//返回栈顶元素
#include<queue>//定义队列所需的头文件
using namespace std;
queue<int> s;//定义一个元素为int型的栈
int a=10;
q.push(a);//将a队尾插入一个元素
q.pop();//删除队头的元素
q.empty();//返回队列是否为空,是的话返回1,不是返回0
q.size();//返回队列的大小
a=q.front();//返回队首元素
a=q.back();//返回队尾元素
priority_queue<int> pq; // 默认是最大值优先
//priority_queue<int, vector<int>, less<int> > pq2; // 最大值优先
//priority_queue<int, vector<int>, greater<int> > pq3; // 最小值优先
pq.push(2);
pq.push(1);
pq.push(3);
pq.push(0);
while (!pq.empty())
{
int top = pq.top();
cout << " top is: " << top<< endl;
pq.pop();
}
cout << endl;
注:用法可参考 C++栈和队列(stack,queue,priority_queue) 。
从使用的角度来看,allocator隐藏在其他组件中默默工作,不需要关心,但是从理解STL实现角度来看,它是需要首先分析的组件。 allocator的分析可以体现C++在性能和资源管理上优化思想。
#include "jjalloc.h"
#include <vector>
using namespace std;
int main()
{
int ia[5] = { 0, 1, 2, 3, 4 };
unsigned int i;
//为vector配置自定义的空间配置器
vector<int, JJ::allocator<int> > iv(ia, ia + 5);
for (i = 0; i < iv.size(); i++)
{
cout << iv[i] << " ";
}
cout << endl;
return 0;
}
注:《STL源码剖析》侯捷,SGISTL版本的可读性较强。
Boost库是为C语言标准库提供扩展的一些C程序库的总称,由Boost社区组织开发、维护,Boost库可以与C++标准库完美共同工作,并且为其提供扩展功能。
Boost可为大致为20多个分类:字符串和文本处理库、容器库、算法库、函数对象和高阶编程库、综合类库等等。
个人认为如果C++标准库可以满足日常开发的需求,Boost库没有学习必要。
使用C++11中Thread时注意线程安全问题,可以使用mutex等锁:
#include <thread>
#include <mutex>
#include <iostream>
using namespace std;
mutex g_mutex;
void T1()
{
g_mutex.lock();
cout << "T1 Hello" << endl;
g_mutex.unlock();
}
void T2(const char* str)
{
g_mutex.lock();
cout << "T2 " << str << endl;
g_mutex.unlock();
}
int main()
{
thread t1(T1);
thread t2(T2, "Hello World");
t1.join();
//t2.join();
t2.detach();
cout << "Main Hi" << endl;
return 0;
}
join()、detach()可参考
C++11多线程join()和detach()的理解 :
互斥锁mutex可以配合lock_guard、unique_lock使用,参考 c++11中的lock_guard和unique_lock使用浅析 。
原子操作atomic的也可用于线程同步,常用于变量资源,参考 C++原子操作 atomic的使用及效率 。
thread tW1([]()
{
cout << "ThreadSwap1 " << endl;
});
thread tW2([]()
{
cout << "ThreadSwap2 " << endl;
});
cout << "ThreadSwap1' id is " << tW1.get_id() << endl;
cout << "ThreadSwap2' id is " << tW2.get_id() << endl;
cout << "Swap after:" << endl;
swap(tW1, tW2);
cout << "ThreadSwap1' id is " << tW1.get_id() << endl;
cout << "ThreadSwap2' id is " << tW2.get_id() << endl;
tW1.join();
tW2.join();
ThreadSwap1
ThreadSwap2
ThreadSwap1' id is 26136
ThreadSwap2' id is 26612
Swap after:
ThreadSwap1' id is 26612
ThreadSwap2' id is 26136
thread tM1( []() { ; } );
//tM1.join();
cout << "ThreadMove1' id is " << tM1.get_id() << endl;
cout << "Move after:" << endl;
thread tM2 = move(tM1);
cout << "ThreadMove2' id is " << tM2.get_id() << endl;
cout << "ThreadMove1' id is " << tM1.get_id() << endl;
tM2.join();
ThreadMove1' id is 17940
Move after:
ThreadMove2' id is 17940
ThreadMove1' id is 0
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://www.cnblogs.com/timefiles/p/CppStudyNotesAdvancedProgramming.html
内容来源于网络,如有侵权,请联系作者删除!