C++11 标准库 STL

STL 中的容器是用来存储和管理对象集合的类。容器根据其内部数据结构和访问方式可以分为三大类:顺序容器、关联容器和无序关联容器。下面是对这些容器的详细介绍

1. 顺序容器(Sequence Containers

顺序容器用于按特定顺序存储元素。主要包括以下几种

1.1 *std::vector

特点动态数组,支持快速随机访问,插入和删除操作在末尾很快,但在中间或前面插入和删除速度较慢(中间插入/删除用list)。

使用场景:需要动态调整大小频繁进行随机访问(list/deque不支持这个功能)的场景。

	    #include <vector>
		#include <iostream>
		int main() {
		    std::vector<int> vec = {1, 2, 3, 4, 5};
		    vec.push_back(6); // 在末尾添加元素
		    for (int val : vec) {
		        std::cout << val << " ";
		    }
		    return 0;
		}

1.2 std::deque

特点双端队列,支持快速随机访问,允许在两端进行快速插入和删除操作。

使用场景:需要在两端插入和删除元素的场景。

#include <deque>
		#include <iostream>
		int main() {
		    std::deque<int> deq = {1, 2, 3, 4, 5};
		    deq.push_front(0); // 在前面添加元素
		    deq.push_back(6);  // 在末尾添加元素
		    for (int val : deq) {
		        std::cout << val << " ";
		    }
		    return 0;
		}

如定义一个task队列, 从队列的尾部添加新的task,从队列的头部开始执行task

template <class T>
class TaskQueue {
 public:
  TaskQueue() {}
  virtual ~TaskQueue() {}

  void AppendTask(T task) {
    Lock lock(mutex_);
    tasks_.push_back(task);
  }

  void TriggerAllTask() {
    Lock lock(mutex_);
    while (!tasks_.empty()) {
      T task = tasks_.front();
      tasks_.pop_front();
      mutex_.Unlock();

      task();
      mutex_.Lock();
    }
  }

  void pop_front() {
    Lock lock(mutex_);
    if (!tasks_.empty()) {
      T task = tasks_.front();
      tasks_.pop_front();
      mutex_.Unlock();
      task();
    }
  }
 protected:
  std::deque<T> tasks_;
  PthreadMutex mutex_;
};

实例化上面的task如下:

class MsgTaskQueue
{
    public:
    static MsgTaskQueue& Instance() {
        static MsgTaskQueue instance;
        return instance;
    }
    void RemoveTask(const std::string uuId) {
        std::lock_guard<std::mutex> lockGuard(mutex_);
        for (std::deque<MsgTaskQueue>::iterator iter = tasks_.begin();
             iter != tasks_.end();) {
          if (iter->uuId == uuId) {
            iter = tasks_.erase(iter);
          } else {
            ++iter;
          }
        }
    }

    void AppendTask(MsgTaskQueuetask) {
        std::lock_guard<std::mutex> lockGuard(mutex_);
        tasks_.push_back(task);
    }


    void PopFront() {
        std::lock_guard<std::mutex> lockGuard(mutex_);
        if (!tasks_.empty()) {
           MsgTaskQueue task = tasks_.front();
            tasks_.pop_front();
            mutex_.unlock();
            task();
        }
    }


    protected:
    std::deque<MsgTaskQueue> tasks_;
    std::mutex mutex_;
};

1.3 ** std::list

特点:双向链表,支持快速插入和删除操作,但不支持随机访问。

使用场景:需要频繁在中间插入和删除元素的场景。

#include <list>
		#include <iostream>
		int main() {
		    std::list<int> lst = {1, 2, 3, 4, 5};
		    lst.push_back(6); // 在末尾添加元素
		    lst.push_front(0); // 在前面添加元素
		    for (int val : lst) {
		        std::cout << val << " ";
		    }
		    return 0;
		}

1.4 std::forward_list

特点单向链表,只能向前遍历内存开销比 std::list 小。

使用场景:需要轻量级的链表结构且只需向前遍历的场景。

1.5 std::array

特点固定大小的数组,大小在编译时确定

使用场景:需要固定大小数组且不需要动态调整大小的场景。

#include <array>
		#include <iostream>
		int main() {
		    std::array<int, 5> arr = {1, 2, 3, 4, 5};
		    for (int val : arr) {
		        std::cout << val << " ";
		    }
		    return 0;
		}

1.6 std::vector<bool>

特点:特殊化的 std::vector,用于存储布尔值。

注意:由于实现方式的不同,std::vector<bool> 不能像其他 std::vector 那样直接访问元素

#include <vector>
		#include <iostream>
		int main() {
		    std::vector<bool> vec = {true, false, true};
		    for (bool val : vec) {
		        std::cout << val << " ";
		    }
		    return 0;
		}

2.关联容器(Associative Containers

关联容器用于以键值对的形式存储元素,并基于键进行快速查找

2.1 std::set

特点:存储唯一的键,自动排序

使用场景:需要存储唯一元素并快速查找的场景。

#include <set>
		#include <iostream>
		int main() {
			std::cout << " main started" << std::endl;
		    std::set<int> s = {1, 2, 7, 4, 5};
		    
		    for (int val : s) {
		        std::cout << val << " ";
		    }
		    return 0;
		}
output:
 main started
1 2 4 5 7 

2.2 std::map

特点:存储键值对,键唯一且自动排序。

使用场景:需要根据键快速查找值的场景。

#include <map>
		#include <iostream>
		int main() {
		    std::map<int, std::string> m = {{1, "one"}, {7, "two"}, {3, "three"}};
		
		    for (const auto& [key, val] : m) {
		        std::cout << key << ": " << val << std::endl;
		    }
		    return 0;
		}
1: one
3: three
7: two

2.3 std::multiset

特点:存储可重复的键,自动排序。

使用场景:需要存储重复元素并快速查找的场景。

2.4 std::multimap

特点:存储键值对,键可重复且自动排序。

使用场景:需要根据键快速查找多个值的场景。

3. 无序关联容器(Unordered Associative Containers

无序关联容器通过哈希表实现,支持更快的平均查找速度

3.1 std::unordered_set

3.2 std::unordered_map

3.3 std::unordered_multiset

3.4 std::unordered_multimap

4.迭代器的使用

4.1 访问迭代器中的值

* 解引用

->

4.2 基本用法(注意:删除其中的某个数据)

4.2.1 遍历

#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};

    // 使用普通迭代器遍历
    for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    // 使用范围 for 循环(C++11 引入)
    for (int val : vec) {
        std::cout << val << " ";
    }
    std::cout << std::endl;

    return 0;
}

4.2.2 修改(访问其中的数据)

vector/list:

使用* 或者->

#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};

    for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
        *it *= 2; // 将每个元素乘以 2
    }

    for (int val : vec) {
        std::cout << val << " ";
    }
    std::cout << std::endl;

    return 0;
}

