由于源代码有点长,所以我放在GitHub上了
目录
9.对unordered_multiset/unordered_multimap的测试
10.对map/set,unordered_set/unordered_map的测试
一、容器的结构与分类
1.序列式容器
1.array:连续空间,你要多大就多大
2.vector:自动扩充,分配器在背后作用
3.deque:理解为两端可进可出的队列
4.list:链表,双向链表
5.forward-list:单向链表
2.关联式容器(元素有key-value,适合做快速查找)
1.set/multiset:集合(用红黑树做) key和value是同一个,不分的
前者元素不能重复,后者可以
2.map/multimap:用红黑树做,每个节点有key和value,将来用key来找value
前者key不能重复,后者可以
3.不定序容器
1.unordered set/multiset:
2.unordered map/multimap:
对hash table (separate changing)的补充:分离链地址法实现
二、对容器的测试代码
辅助函数:
1.输入目标数值
2.输入目标数值,转化为字符串
3.对数值的比大小(为了进行快排)
4.对字符串的比大小(为了进行快排)
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 (0~" << RAND_MAX << "):" ;
cin >> target;
snprintf(buf, 10, "%d", target);
return string(buf);
}
int compareLongs(const void* a, const void* b )
{
return ( *(long*)a - *(long*)b );// 将a转化为long类型的指针,并取其指向地址的值(即target的值)
}
int compareStrings(const void* a, const void* b)
{
if (*(string*)a > *(string*)b)
return 1;
else if (*(string*)a < *(string*)b)
return -1;
else
return 0;
}
1.对array的测试
首先,创建一个大小为50万的array,接着,对每个元素进行赋值(随机数)
然后,对整个array的每个元素进行qsort(快排),最后,对输入的数据进行二分查找(bsearch)
(1) c.data()返回数组首地址
(2) 使用bsearch二分查找前需要对数组进行排序,这里使用快排qsort,两者都是c标准库的
必须使用头文件<cstdlib>
(3) qsort应用:qsort(c.data,size,size(long),comparelongs)
(4) bsearch()应用:bsearch(&target,(c.data()),size,size(long),comparelongs)
#include<array>
#include<ctime>
#include<cstdlib>
#include<iostream>
namespace jj01
{
void test_array()
{
cout << "\ntest array .........." << endl;
array<long, ASIZE> c;
clock_t timeStart = clock();
for (long i = 0; i < ASIZE; i++) {
c[i] = rand();
}
cout << "milli-seconds:" << clock() - timeStart << endl;
cout << "c.size() = " << c.size() << endl;
cout << "c.front() = " << c.front() << endl;
cout << "c.back() = " << c.back() << endl;
cout << "c.data() = " << c.data() << endl;
long target = get_a_target_long();
timeStart = clock();
qsort(c.data(), ASIZE, sizeof(long), compareLongs);//数组首地址,数组有多少项,每项大小,比大小函数
long* flag = (long*)bsearch(&target, (c.data()), ASIZE, sizeof(long), compareLongs);
cout << "qsort()+bsearch(),milli-seconds:" << clock() - timeStart << endl;
if (flag != NULL)
cout << "found," << *flag << endl;
else
cout << "not found!!!" << endl;
}
}
2.对vector的测试
(1) vecotr增长速度为两倍增长,当capacity不够时,乘以2,
例如, 插入第一个数据,vector本身容量为1,够用。
插入第二个数据,vector容量*2,变为2。
插入第三个数据,vector容量*2,变为4。(此时vector只存了3个数据,即size=3,而capacity=4)
(2) vector 是去别的地方找一块本身两倍的内存,然后把现在的所有内容搬过去
(3) 关于异常处理,采用try...catch结构
(4) ::find()模板函数,加冒号表明是全局函数,当没有冒号时,
编译器在当前没有找到,也会到全局去找。
#include<vector>
#include<cstdlib>//qsort,bsearch,abort
#include<cstdio>//snprintf
#include<iostream>
#include<string>
#include<ctime>
#include<algorithm>//算法,sort
#include<stdexcept>//抛出异常
namespace jj02
{
void test_vector(long& value)//传引用
{
cout << "test vector.........." << endl;
vector<string> c;
char buf[10];
clock_t timeStart = clock();
for (long i = 0; i < value; i++)
{
try
{
snprintf(buf, 10, "%d", rand());
c.push_back(string(buf));//buf是一个char数组,需要转化为string类型,才能放入vector中
}//如果系统无法再分配空间了,就会引发异常
catch (exception& p)//捕获了异常,抓住了异常
{
cout << "i=" << i << " " << p.what() << endl;
abort();//退出程序
}
}
cout << "milli-seconds:" << clock() - timeStart << endl;
cout << "c.size() = " << c.size() << endl;
cout << "c.front() = " << c.front() << endl;
cout << "c.back() = " << c.back() << endl;
cout << "c.data() = " << c.data() << endl;
cout << "c.capicy() = " << c.capacity() << endl;
//vector两倍增长,放入1,变成2,放入2,不变,放入3,变成4,放入4,不变
//放入5,变成8,放入6,7,8,均不变,所以capacity是容器能存储的元素个数
//而size是容器目前存在的元素个数
string target = get_a_target_string();
{
timeStart = clock();
auto flag = ::find(c.begin(), c.end(), target);
cout << "::find().milli-seconds:" << clock() - timeStart << endl;
if (flag != c.end())
cout << "found," << *flag << endl;
else
cout << "not found" << endl;
}
{
timeStart = clock();
sort(c.begin(), c.end());
string* flag = (string*)bsearch(&target, c.data(), c.size(), sizeof(string), compareStrings);
cout << "qsort()+bsearch(),milli-seconds:" << clock() - timeStart << endl;
if (flag != NULL)
cout << "found," << *flag << endl;
else
cout << "not found!!!" << endl;
}
}
}
3.对list的测试
在STL标准库全局有一个sort函数,
但这里调用的是list容器自身内部的sort函数。
注意在STL容器中有些自身有sort函数,此时用自身的排序算法更快。
#include<list>
#include<cstdlib>//qsort,bsearch,abort
#include<cstdio>//snprintf
#include<iostream>
#include<string>
#include<ctime>
#include<algorithm>//算法,sort
#include<stdexcept>//抛出异常
namespace jj03
{
void test_list(long& value)//传引用
{
cout << "test list.........." << endl;
list<string> c;
char buf[10];
clock_t timeStart = clock();
for (long i = 0; i < value; i++)
{
try
{
snprintf(buf, 10, "%d", rand());
c.push_back(string(buf));//buf是一个char数组,需要转化为string类型,才能放入vector中
}//如果系统无法再分配空间了,就会引发异常
catch (exception& p)//捕获了异常,抓住了异常
{
cout << "i=" << i << " " << p.what() << endl;
abort();//退出程序
}
}
cout << "milli-seconds:" << clock() - timeStart << endl;
cout << "c.size() = " << c.size() << endl;
cout << "c.front() = " << c.front() << endl;
cout << "c.back() = " << c.back() << endl;
cout << "c.max_size() = " << c.max_size() << endl;
string target = get_a_target_string();
timeStart = clock();
auto flag = ::find(c.begin(), c.end(), target);
cout << "::find().milli-seconds:" << clock() - timeStart << endl;
if (flag != c.end())
cout << "found," << *flag << endl;
else
cout << "not found" << endl;
timeStart = clock();
c.sort();
cout << "c.sort(),milli-seconds:" << clock() - timeStart << endl;
}
}
4.对forward-list的测试
#include <forward_list>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort()
#include <cstdio> //snprintf()
#include <iostream>
#include <ctime>
namespace jj04
{
void test_forward_list(long& value)
{
cout << "\ntest_forward_list().......... \n";
forward_list<string> c;
char buf[10];
clock_t timeStart = clock();
for (long i = 0; i < value; ++i)
{
try {
snprintf(buf, 10, "%d", rand());
c.push_front(string(buf));
}
catch (exception& p) {
cout << "i=" << i << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds : " << (clock() - timeStart) << endl;
cout << "forward_list.max_size()= " << c.max_size() << endl; //536870911
cout << "forward_list.front()= " << c.front() << endl;
string target = get_a_target_string();
timeStart = clock();
auto pItem = find(c.begin(), c.end(), target);
cout << "std::find(), milli-seconds : " << (clock() - timeStart) << endl;
if (pItem != c.end())
cout << "found, " << *pItem << endl;
else
cout << "not found! " << endl;
timeStart = clock();
c.sort();
cout << "c.sort(), milli-seconds : " << (clock() - timeStart) << endl;
c.clear();
}
}
5.对deque的测试
(1) 每次扩充一个buffer,buffer由指针指向
(2) 本身没有sort函数,所以只能使用全局的sort函数排序
#include<deque>
#include<cstdlib>//qsort,bsearch,abort
#include<cstdio>//snprintf
#include<iostream>
#include<string>
#include<ctime>
#include<algorithm>//算法,sort
#include<stdexcept>//抛出异常
namespace jj05
{
void test_deque(long& value)//传引用
{
cout << endl << "test deque.........." << endl;
deque<string> c;
char buf[10];
clock_t timeStart = clock();
for (long i = 0; i < value; i++)
{
try
{
snprintf(buf, 10, "%d", rand());
c.push_back(string(buf));//buf是一个char数组,需要转化为string类型,才能放入vector中
}//如果系统无法再分配空间了,就会引发异常
catch (exception& p)//捕获了异常,抓住了异常
{
cout << "i=" << i << " " << p.what() << endl;
abort();//退出程序
}
}
cout << "milli-seconds:" << clock() - timeStart << endl;
cout << "c.size() = " << c.size() << endl;
cout << "c.front() = " << c.front() << endl;
cout << "c.back() = " << c.back() << endl;
cout << "c.max_size() = " << c.max_size() << endl;
string target = get_a_target_string();
timeStart = clock();
auto flag = ::find(c.begin(), c.end(), target);
cout << "::find().milli-seconds:" << clock() - timeStart << endl;
if (flag != c.end())
cout << "found," << *flag << endl;
else
cout << "not found" << endl;
timeStart = clock();
::sort(c.begin(), c.end());
cout << "::sort(c.begin(), c.end()),milli-seconds:" << clock() - timeStart << endl;
}
}
6.对slist,stack,queue的测试
(1) stack和queue严格来讲是一种容器适配器,其内部都是由deque构成的
(2) stack和queue不会有一个函数来返回迭代器(泛化的指针),
因为有了迭代器可能你就会去改变stack或queue中的某个数据的值,
或者说插入一个数据,然而这与stack和queue自身的先进后出和先进先出的特点相违背。
所以以上两种适配器find是无法作用的,因为find函数返回的是迭代器类型
好吧其实我并没有测试这些,代码和上面的都差不多,自己去体会一下各自的特点就行
7.对multiset的测试
(1) 先测试multiset而不是set的原因:
前者可以放重复数据,而后者不行
(2) 元素放进去为insert,你无需知道它具体放在哪,只需知道它放进去了(放在红黑树中)
(3) 把元素放进去就已经给你排序好了,所以时间比较久
(4) 测试了全局的find和multiset本身的find函数速度(结果显而易见)
(5) 关联式容器查找非常快,给它一个key,很快就能查找到value。
#include<set>
#include<cstdlib>//qsort,bsearch,abort
#include<cstdio>//snprintf
#include<iostream>
#include<string>
#include<ctime>
#include<algorithm>//算法,sort
#include<stdexcept>//抛出异常
namespace jj06
{
void test_multiset(long& value)//传引用
{
cout << endl << "test multiset.........." << endl;
multiset<string> c;
char buf[10];
clock_t timeStart = clock();
for (long i = 0; i < value; i++)
{
try
{
snprintf(buf, 10, "%d", rand());
c.insert(string(buf));//buf是一个char数组,需要转化为string类型,才能放入vector中
}//如果系统无法再分配空间了,就会引发异常
catch (exception& p)//捕获了异常,抓住了异常
{
cout << "i=" << i << " " << p.what() << endl;
abort();//退出程序
}
}
cout << "milli-seconds:" << clock() - timeStart << endl;
cout << "c.size() = " << c.size() << endl;
cout << "c.max_size() = " << c.max_size() << endl;
string target = get_a_target_string();
timeStart = clock();
auto flag = ::find(c.begin(), c.end(), target);
cout << "::find().milli-seconds:" << clock() - timeStart << endl;
if (flag != c.end())
cout << "found," << *flag << endl;
else
cout << "not found" << endl;
timeStart = clock();
flag = c.find(target);
cout << "c.find(target),milli-seconds:" << clock() - timeStart << endl;
if (flag != c.end())
cout << "found," << *flag << endl;
else
cout << "not found" << endl;
}
}
8.对multimap的测试
(1) multimap内部是红黑树,用key来找value
(2) multimap不可以用[]来做insertion(原因见map)
(3) c.insert( pair<long,string> (i, buff ) )
(4) pair表示multimap中的键值对
(5) (*flag).second
flag是一个迭代器,
前面加*,表示返回迭代器所指的值(这里是指key值为target的的pair,second表示pair的第二个元素)
#include<map>
#include<string>
#include<cstdlib>//qsort,bsearch,abort
#include<cstdio>//snprintf
#include<iostream>
#include<ctime>
#include<stdexcept>//抛出异常
namespace jj07
{
void test_multimap(long& value)//传引用
{
cout << endl << "test multimap.........." << endl;
multimap <long,string> c;
char buf[10];
clock_t timeStart = clock();
for (long i = 0; i < value; i++)
{
try
{
snprintf(buf, 10, "%d", rand());
c.insert( pair<long, string> (i, buf));
}
catch (exception& p)//捕获了异常,抓住了异常
{
cout << "i=" << i << " " << p.what() << endl;
abort();//退出程序
}
}
cout << "milli-seconds:" << clock() - timeStart << endl;
cout << "c.size() = " << c.size() << endl;
cout << "c.max_size() = " << c.max_size() << endl;
long target = get_a_target_long();
timeStart = clock();
auto flag = c.find(target);
cout << "c.find(target),milli-seconds:" << clock() - timeStart << endl;
if (flag != c.end())
cout << "found," << (*flag).second << endl;
else
cout << "not found" << endl;
}
}
9.对unordered_multiset/unordered_multimap的测试
(1) 使用hashtable使用分离链地址方法实现
(2) 篮子比存的元素多,合理,原因:
若元素个数>=篮子个数,篮子需要扩充,变成大约两倍
原来的元素重新打散,挂在篮子上
#include<unordered_set>
#include<cstdlib>//qsort,bsearch,abort
#include<cstdio>//snprintf
#include<iostream>
#include<string>
#include<ctime>
#include<algorithm>//算法,sort
#include<stdexcept>//抛出异常
namespace jj08
{
void test_unordered_multiset(long& value)//传引用
{
cout << endl << "test unordered_multiset.........." << endl;
unordered_multiset<string> c;
char buf[10];
clock_t timeStart = clock();
for (long i = 0; i < value; i++)
{
try
{
snprintf(buf, 10, "%d", rand());
c.insert(string(buf));//buf是一个char数组,需要转化为string类型
}//如果系统无法再分配空间了,就会引发异常
catch (exception& p)//捕获了异常,抓住了异常
{
cout << "i=" << i << " " << p.what() << endl;
abort();//退出程序
}
}
cout << "milli-seconds:" << clock() - timeStart << endl;
cout << "c.size() = " << c.size() << endl;
cout << "c.max_size() = " << c.max_size() << endl;
cout << "c.buket_count() = " << c.bucket_count() << endl;
cout << "c.load_factor() = " << c.load_factor() << endl;
cout << "c.max_bucket_count() = " << c.max_bucket_count() << endl;
for (int i = 0; i < 20; i++) {
cout << "bucket# " << i << " has " << c.bucket_size(i) << " elements " << endl;
}
string target = get_a_target_string();
timeStart = clock();
auto flag = ::find(c.begin(), c.end(), target);
cout << "::find().milli-seconds:" << clock() - timeStart << endl;
if (flag != c.end())
cout << "found," << *flag << endl;
else
cout << "not found" << endl;
timeStart = clock();
flag = c.find(target);
cout << "c.find(target),milli-seconds:" << clock() - timeStart << endl;
if (flag != c.end())
cout << "found," << *flag << endl;
else
cout << "not found" << endl;
}
}
10.对map/set,unordered_set/unordered_map的测试
(1) set中key和value是同一个,所以其中不允许存重复数据
存了1000000,但实际上真正的大小只有32768,因为是存了(0~32767)
(2) map中key不可重复,value可重复
map的insertion可用[]
c[i] = string(buf);
map会把key和value合成一个pair,放入红黑树
三、关于源代码
由于源代码有点长,所以我放在GitHub上了