先前参加了蓝桥杯的省赛,侥幸进入了国赛,本来是准备全心考研,但又多了这么一次机会,那就好好准备吧。此前对于算法,我一直都是用纯C来编写。经过辅导老师点拨,国赛时纯C的算法很大可能会超时,所以为了能取得好成绩,还是了解一下吧。
一,STL的组成部分
1).容器(containers):是一种数据结构容器,使用类模板的方法提供,我们可以方便的进行数据的存储操作
2).适配器(adapters):以序列式容器为基础,提供的栈,队列和优先级队列的这种容器
3).迭代器(iterator):类似于指针,用来操作容器的元素
4).算法(algorithm):包含一系列常见的算法
5).空间适配器(allocator):其中的主要工作包括两部分:1,对象的创建和销毁。2,内存的创建与释放
6).仿函数(function):仿函数又称为函数对象,其实就是好重载了()操作符的struct,没有什么特别的地方
二,STL的容器
1,序列式容器
1).每个元素都有固定的位置,取决于插入时机和地点。与元素值无关。
2).vector(向量):底层数据结构是数组,可以随机存取数据元素(用索引直接存取),数组的尾部添加和移除元素很快,但在头部和中部插入元素比较耗时。
//vector容器简单用法
//输入
#include <iostream>
#include <vector>
#include <stdio.h>
using namespace std;
int main(void)
{
//vector(动态数组)有内存管理的机制,
//也就是说对于插入和删除,vector可以动态调整所占用的内存空间。
vector<int> tmp;
for(int i=0;i<10;i++)
{
tmp.push_back(i);
}
//获得tmp的迭代器it,it初始化为tmp的开头,遍历到tmp的结尾
for(vector<int>::iterator it = tmp.begin();it!=tmp.end();it++)
{
cout<<*it<<" "; //对迭代器it进行解引用
}
return 0;
}
#include <iostream>
#include <vector>
#include <algorithm>
#include <ctime>
using namespace std;
void print(vector<int> tmp);
bool comp(const int &a,const int &b)
{
return a>b;
}
int main(void)
{
vector<int> tmp;
for(int i=0;i<10;i++)
{
tmp.push_back(rand()%100);
}
print(tmp);
//颠倒
reverse(tmp.begin(),tmp.end());
print(tmp);
//默认升序
sort(tmp.begin(),tmp.end());
print(tmp);
//降序
sort(tmp.begin(),tmp.end(),comp);
print(tmp);
return 0;
}
void print(vector<int> tmp)
{
for(vector<int>::iterator it = tmp.begin();it!=tmp.end();it++)
{
cout<<*it<<" ";
}
cout<<endl;
}
3).deque(双端队列):底层数据结构是数组,可以随机存取数据元素,在数组的头部和尾部插入和删除元素很快。
/*
deque和vector一样,采用线性表,与vector唯一不同的是,deque采用的分块的线性存储结构,
每块大小一般为512字节,称为一个deque块,所有的deque块使用一个Map块进行管理,
每个map数据项记录各个deque块的首地址,这样以来,deque块在头部和尾部都可已插入和删除元素,
而不需要移动其它元素。使用push_back()方法在尾部插入元素,使用push_front()方法在首部插入元素,
使用insert()方法在中间插入元素。
*/
#include <iostream>
#include <deque>
using namespace std;
int main(void)
{
deque<int> tmp;
for(int i=0;i<10;i++)
{
if(i%2==0) tmp.push_front(i);
else tmp.push_back(i);
}
tmp.insert(tmp.begin+4,101); //用insert从中间插入
//可以使用下标遍历,此处使用迭代器
for(deque<int>::iterator it = tmp.begin();it!=tmp.end();it++)
cout<<*it<<" ";
return 0;
}
4).list(列表):底层数据结构是双向链表,不提供随机存取数据元素(需要按顺序走到要存取的元素),在任何位置插入和删除都很快,只需要移动一下指针。
#include <iostream>
#include <list>
using namespace std;
int main(void)
{
list<int> tmp;
tmp.push_back(5);
tmp.push_front(2);
tmp.push_back(2);
tmp.push_front(32);
tmp.push_back(6);
tmp.push_front(7);
tmp.push_back(0);
tmp.push_front(1);
for(list<int>::iterator it = tmp.begin();it!=tmp.end();it++)
cout<<*it<<" ";
cout<<endl;
//排序
tmp.sort();
for(list<int>::iterator it = tmp.begin();it!=tmp.end();it++)
cout<<*it<<" ";
cout<<endl;
//排除重复的(得先排序)
tmp.unique();
for(list<int>::iterator it = tmp.begin();it!=tmp.end();it++)
cout<<*it<<" ";
cout<<endl;
return 0;
}
2,关联式容器
1).元素位置取决于特定的排序准则,和插入的顺序无关,底层数据结构是二叉树。
2).set(集合):内部元素依据其值自动排序,set内相同的数值元素只能出现一次。
/*
set是用红黑树的平衡二叉索引树的数据结构来实现的,插入时,它会自动调节二叉树排列,
把元素放到适合的位置,确保每个子树根节点的键值大于左子树所有的值、小于右子树所有的值,
插入重复数据时会忽略。set迭代器采用中序遍历,检索效率高于vector、deque、list,
并且会将元素按照升序的序列遍历。set容器中的数值,一经更改,set会根据新值旋转二叉树,
以保证平衡,构建set就是为了快速检索
multiset,multiset与set的不同之处就是key可以重复,
以及erase(key)的时候会删除multiset里面所有的key并且返回删除的个数。
*/
#include <iostream>
#include <set>
using namespace std;
struct Comp{ //自定义比较函数(元素本身不是结构体)
bool operator()(const int &a,const int &b)
{
return a>b;
}
};
int main(void)
{
set<int> tmp;
tmp.insert(5);
tmp.insert(6);
tmp.insert(1);
tmp.insert(3);
tmp.insert(4);
tmp.insert(2);
tmp.insert(6);
//自动升序
for(set<int>::iterator it = tmp.begin();it!=tmp.end();it++)
{
cout<<*it<<" ";
}
cout<<endl;
//降序遍历
for(set<int>::reverse_iterator it = tmp.rbegin();it!=tmp.rend();it++)
{
cout<<*it<<" ";
}
cout<<endl;
set<int,Comp> tmpC;
tmpC.insert(5);
tmpC.insert(6);
tmpC.insert(1);
tmpC.insert(3);
tmpC.insert(4);
tmpC.insert(2);
tmpC.insert(6);
//自定义比较函数,降序
for(set<int,Comp>::iterator it = tmpC.begin();it!=tmpC.end();it++)
{
cout<<*it<<" ";
}
cout<<endl;
return 0;
}
3).multiset(多重集合):内部元素依据其值自动排序,set内可以出现重复的元素。
4).map(映射):map的元素是成对的键值对,内部元素的值依据键自动排序,键只可以出现一次
/*
map也是使用红黑树,他是一个键值对(key:value映射),便利时依然默认按照key程序的方式遍历,同set。
*/
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main(void)
{
map<string,double> tmp;
tmp["A"] = 12.5;
tmp["B"] = 35.2;
tmp["D"] = 45.2;
tmp["C"] = 452.1; //遍历时,按照键排序输出
for(map<string,double>::iterator it = tmp.begin(); it != tmp.end(); ++it)
{
cout<<(*it).first<<"->"<<(*it).second<<endl;
}
return 0;
}
三,STL的适配器
1),什么是适配器
STL提供了三种适配器stack,queue和priority_queue。这些适配器是包装了序列式容器(vector,deque,list)中的一种。
因此所谓的适配器就是序列式容器的包装器,注意:适配器没有提供迭代器。
2).stack(栈)
栈可以使用序列式容器中的vector,deque,list中的任意一种作为其底层的数据结构。默认是使用deque来实现的stack。
#include <iostream>
#include <stack>
using namespace std;
int main(void)
{
stack<int> tmp;
tmp.push(2);
tmp.push(1);
tmp.push(3);
tmp.push(4);
tmp.push(5);
tmp.push(28);
tmp.push(7);
cout<<"size is:"<<tmp.size()<<endl;
while(!tmp.empty()) //栈不为空 ,适配器没有迭代器
{
cout<<tmp.top()<<" ";
tmp.pop(); //移除栈顶元素
}
return 0;
}
3).queue(队列)
队列可以使用deque和list中的任意一种作为其底层的数据结构。默认是使用deque来实现的queue。
4).priority_queue(优先队列)
优先队列也是一种队列,不过在进入队列之后会对元素进行排序,可以使用vector和deque来实现其底层结构,默认是使用
vector来实现priority_queue。
#include <iostream>
#include <queue>
using namespace std;
int main(void)
{
priority_queue<int> tmp;
tmp.push(1);
tmp.push(3);
tmp.push(2);
tmp.push(8);
tmp.push(9);
tmp.push(0);
cout << "size: " << tmp.size() << endl;
while(!tmp.empty())//如果优先队列为空,则返回真
{
cout << tmp.top()<<" "; //返回优先队列中有最高优先级的元素
tmp.pop(); //删除第一个元素
}
return 0;
}
5).序列式容器和适配器比较