- 简述: C++标准库中的代码几乎都是使用泛型编程(GP),而所谓的泛型编程:就是使用tmeplate为主要工具来编写程序。
C++标准库( C++ standard library )
对于STL标准模板库而言,standard template library标准库以hearderfile形式呈现,所以可以看到其内容。对于C++标准库:
1).C++变准哭的hearder files 不带副档名(.h),例如#include
2) .新式C hearder files 不带副档名(.h),例如#include
3) .旧式 C hearder files(带有副档名 .h )任然可用,例如:#include<stdio.h>。
新式hearders 内的组件封装在namespace “std”中使用时通过using namespace std;或using std::cout这种形式;对于旧式hearders 内的组件不封装于 namespace “std“中。
下面给大家推荐几个学习C++的网站,可以用于C++stl库的查询:www.cplusplus.com;www.cppReference.com;gcc.gnu.org.
- STL的六大部件(components)
STL的六大部件包括:容器(Containers)、分配器(Allocators)、算法(Algorithms)、迭代器(Iterators)、适配器(Adapters)、仿函数(Functions)如下图所示:
从图中可以看出容器是需要有分配器来支持的,从而帮容器分配内存,而迭代器它实际上是相当于一种泛化的指针,通过下面简单的一小段程序来简要的说明一个这六大部件。
#include<iostream>
#include<vector>
#include<functional>
#include<algorithm>
#include<iterator>
using namespace std;
int main()
{
int ai[] = { 1, 23, 43, 13, 56, 75, 66, 98, 14,23,23 };
vector<int, allocator<int>>vi(ai, ai + 11);
cout << count_if(vi.begin(),vi.end(),bind2nd(less<int>(),40)) << endl;//小于40的个数
cout << count_if(vi.begin(), vi.end(), not1(bind2nd(less<int>(), 40))) << endl;//大于等于40的元素个数
return 0;
}
上面的一小段程序包括了所说的六大部件:
使用了容器 vector,然后通过分配器allocator来给容器vector分配内存,而count_if()是算法表示如果满足条件则计数,vi.begin()和vi.end()则使用了迭代器,not1为函数适配器(function adaptor),bind2nh表示绑定第二参数(也是函数适配器的一种),最后的less()则为比大小的函数。这段程序运行的结果如下所示:
输出小于40的有6个数,大于40的有5个数。
谈到了算法,谈到了容器,免不了会想到使用户哪一个,哪一个效率高,取决与数据的特性,根据特性选择适当的容器,这里面会牵扯到复杂度的问题(complexity,Big-oh)
目前常见的Big-oh有下列几种形式:
而刚才我们说到的使用哪一个,哪一个效率高的问题,以及本文的标题为几种容器的测试,那么接下来我们主要来说一下C++标准库中的几种容器,
通过上图可以看出,在C++中的容器主要有两大类:sequence containers和associative containers两种,而unordered containers也是属于associative containers的一种。图中的“->”、“<-”代表指针。存内存的角度来说,vector容器的扩充是通过分配器进行扩充的,而Deque的扩充是一段一段的进行,链表list有两个指针,分别指向上一个和下一个结点,而Forward list这是一个单向的链表,每个结点只有一个指针并且其指向下一个结点,而不能指向上一个结点,同时list比Forward list要占内存,list都是通过指针串起来的,且每个元素带有两个指针。同时他们都属于sequence containers。
那么如果我们的需求是要进行大量的查找的话,更多的时候Associative containers 的效率会比sequence containers的效率要高,对于关联型容器有:Set\MultiSet\Map\MultiMap然而对于set而言他的数据成员中key就是value,value就是key,而Map它的key和value是分开的(对于Map而言,它的一个数据成员由一个key和一个value组成);通常我们还会使用到哈希表(Harshtable)这种unordered containers也属于一种Associative containers它有unordered set\MultiSet、unordered Map\MultiMap。
**注意:**如果选择的是Set,表示放的元素不能重复;如果选择的是Map,表示元素的key不能重复;但是如果选择的是MultiSet或者MultiMap的话则MultiSet的元素是可以重复的、MultiMap的key(键值)也是可以重复的。
了解了又哪些容器之后,接下来我们来对这几种容器分别通过代码来进行分析,程序通过查找某一个long型元素long get_a_target_long(),或者string型字符串来进行测试。下面的代码为在一个命名空间中定义需要获取的long型元素函数、需要获取string型的元素函数、对long型元素进行大小比较的函数 int comparelongs(const void * a,const void *b)、对string型字符串进行大小比较的函数int comparestrings(const void * a, const void * b)…
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#define snprintf _snprintf
using namespace std;
namespace exp1{
long get_a_target_long()
{
long target = 0;
cout << "target(0~" << RAND_MAX << ") ";
cin >> target;
return target;
}
string get_a_target_string()
{
long target = 0;
char buf[10];
cout << "target string(0~ " << RAND_MAX << ") ";
cin >> target;
snprintf(buf, 10, "%", target);//将 long 型的对象target 转化成字符串
return string(buf);
}
int comparelongs(const void * a,const void *b)
{
if (*(long *)a > *(long *)b)
return 1;
else if (*(long *)a < *(long *)b)
return -1;
else
return 0;
//return (*(long *)a-*(long *)b);
}
int comparestrings(const void * a, const void * b)
{
if (*(string *)a>*(string *)b)
return 1;
else if (*(string *)a < *(string *)b)
return -1;
else 0;
}
}
上述程序中* (long *)a的意思为将指针a转化成long型指针,然后再取它的地址。
- Array数组的测试程序:
#include<array>
#include<cstdio>
#include<cstdlib>
#include<ctime>
using namespace std;
namespace test_array{
const long ASIZE = 1000000;
void test_array()
{
cout << "\n test_array()......\n";
array<long, ASIZE>c;
clock_t timestate = clock();
long target =exp1:: get_a_target_long();
srand((int)time(NULL));//随机数种子
for (long i = 0; i < ASIZE; i++)
{
c[i] = rand();
}
//打印出数组的相关信息
cout << "milli-seconds of rand array c : " << (clock() - timestate) << endl;
cout << "array.front() = " << c.front() << endl;
cout << "array.back() = " << c.back() << endl;
cout << "array.size() = " << c.size() << endl;
cout << "array.data() = " << c.data() << endl;
timestate = clock();
::qsort(c.data(),ASIZE,sizeof(long),exp1::comparelongs);//快速排序
long * PItem = (long *)bsearch(&target,c.data(),ASIZE,sizeof(long),exp1::comparelongs);
cout << "qsort()+bsearch(),milli-seconds : " << (clock() - timestate) << endl;
if (PItem != NULL)
cout << "found : " << *PItem << endl;
else
cout << "not found!" << endl;
}
}
int main()
{
test_array::test_array();
system("pause");
return 0;
}
测试结果如下:
其中bsearch为二分查找法,注意在使用二分查找法之前需要排好序,qsort()为快速排序法。测试的结果123为通过控制台输入的需要查找的字符串“123”,程序从开始到现在用时27856ms,数组的第一个元素为11186,数组的最后一个元素为24423,数组的长度为10万,数组的首地址为0173DE20,通过快速排序法后进行二分法查找字符串123用时121ms。
- vector容器的测试程序:
#include<iostream>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<string>
#include<ctime>
using namespace std;
namespace test_vector{
void test_vector(long & value){
cout << "\n test_vector()........\n" << endl;
vector<string>s;
char buf[10];
clock_t timestate = clock();
srand((int)time(NULL));//随机数种子
for (long i = 0; i < value; i++){
try{
snprintf(buf, 10, "%d", rand());//将随机生成的 long 型数据变成 string 类型的字符串
//将每一个字符串 压入 s 中
s.push_back(string(buf));//在尾部增加一个数据
}
/*************************************************************************************************/
catch (exception & p){//捕获并处理异常
cout << "i = " << i << " " << p.what() << endl;
/*如果new杂调用分配器分配存储空间时出现错误(错误信息被保存了一下),就会catch到
一个bad_alloc 类型的异常,其中的what()函数,就是提取这个错误的基本信息,*/
abort();//程序终止
}
}
cout << "milli-seconds of rand vector s : " << (clock() - timestate) << endl;
cout << "vector s.size() = " << s.size() << endl;
cout <<"vector s.front() = " << s.front() << endl;
cout << "vector s.back() = " << s.back() << endl;
cout << "vector s.max_size() = " << s.max_size() << endl;//得到vector最大可能是多少
cout << "vector s.data() = " << s.data() << endl;//传回数组在内存里面的起点的地址
cout << "vector s.capacity() = " << s.capacity() << endl;//capacity 表示当前vector分配的大小
string target = exp1::get_a_target_string();
{//测试循序查找法 fine 的效率
timestate = clock();
auto PItem = ::find(s.begin(), s.end(), target);//循序查找法,找target
cout << "::find milli-seconds : " << (clock() - timestate) << endl;
if (PItem != s.end())
cout << "found the vector target: " << *PItem << endl;
else
cout << "not found vector target!" << endl;
}
//使用二分法进行查找需要的时间与循序查找法进行对比,但是需要注意的是,使用二分法查找时
//首先需要对其进行排序,然后才能 bsearch .
{
timestate = clock();
sort(s.begin(), s.end());/*************** 注意算法调用时他的参数个数 *****************/
string * PItem = (string *)::bsearch(&target,s.data(),value,sizeof(string),exp1::comparestrings);
cout << "sort()+bsearch(),milli-seconds : " << (clock() - timestate) << endl;
if (PItem!=NULL)
cout << "found the vector target: " << *PItem << endl;
else
cout << "not found vector target!" << endl;
}
}
}
int main()
{
long value =500000;
test_vector::test_vector(value);
system("pause");
return 0;
}
测试结果如下:
随机生成50万个元素,然后再50万个元素中分别使用::find()以及bsearch()进行查找123字符串。
**注意:**1.在写测试程序的时候,将每一个小的测试程序放在一个namespace中,每个namespace中的任何定义,任何变量不会与其他namespace相冲突,而且在每个namespace的上头会有这个namespace所需要的头文件,头文件可以重复#include,因为其自身有保护机制(#ifndef…#define…#endif).
**注意:**2.变量的申明在写正规程序的时候放在程序的开始。
**注意:**3.vector的空间时两倍增长的,当放第一个元素时它占用的内存空间是1,再加上一个元素后占用的内存空间时2;此时若是再加上一个元素后,它此时的内存占用空间不是3而是4,因为他的内存空间的增长是两倍两倍的增长的。
**注意:**4.在上述的程序大家会看到使用可try…catch…的写法,这样的话程序执行到这一块后如果发生了异常则会终止程序abort()。
- list容器的测试程序
#include<iostream>
#include<ctime>
#include<cstdio>
#include<cstdlib>
#include<list>
#include<algorithm>
using namespace std;
namespace test_list{
void test_list(long & value)
{
cout << "\n test_list()......\n" << endl;
list<string>l;
char buf[10];
clock_t timestate = clock();
srand((int)time(NULL));
for (long i = 0; i < value; i++){
try{
snprintf(buf,10,"%d",rand());
l.push_back(string(buf));
}
catch (exception & p){
cout << "i = " << i <<" "<< p.what() << endl;
abort();
}
}
cout << "milli-seconds of rand list l : " << (clock() - timestate) << endl;
cout << "list l.size() = " << l.size() << endl;
cout << "list l.max_size() = " << l.max_size() << endl;
cout << "list l.front() = " << l.front() << endl;
cout << "list l.back() = " << l.back() << endl;
//上述程序已经生成了 value 个元素的链表
string target = exp1::get_a_target_string();
{
timestate = clock();
auto PItem = ::find(l.begin(), l.end(), target);
cout << "::find the list target milli-seconds : " << (clock() - timestate) << endl;
if (PItem != l.end())
cout << "found the list target : " << *PItem << endl;
else
cout << "not found the list " << endl;
}
timestate = clock();
l.sort();
cout << "the list of the l.sort(),milli-seconds : " << (clock() - timestate)<<endl;
}
}
int main()
{
long value =500000;
test_list::test_list(value);
system("pause");
return 0;
}
- forward_list容器的测试程序
#include<iostream>
#include<ctime>
#include<cstdlib>
#include<cstdio>
#include<forward_list>
using namespace std;
namespace test_forward_list{
void test_forward_list(long & value)
{
cout << "\n test_forward_list()........\n" << endl;
char buf[10];
forward_list<string>f;
clock_t timestate = clock();
srand((int)time(NULL));
for (long i = 0; i < value; i++){
try{
snprintf(buf, 10, "%d", rand());
f.push_front(string(buf));
}
catch (exception & p){
cout << "i = " << i << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds of rand froward_list f : " << (clock() - timestate) << endl;
cout << "froward_list f..max_size() = " << f.max_size() << endl;
cout << "froward_list f.front() = " << f.front() << endl;
string target = exp1::get_a_target_string();
{
timestate = clock();
auto PItem = ::find(f.begin(), f.end(), target);
cout << "::find the forward_list target milli-seconds : " << (clock() - timestate) << endl;
if (PItem != f.end())
cout << "found the forward_list target : " << *PItem << endl;
else
cout << "not found the forward_list " << endl;
}
timestate = clock();
f.sort();
cout << "the forward_list of the f.sort(),milli-seconds : " << (clock() - timestate) << endl;
}
}
int main()
{
long value =500000;
test_forward_list::test_forward_list(value);
system("pause");
return 0;
}
- deque容器的测试程序
#include<iostream>
#include<ctime>
#include<cstdlib>
#include<cstdio>
#include<deque>
using namespace std;
namespace test_deque{
void test_deque(long & value)
{
cout << "\n test_deque()........\n" << endl;
char buf[10];
deque<string>d;
clock_t timestate = clock();
srand((int)time(NULL));
for (long i = 0; i < value; i++){
try{
snprintf(buf, 10, "%d", rand());
d.push_front(string(buf));
}
catch (exception & p){
cout << "i = " << i << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds of rand test_deque f : " << (clock() - timestate) << endl;
cout << "test_deque d.max_size() = " << d.max_size() << endl;
cout << "test_deque d.front() = " << d.front() << endl;
string target = exp1::get_a_target_string();
{
timestate = clock();
auto PItem = ::find(d.begin(), d.end(), target);
cout << "::find the test_deque target milli-seconds : " << (clock() - timestate) << endl;
if (PItem != d.end())
cout << "found the test_deque target : " << *PItem << endl;
else
cout << "not found the test_deque " << endl;
}
}
}
int main()
{
long value =500000;
test_deque::test_deque(value);
system("pause");
return 0;
}
- stack栈的测试程序
#include<iostream>
#include<ctime>
#include<cstdlib>
#include<cstdio>
#include<stack>
using namespace std;
namespace test_stack{
void test_stack(long & value)
{
cout << "\n test_stack()........\n" << endl;
char buf[10];
stack<string>st;
clock_t timestate = clock();
srand((int)time(NULL));
for (long i = 0; i < value; i++){
try{
snprintf(buf, 10, "%d", rand());
st.push(string(buf));
}
catch (exception & p){
cout << "i = " << i << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds of rand test_stack st : " << (clock() - timestate) << endl;
cout << "test_stack st.size() = " << st.size() << endl;
cout << "test_stack st.top() = " << st.top()<<endl;
st.pop();
cout << "test_stack st.size() = " << st.size() << endl;
cout << "test_stack st.top() = " << st.top() << endl;
/**********************************************************************************************/
//给 stack (栈)中元素排序需要先定义一个暂时缓冲栈
//以下为给栈 st 中的元素进行排序
timestate = clock();
stack<string>Help;
while (!st.empty())
{
string Curvalue = st.top();//先将栈顶元素给一个中间字符串元素
st.pop();
while (!Help.empty() && Curvalue > Help.top())//在另外一个栈中寻找插入位置
{
st.push(Help.top());
Help.pop();
}
Help.push(Curvalue);
}
while (!Help.empty())
{
string val = Help.top();
st.push(val);
//cout << Help.top() << " ";
Help.pop();
}
cout << endl;
cout << "sort of stack,milli-seconds : " << (clock() - timestate) << endl;
/**********************************************************************************************/
}
}
int main()
{
long value =500000;
test_stack::test_stack(value);
system("pause");
return 0;
}
- queue堆的测试程序
#include<iostream>
#include<ctime>
#include<cstdlib>
#include<cstdio>
#include<queue>
using namespace std;
namespace test_queue{
void test_queue(long & value)
{
cout << "\n test_queue()........\n" << endl;
char buf[10];
queue<string>que;
clock_t timestate = clock();
srand((int)time(NULL));
for (long i = 0; i < value; i++){
try{
snprintf(buf, 10, "%d", rand());
que.push(string(buf));
}
catch (exception & p){
cout << "i = " << i << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds of the test_queue que : " << (clock() - timestate) << endl;
cout << "test_queue st.size() = " << que.size() << endl;
cout << "test_queue st.front() = " << que.front() << endl;
cout << "test_queue st.back() = " << que.back() << endl;
que.pop();
cout << "test_queue st.size() = " << que.size() << endl;
cout << "test_queue st.front() = " << que.front() << endl;
cout << "test_queue st.back() = " << que.back() << endl;
}
}
int main()
{
long value =500000;
test_queue::test_queue(value);
system("pause");
return 0;
}
上述的几个测试程序都是sequence containers类型,那么对于Associatice containers类型的容器又会如何呢?下面给出了Multiset和MultiMap类型的容器的测试程序:
- multiset容器的测试程序
/*********** ***********/
//测试associative container 的效率
/*********** ***********/
#include<iostream>
#include<ctime>
#include<set>
#include<cstdlib>
#include<cstdio>
using namespace std;
namespace test_multiset{
void test_multiset(long & value)
{
cout << "\n test_multiset().........\n";
char buf[10];
multiset<string>mu;
clock_t timestate = clock();
srand((int)time(NULL));
for (long i = 0; i < value; i++){
try{
snprintf(buf, 10, "%d", rand());
mu.insert(string(buf));//插入数据
}
catch (exception & p){
cout << "i = " << i << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds of the test_multiset mu : " << (clock() - timestate) << endl;
cout << "test_multiset mu.size() = " << mu.size() << endl;
cout << "test_multiset mu.max_size()" << mu.max_size() << endl;
string target = exp1::get_a_target_string();
{
timestate = clock();
auto PItem = ::find(mu.begin(), mu.end(), target);
cout << "tets_multiset ::find milli-seconds : " << (clock() - timestate) << endl;
if (PItem != mu.end())
cout << "test_multiset ::find the target : " << *PItem << endl;
else
cout << "test_multiset not found the target ! " << endl;
}
{
timestate = clock();
auto PItem = mu.find(target);//multiset 自身的find算法
cout << "tets_multiset find milli-seconds : " << (clock() - timestate) << endl;
if (PItem != mu.end())
cout << "test_multiset find the target : " << *PItem << endl;
else
cout << "test_multiset not found the target ! " << endl;
}
}
}
int main()
{
long value =500000;
test_multiset::test_multiset(value);
system("pause");
return 0;
}
- multiMap容器的测试程序
#include<iostream>
#include<map>
#include<ctime>
#include<cstdio>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio> //snprintf()
#include<utility>
using namespace std;
namespace test_multimap{
void test_multimap(long & value){
cout << "\n test_multimap()........\n" << endl;
char buf[10];
multimap<long, string>mu_map;//定义一个multimap的对象
clock_t timestate = clock();
srand((int)time(NULL));
for (long i = 0; i < value; i++){
try{
snprintf(buf, 10, "%d", rand());
//multimap 不可使用 [] 做 insertion
mu_map.insert(pair<long, string>(i, buf));//************插入时为键+值
}
catch (exception & p){
cout << "i = " << i << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds of the test_multimap mu_map : " << (clock() - timestate) << endl;
cout << "test_multimap mu_map.max_size() = " << mu_map.max_size() << endl;
cout << "test_multimap mu_map.size() = " << mu_map.size() << endl;
long target = exp1::get_a_target_long();
{
timestate = clock();
auto PItem = ::find(mu_map.begin(), mu_map.end(), target);
cout << "milli-secpnds ::find test_multimap : " << (clock() - timestate) << endl;
if (PItem != mu_map.end())
cout << "test_multimap :: found," << (*PItem).second << endl;
else
cout << "test_multimap not found !" << endl;
}
{
timestate = clock();
auto PItem = mu_map.find(target);
cout << "milli-secpnds find test_multimap : " << (clock() - timestate) << endl;
if (PItem != mu_map.end())
cout << "test_multimap :: found," << (*PItem).second << endl;
else
cout << "test_multimap not found !" << endl;
}
}
}
int main()
{
long value =500000;
test_multimap::test_multimap(value);
system("pause");
return 0;
}
- 补充:下面主要补充一下try\catch\throw的 使用
1.“try”总是与“catch”一同出现,伴随一个try语句,至少应该有一个catch()语句,try随后的block是可能抛出异常的地方。
2.“catch”带有一个参数,参数类型以及参数名字都由程序指定,名字可以忽略。如果在catch随后的block中并不打算引用这个异常对象的。参数类型可以是build-intype,例如int、long、char等,也可以是一个对象,一个对象指针或者引用,如果希望捕获任意类型的异常,可以使用“…”作为catch的参数。
3.“catch”不一定要全部捕获tryblock中抛出的异常,剩下没有捕获的可以交给上一级函数处理。
4.“throw”throw类型后面带一个类型的实例,它和catch的关系就像是函数的调用,catch指定形参,throw给出实参。编译器按照catch给定的顺序以及catch指定的参数类型,确定一个异常由哪一个catch来处理。