STL_API
- 容器:包含序列容器和关联容器
- 迭代器
string 容器
- string str //构造
- str.assign(“abcd”,4) //选取前四个赋值
- str.assign(“abcd”,1,3) //选取1到3的赋值
- s[100] 和 s.at(100) 区别
- += 的重载
- str.append(“abc”)
- int pos =str.find(“bc”) //返回第一次出现的位置索引,找不到返回-1
- str.replace(1,3,“111”) //从1开始3个字符的位置替换成“111”
- s1.compare(s2) //s1大于s2时返回1 ,小于返回-1,等于返回0
- string str2 = str1.**substr **(1 , 3) //子串1开始3个元素提取
- str.insert(1,“111”) //从第1个位置开始插入“111” vector中要告诉它迭代器的位置
- str.erase(1,3) //从1开始删除3个元素
- const char* p = str.c_str(); //与c风格字符串转换
- 注意:**string不能隐式转换为 char **
- s[i] = toupper( s[i] ), s[i] = tolower( s[i] )
- v.insert(v.begin(),2,100) 在一开始加入2个100
vector 容器(***)
-
动态数组、可变数组、单口容器
-
push_back() 、pop_back() 这两种指的在尾端操作,**尾插 **和 尾删
-
迭代器 v.begin()、最后一位的下一位v.end() 、v.rbegin() 、v.rend()
-
for_each() 算法的使用(遍历)
-
insert () 可以在指定位置插入元素(插入到中间时后面需要后移,这样效率不高)
-
vector 实现动态 增长原理:
当插入新元素的时候,如果空间不足,那么vector会重新申请更大的一块内存空间,将原空间数据拷贝到新空间,释放旧空间的数据,再把新元素插入到新申请空间。
-
巧用swap来收缩空间 ——vector(v).swap(v) 利用 初始化匿名对象,这个匿名的对象随着swap交换指针后,当前行运行完就释放了,完成v的空间收缩
-
reserve(int len)预留开辟len个空间,不用再随着增长多次开辟空间了
-
**v.front()**第一个元素,v.back(),最后一个元素
-
v.erase(v.begin,v.end) 全部删除 相当于 v.clear()
-
rbegin() 和 rend()
deque容器
迭代器见到:const_iterator / reverse_iterrator
- 双口容器**_包含中控器和buffer结构,**不存在空间限制
- 双端插入和删除元素效率较高
- 指定位置插入也会导致数据元素移动,降低效率
- 可以随机存取,效率高
- push_front(), pop_front(), push_back(), pop_back()
- deque d
- size/resize/empty与之前一样
- d.insert(d.begin() , d2.begin(), d2.end() ) //将d2的区间插入到d中
Stack 容器
- stack 是没有迭代器的,它不让你遍历,他是“先进后出”
- stack s
- s.push(10)
- s.top() //栈顶
- s.pop()
- s.empty()
queue 容器
- 队列——排队打饭例子,“先进先出”
- 它的头和尾是可以让你看到的,但是中间过程是不允许看到的,所以他不提供遍历功能,也就不提供迭代器
- queue q
- q.push(10)
- q.pop() //弹出
- q.front() //队头
- q.back() //队尾
- q.empty()
list 容器(**)
-
双向循环链表
-
对于任何位置的插入是常数时间, list 迭代器是不支持随机访问的
-
迭代器可见:Bidirectional_iterator / const_iterator / reverse_iterator(逆向)
-
listL
-
L.push_back(10) //将10插入尾部
-
L.push_front(10) //将10插入头部
-
L.pop_front(10)
-
L.pop_back(10)
-
L.front()
-
L.back()
-
L.insert(L.begin(),1000) //插入1000
-
L.clear()
-
L.erase(beg,end)
-
L.remove(10) //删除容器中所有与 elem 值匹配的元素
-
L.size()
-
L.resize(10)
-
L.empty()
-
L.reverse() //反转
-
注意:sort( L.begin() , L.end() ) //不能这样,所有不支持随机访问的迭代器,不可以用系统提供的算法
-
L.sort() //从小到大 如果需要从大到小的需求,择需要指定排序规则L.sort(规则函数)
-
L.remove(对象名) //删除自定义数据类型,从源码的角度看可以重载“==”
set/multiset 容器
-
set 里面自动排序(从小到大),不允许有重复的值,不允许通过迭代器修改set元素的值
-
multiset 允许重复(键值重复),他和set的底层实现是红黑树
-
set s1
-
s1.insert(10) //只能这么插入
-
clear / empty / erase(迭代器或者值 ) / size
-
对于set来说,key就是value
-
set::iterator pos = s1.find(3) //找到返回迭代器,没找到返回s1.end()
-
s1.count(1) //查找 key 的元素的个数,有的话返回1,没有返回0(因为set中没有重复元素)
-
set::iterator it = s1.lower_bound(3) //返回第一个key>=3的元素的迭代器,没找到就返回s1.end()
-
set::iterator it2 = s1.upper_bound(3) //返回第一个key>3的元素的迭代器,没找到就返回s1.end()
-
pair< set::iterator, set::iterator > ret = s1.equal_range(3) //返回容器中key与 3 相等的上下限的两个迭代器,上下限就是lower_bound 与 upper_bound 获取第一个值就 ret.first
-
pair<string , int > p(string(“Tom”),100) //创建对组(不需要引用任何头文件)-
-
pair<string , int > p = make_pair(“Jerry”, 200)
-
set在使用 insert 插入时,返回的是一个pair对组 <迭代器,是否成功标识>,multiset允许插入重复值
-
对于使用仿函数来改变set容器里面默认从小到大排序的规则
-
在 set里面存储自定义数据类型,一上来就要指定好数据类型
map / multimap 容器
-
map 所有的元素都是pair,但是 map 不允许有相同的 key 值
-
multimap 与 map 的区别是它的 key 值是可以重复的
-
map<int,int> m
-
m.insert(pair<int,int>(1,10))
-
m.insert(make_pair(2,20)) //推荐
-
m.insert(map<int,int> :: value_type(3,30)) //不推荐
-
m[1] = 10 //尽量 保证这个key存在
-
swap / size / empty / clear / erase(迭代器,键值,区间,都可以)
-
m.find(key) //找到返回迭代器,找不到返回m.end()
-
m.count(3)
-
map<int,int>::iterator ret = m.lower_bound(3)
-
map<int,int>::iterator ret = m.upper_bound(3)
-
pair< map<int,int>::iterator , map<int,int>::iterator > p1 = m.equal_range(3)
-
指定map的默认排序规则
函数对象(仿函数)
-
是一个类,不是一个函数
-
可以储存属性,即可以有自己的状态(例如调用次数)
-
函数对象可以作为参数进行传递
-
重载“()”
-
作为类型,与模板进行配合使用
谓词
-
普通函数或者重载的operator()返回值是bool类型的函数对象(仿函数),根据参数的数量分为一元谓词和二元谓词
-
find_if(v.begin() , v.end() , _pr_pred(仿函数)) //返回迭代器
-
lambda表达式的形式
内建 函数对象(仿函数)
-
negate n --cout<< n(10) //取反
-
plusp – cout<< p(1,1) //加法
-
sort( v.begin() , v.end() , **greater() **) //匿名对象,记得包含 #include此外,还有 less()
-
for_each(v.begin(),v.end(),[](int val){cout << val << “”}) //lambda,后面如果是函数就用函数名,如果是仿函数就用函数对象
适配器的使用
普通适配器
-
bind2nd(MyPrint(),num) //绑定数据-
-
class MyPrint:public binary_function<参数类型1 , 参数类型2 , 返回值> //继承
-
加const修饰operator()
取反适配器
-
not1(函数对象) //表示取反——一元取反适配器,继承unary_function<参数类型1.返回值类型>
-
高端一点:auto pos = find_if(v.begin() , v.end() , not1( bind2nd(greater() , 5) ) )
-
sort(v.begin() , v.end() , not2(less() ) )
函数指针适配器——将函数指针适配为函数对象
-
for_each(v.begin(), v.end(), bin2nd( ptr_fun(MyPrint相当于普通函数指针),100 )) ** //相当于将普通函数指针适配成函数对象**了
成员函数适配器
-
for_each( v.begin(), v.end(), mem_fun_ref(&Person::showPerson )) //成员函数的适配mem_fun_ref
常用遍历算法
-
for_each(beg , end , _callback) //__callback可以使普通函数也可以是仿函数
-
for_each 是有返回值的,返回的是与_callback类型一样的对象,这个对象里面可以存储属性
-
for_each 可以绑定参数进行输出,for_each( v.begin() , v.end() , bind2nd( myPrint(), 10000 ) ),记住在使用bind2nd时需要引入#include头文件
-
transform( v.begin() , v.end() , vTarget.begin() , 仿函数 ) // **搬运 **功能,注意使用前要给 vTarget 对象分配内存——vTarget.resize(v.size() )
-
transform另一个用法,那么将两个容器搬运到一个目标容器:transform( v1.begin() , v1.end() , v2.begin() , vTarget.begin() , 仿函数 )
常用查找算法
- find(v.begin() , v.end() , 5) //返回迭代器,找不到返回v.end()
- find查找自定义数据类型,v.find(v.begin() , v.end() , p1) ,需要重载“==”,返回仍然是迭代器
- find_if
- adjacent_find(v.begin() , v.end() ) //返回迭代器,两个重复的元素,返回第一个迭代器
- binary_search(v.begin() , v.end() , 4) //返回布尔值
- count(v.begin() , v.end() , 4 ) //返回 int
- count_if(v.begin() , v.end() , 仿函数)
常用排序算法
-
merge(v1.begin() , v1.end() , v2.begin() , v2.end() , vTarget.begin()) //两个有序容器合并,记得要给vTarget 开辟空间
-
sort(v.begin() , v.end() , 可以选择补充的条件(仿函数),不补充也可以,默认从小到大)
-
random_shuffle(beg , end) //洗牌,需要在main里面设置随机种子,srand(unsigned int)time(NULL)
-
reverse(v.begin() , v.end()) //翻转
常用拷贝和替换算法
- copy(v.begin() , v.end() , vTarget.begin() )
- copy高端操作,copy(vTarget.begin() , vTarget.end() , ostream_iterator(cout , " ")) //等于是把对象数据复制到流对象里,其实就是用copy来实现对象的元素数据的输出操作,这种方式不能换行,记住就行
- replace(v.begin() , v.end() , 3 ,300) //将 3 替换为 300,输出的时候我们又可以像上一点那样,copy(v.begin() ,v.end(), ostream_iterator(cout," ")),记得包含头文件#include
- replace_if(v.begin(), v.end() , MyCopare() , 300) //MyCopare()是一个匿名对象(仿函数),满足条件的替换成300,同样输出可用copy(v.begin(),v.end(),ostream_iterater(cout," ") )
- swap(v1 , v2)
常用算数生成算法
- accumulate(v.begin() , v.end() , 0 ) //它的头文件要运用**#include ,** 返回值int,这里的0,是一个起始累加值
- fill(v.begin() , v.end() ,101) //填充101
常用集合算法
-
get_intersection(v1.begin() ,v1.end(), v2.begin(), v2.end() , vTarget.begin()) //交集,返回值是vTarget最后一个元素的迭代器,之前要有vTarget.resize(min(v1.size(),v2.size()))分配空间,copy(vTarget.begin() , 上面返回的结果itEnd , ostream_iterator(cout , " "))
-
set_union(v1.begin() ,v1.end(), v2.begin(), v2.end() , vTarget.begin()) //并集
-
set_difference(v1.begin() ,v1.end(), v2.begin(), v2.end() , vTarget.begin()) //v1差v2
//综合案例
#include<iostream>
using namespace std;
#include<vector>
#include<map>
#include<string>
#include<algorithm>
#include<deque>
#include<numeric>
#include<functional>
class Speaker
{
public:
string m_Name; //name
int m_Score[3];
};
void createSpeaker(vector<int>& v, map<int,Speaker>& m)
{
string nameSeed = "ABCDEFGHIJKLMNOPQRSTUVWX";
for (int i = 0; i < nameSeed.size(); i++)
{
string name = "选手";
name += nameSeed[i];
Speaker sp;
sp.m_Name = name;
for (int j = 0; j < 3; j++)
{
sp.m_Score[j] = 0;
}
v.push_back(i + 100);
m.insert(make_pair(i + 100, sp));
}
}
void speechDraw(vector<int>& v)
{
random_shuffle(v.begin(), v.end());
}
void speechContest(int index, vector<int>& v1, map<int, Speaker>& m, vector<int>& v2)
{
multimap<int, int, greater<int>> groupMap;
int num = 0;
for (auto it = v1.begin(); it != v1.end(); it++)
{
num++;
deque<int>d;
for (int i = 0; i < 10; i++)
{
int socre = rand() % 41 + 60;
d.push_back(socre);
}
sort(d.begin(), d.end());
d.pop_back();
d.pop_front();
int sum = accumulate(d.begin(), d.end(), 0);
int avg = sum / d.size();
m[*(it)].m_Score[index - 1] = avg;
groupMap.insert(make_pair(avg, *it));
if (num % 6 == 0)
{
/*
cout << "小组比赛成绩" << endl;
for (auto mit = groupMap.begin(); mit != groupMap.end(); mit++)
{
cout << "编号: " << mit->second << "姓名: " << m[mit->second].m_Name << "得分: " << m[mit->second].m_Score[index - 1] << endl;
}
*/
int count = 0;
for (multimap<int, int, greater<int>>::iterator mit = groupMap.begin(); \
mit != groupMap.end(), count < 3; mit++,count++)
{
v2.push_back(mit->second);
}
groupMap.clear();
}
}
}
void showScore(int index, vector<int>& v, map<int, Speaker>& m)
{
cout << "第" << index << "轮,比赛成绩如下:" << endl;
for (auto it = m.begin(); it != m.end(); it++)
{
cout << "选手编号: " << it->first << "\t" << "姓名: " << it->second.m_Name << "\t" << "分数: "\
<< it->second.m_Score[index - 1] << endl;
}
cout << "晋级选手编号: " << endl;
for (auto it = v.begin(); it != v.end(); it++)
{
cout << *it << endl;
}
}
int main()
{
vector<int>v1;
map<int, Speaker>m;
createSpeaker(v1,m);
//测试
for (map<int, Speaker>::iterator it = m.begin(); it != m.end(); it++)
{
cout << "编号:" << (*it).first << "\t" << "姓名:" << (*it).second.m_Name << "\t" << "得分:" << it->second.m_Score[0] << endl;
}
speechDraw(v1);//抽签
vector<int>v2;
speechContest(1, v1, m, v2);
//显示比赛结果
showScore(1, v2, m);
//第二轮比赛
speechDraw(v2);
vector<int>v3;
speechContest(2, v2, m, v3);
showScore(2, v3, m);
//第三轮比赛
speechDraw(v3);
vector<int>v4;
speechContest(3, v3, m, v4);
showScore(3, v4, m);
return 0;
}
贪吃蛇
-
墙模块
- 二维数组维护
- 初始化二维数组
- 画出墙壁
- 提供对外接口setwall和getwall
-
蛇模块
- 初始化蛇
- 销毁所有节点
- 添加新节点
-
食物模块
- foodX foodY
- setFood 对外接口,随机设置食物