GP
image.png

1. 序列式容器

1.1 array

不允许扩充,在使用时指定内存大小 array;

  1. //如果传入的_Nm = 0,则array数组默认分配的内存为1
  2. value_type _M _instance[ Nm ? _ Nm : 1];

image.png

1.2 vector

每次都是成倍扩充,很浪费内存,但是找起来很方便
push_back() pop_back()
clip_image002.jpg

  1. //操作符重载[]
  2. reference operator[] (size_type n)
  3. {
  4. return *(begin() + n);
  5. }


1.3 list

空间利用率很高,但是找起来很麻烦,每次都要遍历一遍
push_back() pop_back()
push_front() pop_front()
clip_image002-1547608564071.jpg

  1. //操作符重载了 ++ ,* ,-> 等符号,和一大推typedefine
  2. self& operator++() {
  3. node = (link_type)((*node) .next);
  4. //取出(*node) .next,再进行强制类型转换link_type,赋值给node
  5. return *this;
  6. }
  7. //T&
  8. reference operator*() const {
  9. return (*node) .data;
  10. }
  11. //T*
  12. pointer operator->() const {
  13. return &(operator*());
  14. }

1.4 deque

分段连续,双向进出,有个中控器维护每段缓冲区的地址,中控器可以理解为一个vector,也是成倍扩充的
这里有个有趣的事情是扩充后,会将原来的数据copy到新内存的中段,这样就保证了可前后进出了。
image.png
push_back() pop_back()
push_front() pop_front()
clip_image002-1547547642923.jpg
在32位的win系统下,每创建一个deque,占的内存为 40bit

  1. //deque类
  2. //所谓 buffer_size是指每个buffer 容纳的元素个数
  3. template < class T, class Alloc=alloc,size_t BufSiz=0 >
  4. class deque {
  5. public:
  6. typedef T value_type;
  7. typedef _deque_iterator<T,T&,T*,BufSiz> iterator;
  8. protected:
  9. typedef pointer* map pointer; //T**
  10. protected:
  11. iterator start;
  12. iterator finish;
  13. map_pointer map;
  14. size_type map_size;
  15. public:
  16. iterator begin() { return start;}
  17. iterator end() {return finish; }
  18. size_type size() const { return finish - start; }
  19. }

image.png
deque的迭代器是一个封装的class,内部含有四个元素cur,first,last,node

  1. //deque的迭代器本身也封装成了类
  2. template <class T, class Refclass Ptr,size_t BufSiz>
  3. struct _deque_iterator {
  4. typedef random_access_iterator_tag iterator_category;
  5. typedef T value_type;
  6. typedef Ptr pointer;
  7. typedef Ref reference;
  8. typedef size_t size_type;
  9. typedef ptrdiff_t difference_type;
  10. typedef _deque_iterator self;
  11. T* cur;
  12. T* first;
  13. T* last;
  14. T** node;
  15. }

stack和queue自己本身并没有实现什么数据结构,其内部其实就是一个deque,借用deque进行操作,所以有时候也不把这两个称为容器,可以理解为容器的适配器
其底层也可以用 list 做支撑,但是deque比较快
image.png
他们也没有迭代器这种东西,因为如果有这个的话意味着他们可以随意插入和删除其中的元素,这样会破坏他们原来的先进先出,先进后出的属性

1.5 stack

先进后出
push() 压入
pop() 弹出
clip_image002-1547604555425.jpg

1.6 queue

先进先出
push() 压入 pop() 弹出
clip_image002-1547606475892.jpg

2. 关联式容器

2.1 红黑树

2.2 set/multiset

image.png

set容器特点:
//所有元素插入时候自动被排序
//set容器不允许插入重复值

  1. void test_multiset(long& value) //传引用
  2. {
  3. cout << endl << "test multiset.........." << endl;
  4. multiset<string> c;
  5. char buf[10];
  6. clock_t timeStart = clock();
  7. for (long i = 0; i < value; i++)
  8. {
  9. try
  10. {
  11. snprintf(buf, 10, "%d", rand());
  12. c.insert(string(buf));
  13. //buf是一个char数组,需要转化为string类型,才能放入vector中
  14. }
  15. //如果系统无法再分配空间了,就会引发异常
  16. catch (exception& p)//捕获了异常,抓住了异常
  17. {
  18. cout << "i=" << i << " " << p.what() << endl;
  19. abort();//退出程序
  20. }
  21. }
  22. cout << "milli-seconds:" << clock() - timeStart << endl;
  23. cout << "c.size() = " << c.size() << endl;
  24. cout << "c.max_size() = " << c.max_size() << endl;
  25. string target = get_a_target_string();
  26. //调用标准库提供的全局::find()
  27. timeStart = clock();
  28. auto flag = ::find(c.begin(), c.end(), target);
  29. cout << "::find().milli-seconds:" << clock() - timeStart << endl; //12ms
  30. if (flag != c.end())
  31. cout << "found," << *flag << endl;
  32. else
  33. cout << "not found" << endl;
  34. //调用容器自己的find()
  35. timeStart = clock();
  36. flag = c.find(target);
  37. cout << "c.find(target),milli-seconds:" << clock() - timeStart << endl; //0ms
  38. if (flag != c.end())
  39. cout << "found," << *flag << endl;
  40. else
  41. cout << "not found" << endl;
  42. }