map:

使用iter->second;

4.2.2.1 注意删除操作
1. std::vector 删除元素

std::vector 的删除操作会导致后续元素移动,从而使迭代器失效。解决办法是使用 erase 方法的返回值来更新迭代器

#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};

    for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); /* 空 */) {
        if (*it % 2 == 0) {
            it = vec.erase(it); // 更新迭代器
        } else {
            ++it; // 仅在没有删除时递增迭代器
        }
    }

    for (int val : vec) {
        std::cout << val << " ";
    }
    std::cout << std::endl;

    return 0;
}
2. std::list 删除元素

std::list 的删除操作不会使其他迭代器失效,但仍需要更新当前迭代器。

#include <iostream>
#include <list>

int main() {
    std::list<int> lst = {1, 2, 3, 4, 5};

    for (std::list<int>::iterator it = lst.begin(); it != lst.end(); /* 空 */) {
        if (*it % 2 == 0) {
            it = lst.erase(it); // 更新迭代器
        } else {
            ++it; // 仅在没有删除时递增迭代器
        }
    }

    for (int val : lst) {
        std::cout << val << " ";
    }
    std::cout << std::endl;

    return 0;
}
3. std::map std::unordered_map 删除元素

std::map 和 std::unordered_map 的删除操作也不会使其他迭代器失效,但需要更新当前迭代器。

#include <iostream>
#include <map>

int main() {
    std::map<int, std::string> myMap = {{1, "one"}, {2, "two"}, {3, "three"}, {4, "four"}};

    for (auto it = myMap.begin(); it != myMap.end(); /* 空 */) {
        if (it->first % 2 == 0) {
            it = myMap.erase(it); // 更新迭代器
        } else {
            ++it; // 仅在没有删除时递增迭代器
        }
    }

    for (const auto& pair : myMap) {
        std::cout << pair.first << ": " << pair.second << " ";
    }
    std::cout << std::endl;

    return 0;
}
4.2.2.2 遍历过程插入数据

对于vector/list

#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};

    // 在遍历过程中插入数据
    for (auto it = vec.begin(); it != vec.end(); ++it) {
        if (*it == 3) {
            it = vec.insert(it, 99); // 在元素3之前插入99
            ++it; // 移动迭代器到下一个位置
        }
    }

    for (int val : vec) {
        std::cout << val << " ";
    }
    std::cout << std::endl;

    return 0;
}

5.mapunordered_map(红黑树VS哈希表)

map map内部实现了一个红黑树(红黑树是非严格平衡二叉搜索树,),红黑树具有自动排序的功能,因此map内部的所有元素都是 有序 的.
缺点:
因为红黑树结构需要额外的内存来存储树节点的指针和其他信息,所以 内存占用较高。
由于需要保持有序性,所以 插入和删除性能较低
优点:
有序性,这是 map 结构最大的优点;
红黑树,内部实现一个红黑书使得 map 的很多操作在 lgn的时间复杂度下就可以实现,因此效率可以(但又因为保证有序性,所以)

适用场景

1. 需要有序或范围查询的访问:例如需要按键排序输出或范围查询。

2. 查找、插入和删除操作频繁:但对性能要求不是极限

假设需要管理一个学生成绩的系统,并且需要按成绩排序输出:

unordered_map : unordered_map 内部实现了一个哈希表(也叫散列表,通过把关键码值映射到
Hash 表中一个位置来访问记录,查找的时间复杂度可达到 O(1) ,其在海量数据处理中有着广泛应
用)。因此,其元素的排列顺序是无序的。
1. 优点:
因为内部实现了哈希表,因此其插入/查找/删除的速度非常的快;
哈希表结构相对简单,内存占用较低
2. 缺点:
无序; 不支持有序遍历
哈希表的建立比较耗费时间
3. 适用场景

不需要有序访问:例如快速查找某个键值对。

对性能要求较高:需要快速插入、删除和查找操作。

假设需要管理一个产品库存系统,并且需要快速查找某个产品的库存数量:

  • 24
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值