概论,各组件的大致示例
6大组件
容器
概论
容器的遍历
STL中的区间遵循前闭后开的表示方式,迭代器begin指向的是第一个元素的起点,end指向的是最后一个元素的下一个元素.
偷懒可以写C++11的ranged based for,就不用写迭代器,见面向对象下
容器的结构
箭头代表内存可以扩充的方向
STL中的容器大体分为序列容器、关联容器和无序容器.(standard library的那本书)
在primer中无序容器归为关联容器
array, forward_list , unordered Container都为C++11新加的
array是数组在封装了一下
list实际上是双向循环链表
set和 map底层是红黑树
map节点是键值对
multi 的含义是可重复的元素
Unordered Set/Map底层是哈希表(拉链法)
容器的示例
const long ASIZE = 500000L; // 数组大小
// 从console中读入一个 long
long get_a_target_long() {
long target = 0;
cout << "target (0~" << RAND_MAX << "): ";
cin >> target;
return target;
}
// 从console中读入一个 string
string get_a_target_string() {
long target = 0;
char buf[10];
cout << "target (0~" << RAND_MAX << "): ";//todo :RAND_MAX
cin >> target;
snprintf(buf, 10, "%d", target);//todo :snprintf,把输入的long转换为字符数组然后放到buf(缓冲区)
return string(buf);//返回string对象
}
// 比较 long
int compareLongs(const void *a, const void *b) {
return (*(long *) a - *(long *) b);
}
// 比较 string
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;
}
array示例
#include <array>
#include <iostream>
#include <ctime>
#include <cstdlib> // qsort, bsearch, NULL
void test_array() {
cout << "\ntest_array().......... \n";
array<long, ASIZE> c;//ASIZE前面定义的辅助函数那里的宏
clock_t timeStart = clock();
for (long i = 0; i < ASIZE; ++i) {
c[i] = rand();
}
cout << "milli-seconds : " << (clock() - timeStart) << endl;//填充的时间
cout << "array.size()= " << c.size() << endl;
cout << "array.front()= " << c.front() << endl;
cout << "array.back()= " << c.back() << endl;
cout << "array.data()= " << c.data() << endl;
long target = get_a_target_long();
timeStart = clock();
::qsort(c.data(), ASIZE, sizeof(long), compareLongs);
long *pItem = (long *) ::bsearch(&target, (c.data()), ASIZE, sizeof(long), compareLongs);
cout << "qsort()+bsearch(), milli-seconds : " << (clock() - timeStart) << endl; //
if (pItem != NULL)
cout << "found, " << *pItem << endl;
else
cout << "not found! " << endl;
}
/*output
test_array()..........
milli-seconds : 13
array.size()= 500000// 大小
array.front()= 28060//第一个元素的内容
array.back()= 25634//最后一个元素的内容
array.data()= 0x6a7910//数组头部地址
target (0~32767):20000 //调用21行辅助函数
qsort()+bsearch(), milli-seconds : 88 //qsort快速排序,bsearch二分查找
found, 20000
*/
<cstdlib> 里有 qsort, bsearch
vector 容器示例
push_back()
#include <vector>
#include <stdexcept>
#include <string>
#include <cstdlib> // abort()
#include <cstdio> // snprintf()
#include <iostream>
#include <ctime>
#include <algorithm> // sort()
void test_vector(long &value) {
cout << "\ntest_vector().......... \n";
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));
}
catch (exception &p) {
cout << "i=" << i << " " << p.what() << endl;
// 曾經最高 i=58389486 then std::bad_alloc
abort();// 退出程序
}
}
cout << "milli-seconds : " << (clock() - timeStart) << endl;
cout << "vector.max_size()= " << c.max_size() << endl;
cout << "vector.size()= " << c.size() << endl;
cout << "vector.front()= " << c.front() << endl;
cout << "vector.back()= " << c.back() << endl;
cout << "vector.data()= " << c.data() << endl;
cout << "vector.capacity()= " << c.capacity() << endl << endl;
string target = get_a_target_string();
{
timeStart = clock();
auto pItem = find(c.begin(), c.end(), target);//find是全局函数
cout << "std::find(), milli-seconds : " << (clock() - timeStart) << endl;
if (pItem != c.end())
cout << "found, " << *pItem << endl << endl;
else
cout << "not found! " << endl << endl;
}
{
timeStart = clock();
sort(c.begin(), c.end());
cout << "sort(), milli-seconds : " << (clock() - timeStart) << endl;
timeStart = clock();
string *pItem = (string *) ::bsearch(&target, (c.data()), c.size(), sizeof(string), compareStrings);
cout << "bsearch(), milli-seconds : " << (clock() - timeStart) << endl;
if (pItem != NULL)
cout << "found, " << *pItem << endl << endl;
else
cout << "not found! " << endl << endl;
}
}
how many elements:1000000
test_vector()..........
milli-seconds : 211
vector.max_size()= 576460752303423487
vector.size()= 1000000//容器里面放了多少元素
vector.front()= 30271
vector.back()= 7756
vector.data()= 0x4830040//首地址
vector.capacity()= 1048576//容器的大小
target (0~32767):23456
std::find(), milli-seconds : 1
found, 23456
sort(), milli-seconds : 2695
bsearch(), milli-seconds : 1
found, 23456
vector底层是一段连续的内存空间,当容器满时进行扩容,将容器大小扩容为原来的两倍.
向后扩容,
先开辟一个两倍的空间,然后拷贝元素过去,然后销毁原有空间
<algorithm>都是一些全局的模板函数
vector<string> c;这里不写第二个模板参数(分配器),直接用默认的
list容器示例
push_front也可以
#include <list>
#include <stdexcept>
#include <string>
#include <cstdlib> // abort()
#include <cstdio> // snprintf()
#include <algorithm> // find()
#include <iostream>
#include <ctime>
void test_list(long &value) {
cout << "\ntest_list().......... \n";
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));
}
catch (exception &p) {
cout << "i=" << i << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds : " << (clock() - timeStart) << endl;
cout << "list.size()= " << c.size() << endl;
cout << "list.max_size()= " << c.max_size() << endl; //357913941
cout << "list.front()= " << c.front() << endl;
cout << "list.back()= " << c.back() << 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;
}
how many elements:1000000
test_list()..........
milli-seconds : 406
list.size()= 1000000
list.max_size()= 384307168202282325
list.front()= 31411
list.back()= 7939
target (0~32767):23456
std::find(), milli-seconds : 4
found, 23456
c.sort(), milli-seconds : 3610//3610ms,3.610s
程序第44行调用的是list类的成员函数sort,而非标准库中的算法sort.
这是因为list类本身具有sort方法,容器本身实现的sort的性能一般比标准库中的算法sort更好.
forward_list容器示例
只能是push_front
forward_list是C++11标准引入的,其前身是gcc(gnu)中的slist.
#include <forward_list>
#include <stdexcept>
#include <string>
#include <cstdlib> // abort()
#include <cstdio> // snprintf()
#include <iostream>
#include <ctime>
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;
}
how many elements:1000000
test_forward_list()..........
milli-seconds : 296
forward_list.max_size()= 461168601842738790
forward_list.front()= 11513
target (0~32767):23456
std::find(), milli-seconds : 9
found, 23456
c.sort(), milli-seconds : 3706
forward_list没有size(), 没有push_back()
deque容器示例
deque容器可以再双端插入和删除,其底层是分段连续的,对于使用者来说造成了一种连续的假象.
遍历到99后,迭代器需要移到0的那里,这是操作符++重载内容
满了申请一个buffer
#include <deque>
#include <stdexcept>
#include <string>
#include <cstdlib> // abort()
#include <cstdio> // snprintf()
#include <iostream>
#include <ctime>
void test_deque(long &value) {
cout << "\ntest_deque().......... \n";
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));
}
catch (exception &p) {
cout << "i=" << i << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds : " << (clock() - timeStart) << endl;
cout << "deque.size()= " << c.size() << endl;
cout << "deque.front()= " << c.front() << endl;
cout << "deque.back()= " << c.back() << endl;
cout << "deque.max_size()= " << c.max_size() << 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();
sort(c.begin(), c.end());
cout << "sort(), milli-seconds : " << (clock() - timeStart) << endl;
}
how many elements:1000000
test_deque()..........
milli-seconds : 170
deque.size()= 1000000
deque.front()= 4080
deque.back()= 29186
deque.max_size()= 576460752303423487
target (0~32767):23456
std::find(), milli-seconds : 5
found, 23456
sort(), milli-seconds : 2924
Stack和Queue容器示例
stack和queue底层是通过deque实现的,从设计模式上来说,这两种容器本质上是deque的适配器.
#include <stack>
#include <queue>
#include <stdexcept>
#include <string>
#include <cstdlib> // abort()
#include <cstdio> // snprintf()
#include <iostream>
#include <ctime>
void test_stack(long &value) {
cout << "\ntest_stack().......... \n";
stack <string> c;
char buf[10];
clock_t timeStart = clock();
for (long i = 0; i < value; ++i) {
try {
snprintf(buf, 10, "%d", rand());
c.push(string(buf));
}
catch (exception &p) {
cout << "i=" << i << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds : " << (clock() - timeStart) << endl;
cout << "stack.size()= " << c.size() << endl;
cout << "stack.top()= " << c.top() << endl;
c.pop();
cout << "stack.size()= " << c.size() << endl;
cout << "stack.top()= " << c.top() << endl;
}
void test_queue(long &value) {
cout << "\ntest_queue().......... \n";
queue <string> c;
char buf[10];
clock_t timeStart = clock();
for (long i = 0; i < value; ++i) {
try {
snprintf(buf, 10, "%d", rand());
c.push(string(buf));
}
catch (exception &p) {
cout << "i=" << i << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds : " << (clock() - timeStart) << endl;
cout << "queue.size()= " << c.size() << endl;
cout << "queue.front()= " << c.front() << endl;
cout << "queue.back()= " << c.back() << endl;
c.pop();
cout << "queue.size()= " << c.size() << endl;
cout << "queue.front()= " << c.front() << endl;
cout << "queue.back()= " << c.back() << endl;
}
how many elements:300000
test_stack()..........
milli-seconds : 57
stack.size()= 300000
stack.top()= 17153
stack.size()= 299999
stack.top()= 31703
how many elements:300000
test_queue()..........
milli-seconds : 54
queue.size()= 300000
queue.front()= 6608
queue.back()= 29870
queue.size()= 299999
queue.front()= 7837
queue.back()= 29870
multiset和multimap
multiset和multimap底层是使用红黑树实现的.
#include <set>
#include <map>
#include <stdexcept>
#include <string>
#include <cstdlib> // abort()
#include <cstdio> // snprintf()
#include <iostream>
#include <ctime>
void test_multiset(long &value) {
cout << "\ntest_multiset().......... \n";
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));
}
catch (exception &p) {
cout << "i=" << i << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds : " << (clock() - timeStart) << endl;
cout << "multiset.size()= " << c.size() << endl;
cout << "multiset.max_size()= " << c.max_size() << endl;
string target = get_a_target_string();
{
timeStart = clock();
auto pItem = find(c.begin(), c.end(), target); //比 multiset::find(...) 慢很多
cout << "std::find(), milli-seconds : " << (clock() - timeStart) << endl;
if (pItem != c.end())
cout << "found, " << *pItem << endl;
else
cout << "not found! " << endl;
}
{
timeStart = clock();
auto pItem = c.find(target); //比 std::find(...) 快很多
cout << "c.find(), milli-seconds : " << (clock() - timeStart) << endl;
if (pItem != c.end())
cout << "found, " << *pItem << endl;
else
cout << "not found! " << endl;
}
}
void test_multimap(long &value) {
cout << "\ntest_multimap().......... \n";
multimap<long, string> c;
char buf[10];
clock_t timeStart = clock();
for (long i = 0; i < value; ++i) {
try {
snprintf(buf, 10, "%d", rand());
//multimap 不可使用 [] 做 insertion
c.insert(pair<long, string>(i, buf));
}
catch (exception &p) {
cout << "i=" << i << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds : " << (clock() - timeStart) << endl;
cout << "multimap.size()= " << c.size() << endl;
cout << "multimap.max_size()= " << c.max_size() << endl; //178956970
long target = get_a_target_long();
timeStart = clock();
auto pItem = c.find(target);
cout << "c.find(), milli-seconds : " << (clock() - timeStart) << endl;
if (pItem != c.end())
cout << "found, value=" << (*pItem).second << endl;
else
cout << "not found! " << endl;
c.clear();
}
how many elements:1000000
test_multiset()..........
milli-seconds : 5202
multiset.size()= 1000000
multiset.max_size()= 288230376151711743
target (0~32767):23456
std::find(), milli-seconds : 75
found, 23456
c.find(), milli-seconds : 0
found, 23456
how many elements:1000000
test_multimap()..........
milli-seconds : 1423
multimap.size()= 1000000
multimap.max_size()= 256204778801521550
target (0~32767):23456
c.find(), milli-seconds : 0
found, value=13328
unordered_multiset和unordered_multimap
unordered_multiset和unordered_multimap底层是使用hash
开散列法或者叫拉链法
#include <unordered_set>
#include <unordered_map>
#include <stdexcept>
#include <string>
#include <cstdlib> // abort()
#include <cstdio> // snprintf()
#include <iostream>
#include <ctime>
void test_unordered_multiset(long &value) {
cout << "\ntest_unordered_multiset().......... \n";
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));
}
catch (exception &p) {
cout << "i=" << i << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds : " << (clock() - timeStart) << endl;
cout << "unordered_multiset.size()= " << c.size() << endl;
cout << "unordered_multiset.max_size()= " << c.max_size() << endl; //357913941
cout << "unordered_multiset.bucket_count()= " << c.bucket_count() << endl;
cout << "unordered_multiset.load_factor()= " << c.load_factor() << endl;
cout << "unordered_multiset.max_load_factor()= " << c.max_load_factor() << endl;
cout << "unordered_multiset.max_bucket_count()= " << c.max_bucket_count() << endl;
for (unsigned i = 0; i < 10; ++i) {
cout << "bucket #" << i << " has " << c.bucket_size(i) << " elements.\n";
}
string target = get_a_target_string();
{
timeStart = clock();
auto pItem = find(c.begin(), c.end(), target); //比 unordered_multiset::find() 慢很多
cout << "std::find(), milli-seconds : " << (clock() - timeStart) << endl;
if (pItem != c.end())
cout << "found, " << *pItem << endl;
else
cout << "not found! " << endl;
}
{
timeStart = clock();
auto pItem = c.find(target); //比 std::find() 快很多
cout << "c.find(), milli-seconds : " << (clock() - timeStart) << endl;
if (pItem != c.end())
cout << "found, " << *pItem << endl;
else
cout << "not found! " << endl;
}
}
void test_unordered_multimap(long &value) {
cout << "\ntest_unordered_multimap().......... \n";
unordered_multimap<long, string> c;
char buf[10];
clock_t timeStart = clock();
for (long i = 0; i < value; ++i) {
try {
snprintf(buf, 10, "%d", rand());
//multimap 不可使用 [] 進行 insertion
c.insert(pair<long, string>(i, buf));
}
catch (exception &p) {
cout << "i=" << i << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds : " << (clock() - timeStart) << endl;
cout << "unordered_multimap.size()= " << c.size() << endl;
cout << "unordered_multimap.max_size()= " << c.max_size() << endl;
long target = get_a_target_long();
timeStart = clock();
auto pItem = c.find(target);
cout << "c.find(), milli-seconds : " << (clock() - timeStart) << endl;
if (pItem != c.end())
cout << "found, value=" << (*pItem).second << endl;
else
cout << "not found! " << endl;
}
how many elements:1000000
test_unordered_multiset()..........
milli-seconds : 1476
unordered_multiset.size()= 1000000
unordered_multiset.max_size()= 384307168202282325
unordered_multiset.bucket_count()= 1832561
unordered_multiset.load_factor()= 0.545684
unordered_multiset.max_load_factor()= 1//装填因子最多只能为1
unordered_multiset.max_bucket_count()= 384307168202282325
bucket #0 has 0 elements.
bucket #1 has 0 elements.
bucket #2 has 0 elements.
bucket #3 has 0 elements.
bucket #4 has 0 elements.
bucket #5 has 0 elements.
bucket #6 has 0 elements.
bucket #7 has 34 elements.
bucket #8 has 0 elements.
bucket #9 has 0 elements.
target (0~32767):23456
std::find(), milli-seconds : 104
found, 23456
c.find(), milli-seconds : 1
found, 23456
how many elements:1000000
test_unordered_multimap()..........
milli-seconds : 1051
unordered_multimap.size()= 1000000
unordered_multimap.max_size()= 384307168202282325
target (0~32767):23456
c.find(), milli-seconds : 0
found, value=20464
unordered_multiset和unordered_multimap的元素个数小于篮子数目,
若元素数目达到篮子个数,则容器扩容,将篮子数组扩充约一倍.
一个篮子的内部链表是循序查找,就慢
set和map
map中c[i]是特殊的
c[i]=string(buf)底层会把i作为key,string(buf)作为value然后放进红黑树
因为每个i都不重复所以100000都成功插入进去
gcc(gnu)类似的
很早就有
分配器
STL容器默认的分配器是std::allocator,除此之外gcc额外定义了几个分配器,其头文件均在目录ext下.
mt_allocator是多线程(multi thread)
gcc额外定义的分配器均位于__gnu_cxx命名空间下.分配器一般用于构建容器,不会直接使用.
因为分配器想要直接使用也不好用(使用free关键字时不需要指定回收内存的大小,而分配器的deallocate函数需要指定回收内存大小).
一般在用容器的时候,去指明分配器类型,而不是单独去用
#include <list>
#include <stdexcept>
#include <string>
#include <cstdlib> // abort()
#include <cstdio> // snprintf()
#include <algorithm> // find()
#include <iostream>
#include <ctime>
#include <cstddef>
#include <memory> //內含 std::allocator
//欲使用 std::allocator 以外的 allocator,得自行 #include <ext\...>
#ifdef __GNUC__
#include <ext\array_allocator.h>
#include <ext\mt_allocator.h>
#include <ext\debug_allocator.h>
#include <ext\pool_allocator.h>
#include <ext\bitmap_allocator.h>
#include <ext\malloc_allocator.h>
#include <ext\new_allocator.h>
#endif
//pass A object to function template impl(),
//而 A 本身是個 class template, 帶有 type parameter T,
//那麼有無可能在 impl() 中抓出 T, 創建一個 list<T, A<T>> object?
//以下先暫時迴避上述疑問.
void test_list_with_special_allocator() {
#ifdef __GNUC__
cout << "\ntest_list_with_special_allocator().......... \n";
//----使用不同的分配器建立list----
//不能在 switch case 中宣告,只好下面這樣. // 1000000次
list <string, allocator<string>> c1; // 3140
list <string, __gnu_cxx::malloc_allocator<string>> c2; // 3110
list <string, __gnu_cxx::new_allocator<string>> c3; // 3156
list <string, __gnu_cxx::__pool_alloc<string>> c4; // 4922
list <string, __gnu_cxx::__mt_alloc<string>> c5; // 3297
list <string, __gnu_cxx::bitmap_allocator<string>> c6; // 4781
int choice;
long value;
cout << "select: "
<< " (1) std::allocator "
<< " (2) malloc_allocator "
<< " (3) new_allocator "
<< " (4) __pool_alloc "
<< " (5) __mt_alloc "
<< " (6) bitmap_allocator ";
cin >> choice;
if (choice != 0) {
cout << "how many elements: ";
cin >> value;
}
char buf[10];
clock_t timeStart = clock();
for (long i = 0; i < value; ++i) {
try {
snprintf(buf, 10, "%d", i);
switch (choice) {
case 1 :
c1.push_back(string(buf));
break;
case 2 :
c2.push_back(string(buf));
break;
case 3 :
c3.push_back(string(buf));
break;
case 4 :
c4.push_back(string(buf));
break;
case 5 :
c5.push_back(string(buf));
break;
case 6 :
c6.push_back(string(buf));
break;
default:
break;
}
}
catch (exception &p) {
cout << "i=" << i << " " << p.what() << endl;
abort();
}
}
cout << "a lot of push_back(), milli-seconds : " << (clock() - timeStart) << endl;
//---直接使用分配器,分配和销毁的时候需要指明大小----
//test all allocators' allocate() & deallocate();
int *p;
allocator<int> alloc1;
p = alloc1.allocate(1);
alloc1.deallocate(p, 1);
__gnu_cxx::malloc_allocator<int> alloc2;
p = alloc2.allocate(1);
alloc2.deallocate(p, 1);
__gnu_cxx::new_allocator<int> alloc3;
p = alloc3.allocate(1);
alloc3.deallocate(p, 1);
__gnu_cxx::__pool_alloc<int> alloc4;
p = alloc4.allocate(2);
alloc4.deallocate(p, 2); //我刻意令參數為 2, 但這有何意義!! 一次要 2 個 ints?
__gnu_cxx::__mt_alloc<int> alloc5;
p = alloc5.allocate(1);
alloc5.deallocate(p, 1);
__gnu_cxx::bitmap_allocator<int> alloc6;
p = alloc6.allocate(3);
alloc6.deallocate(p, 3); //我刻意令參數為 3, 但這有何意義!! 一次要 3 個 ints?
#endif
}
后记和参考
主要内容来自侯捷老师stl课
源码和部分文字和图片来自下方,另外下方是很全的笔记推荐阅读
侯捷C++课程笔记03: STL标准库与泛型编程_c++ stl与泛型编程-优快云博客
这是以前的大二的笔记,现在复习就把以前的笔记整理发出来了。
侵权联系删除