2.3 map/multimap

image.png

  1. void test_multimap(long& value)//传引用
  2. {
  3. cout << endl << "test multimap.........." << endl;
  4. multimap <long, string> c;
  5. char buf[10];
  6. clock_t timeStart = clock();
  7. for (long i = 0; i < value; i++)
  8. {
  9. try
  10. {
  11. snprintf(buf, 10, "%d", rand());
  12. c.insert(pair<long, string>(i, buf));
  13. //c[i] = srting(buf);
  14. //multimap不可用[]做insert,map可以用,但是直接c.insert()比c[i]速度要快一点
  15. }
  16. catch (exception& p)//捕获了异常,抓住了异常
  17. {
  18. cout << "i=" << i << " " << p.what() << endl;
  19. abort();//退出程序
  20. }
  21. }
  22. cout << "milli-seconds:" << clock() - timeStart << endl;
  23. cout << "c.size() = " << c.size() << endl;
  24. cout << "c.max_size() = " << c.max_size() << endl;
  25. long target = get_a_target_long();
  26. timeStart = clock();
  27. auto flag = c.find(target);
  28. cout << "c.find(target),milli-seconds:" << clock() - timeStart << endl;
  29. if (flag != c.end())
  30. cout << "found," << (*flag).second << endl;
  31. else
  32. cout << "not found" << endl;
  33. }

2.6 哈希表

并不是大量的数学公式,而是前辈们的一些经验理论

2.7 unordered_multiset

2.8 unordered_multimap

p9 面向对象编程(OOP)VS泛型编程(GP)

OOP:数据放在类里面,操作这些数据的函数也放在类里面,试图将data与methods直接关联在一起

GP:将data与methods分来,通过模板可以实现函数的复用
QQ截图20210829154632.png
比如我们要实现比较大小的算法,我们完全可以下面这样实现
这个 T 你可以随意指定,可以是vector,list 甚至是 person,stone,只是你需要重载一下操作符 <

template <class T>
inline const T& min(const T& a, const T& b)
{
    return b < a ? b : a;
}

template <class T>
inline const T& max(const T& a, const T& b)
{
    return b > a ? b : a;
}

提问:为什么list容器不能使用全局的sort()函数? 因为list的迭代器有问题,链表的迭代器是单独设计的一个class。 在全局 sort() 源码里会出现迭代器的加减乘除运算,但list不支持随机存储,故不可做加减乘除运算,不能调用全局的 sort() 算法,所以需要在类内重写sort(),

随机访问迭代器的意思是可以在该迭代器指向的位置基础上向前或者向后移动n的位置,还能获取到容器的数据。 并且一个容器的迭代器如果不是随机访问迭代器的话,它往往也不支持使用 [ ] at 来通过下标访问容器中的任意一个元素。

3. 算法

一般会提供两个接口
一个是普通版本,一个是带有仿函数的版本

3.1 accumulate

template <class InputIterator,class T>
T accumulate(InputIterator first, InputIterator last,T init)
{    
    for( ;first != last; ++first)
        //将元素累加至初值init身上
        init = init +*first;return init;
}


template <class InputIterator, class T, class BinaryOperation>
T accumulate(InputIterator first, InputIterator last, T init, BinaryOperation binary_op)
{
    for ( ; first != last; ++first)
        //到元素「累计算」至初值init身上
        init = binary_op(init, * first);
    return init;
}

3.2 for_each

template <class InputIterator, class Function>
Function for_each(InputIterator first, InputIterator last, Function f)
{
    for( ; first != last; ++first)
        f(*first);
    return f;
}

3.3 replace

3.4 count

除了std::count() 形式,还有成员函数形式的 count(),有自己的就用自己的
image.png

3.5 find

除了std::find() 形式,还有成员函数形式的 find()
image.png

3.6 sort

除了std::sort() 形式,还有成员函数形式的 sort()
image.png