2026/5/20 17:00:48
网站建设
项目流程
网站建设协议一百互联,网站域名好了下一步,京东网上购物,wordpress插件获取数据库序列式容器和关联式容器
STL中的部分容器如#xff1a;string、vector、list、deque、array、forward_list等#xff0c;这些容器统称为序列式容器#xff0c;因为逻辑结构为线性序列的数据结构#xff0c;两个位置存储的值之间⼀般没有紧密的关联关系#xff0c;⽐如交换…序列式容器和关联式容器STL中的部分容器如string、vector、list、deque、array、forward_list等这些容器统称为序列式容器因为逻辑结构为线性序列的数据结构两个位置存储的值之间⼀般没有紧密的关联关系⽐如交换⼀下他依旧是序列式容器。顺序容器中的元素是按他们在容器中的存储位置来顺序保存和访问的。关联式容器也是⽤来存储数据的与序列式容器不同的是关联式容器逻辑结构通常是⾮线性结构两个位置有紧密的关联关系交换⼀下他的存储结构就被破坏了。顺序容器中的元素是按关键字来保存和访问的。关联式容器有map/set系列和unordered_map/unordered_set系列。map和set底层是红⿊树红⿊树是⼀颗平衡⼆叉搜索树。set是key搜索场景的结构map是key/value搜索场景的结构。set系列的使⽤set和multiset参考⽂档参考文档set类的介绍set的声明如下T就是set底层关键字的类型set默认要求T⽀持⼩于⽐较如果不⽀持或者想按⾃⼰的需求⾛可以⾃⾏实现仿函数传给第⼆个模版参数set底层存储数据的内存是从空间配置器申请的如果需要可以⾃⼰实现内存池传给第三个参数。⼀般情况下我们都不需要传后两个模版参数。set底层是⽤红⿊树实现增删查效率是O(logN) 迭代器遍历是⾛的搜索树的中序所以是有序的。template class T, // set::key_type/value_type class Compare lessT, // set::key_compare/value_compare class Alloc allocatorT // set::allocator_type class set;set的构造和迭代器set的构造我们关注以下⼏个接⼝即可。set的⽀持正向和反向迭代遍历遍历默认按升序顺序因为底层是⼆叉搜索树迭代器遍历⾛的中序⽀持迭代器就意味着⽀持范围forset的iterator和const_iterator都不⽀持迭代器修改数据修改关键字数据破坏了底层搜索树的结构。// empty (1) ⽆参默认构造 explicit set (const key_compare comp key_compare(), const allocator_type alloc allocator_type()); // range (2) 迭代器区间构造 template class InputIterator set (InputIterator first, InputIterator last, const key_compare comp key_compare(), const allocator_type allocator_type()); // copy (3) 拷⻉构造 set (const set x); // initializer list (5) initializer 列表构造 set (initializer_listvalue_type il, const key_compare comp key_compare(), const allocator_type alloc allocator_type()); // 迭代器是⼀个双向迭代器 iterator - a bidirectional iterator to const value_type // 正向迭代器 iterator begin(); iterator end(); // 反向迭代器 reverse_iterator rbegin(); reverse_iterator rend();set的增删查Member types key_type - The first template parameter (T) value_type - The first template parameter (T) // 单个数据插⼊如果已经存在则插⼊失败 pairiterator,bool insert (const value_type val); // 列表插⼊已经在容器中存在的值不会插⼊ void insert (initializer_listvalue_type il); // 迭代器区间插⼊已经在容器中存在的值不会插⼊ template class InputIterator void insert (InputIterator first, InputIterator last); // 查找val返回val所在的迭代器没有找到返回end() iterator find (const value_type val); // 查找val返回Val的个数 size_type count (const value_type val) const; // 删除⼀个迭代器位置的值 iterator erase (const_iterator position); // 删除valval不存在返回0存在返回1 size_type erase (const value_type val); // 删除⼀段迭代器区间的值 iterator erase (const_iterator first, const_iterator last); // 返回⼤于等val位置的迭代器 iterator lower_bound (const value_type val) const; // 返回⼤于val位置的迭代器 iterator upper_bound (const value_type val) const;insert和迭代器遍历使⽤样例#includeiostream #includeset using namespace std; int main() { // 去重升序排序 setint s; // 去重降序排序给⼀个⼤于的仿函数 //setint, greaterint s; s.insert(5); s.insert(2); s.insert(7); s.insert(5); //setint::iterator it s.begin(); auto it s.begin(); while (it ! s.end()) { // error C3892: “it”: 不能给常量赋值 // *it 1; cout *it ; it; } cout endl; // 插⼊⼀段initializer_list列表值已经存在的值插⼊失败 s.insert({ 2,8,3,9 }); for (auto e : s) { cout e ; } cout endl; setstring strset { sort, insert, add }; // 遍历string⽐较ascll码⼤⼩顺序遍历的 for (auto e : strset) { cout e ; } cout endl; }find和erase使⽤样例#includeiostream #includeset using namespace std; int main() { setint s { 4,2,7,2,8,5,9 }; for (auto e : s) { cout e ; } cout endl; // 删除最⼩值 s.erase(s.begin()); for (auto e : s) { cout e ; } cout endl; // 直接删除x int x; cin x; int num s.erase(x); if (num 0) { cout x 不存在 endl; } for (auto e : s) { cout e ; } cout endl; // 直接查找在利⽤迭代器删除x cin x; auto pos s.find(x); if (pos ! s.end()) { s.erase(pos); } else { cout x 不存在 endl; } for (auto e : s) { cout e ; } cout endl; // 算法库的查找 O(N) auto pos1 find(s.begin(), s.end(), x); // set⾃⾝实现的查找 O(logN) auto pos2 s.find(x); // 利⽤count间接实现快速查找 cin x; if (s.count(x)) { cout x 在 endl; } else { cout x 不存在 endl; } return 0; }#includeiostream #includeset using namespace std; int main() { std::setint myset; for (int i 1; i 10; i) myset.insert(i * 10); // 10 20 30 40 50 60 70 80 90 for (auto e : myset) { cout e ; } cout endl; // 实现查找到的[itlow,itup)包含[30, 60]区间 // 返回 30 auto itlow myset.lower_bound(30); // 返回 60 auto itup myset.upper_bound(60); // 删除这段区间的值 myset.erase(itlow, itup); for (auto e : myset) { cout e ; } cout endl; return 0; }multiset和set的差异multiset和set的使⽤基本完全类似主要区别点在于multiset⽀持值冗余那么insert/find/count/erase都围绕着⽀持值冗余有所差异#includeiostream #includeset using namespace std; int main() { // 相⽐set不同的是multiset是排序但是不去重 multisetint s { 4,2,7,2,4,8,4,5,4,9 }; auto it s.begin(); while (it ! s.end()) { cout *it ; it; } cout endl; // 相⽐set不同的是x可能会存在多个find查找中序的第⼀个 int x; cin x; auto pos s.find(x); while (pos ! s.end() *pos x) { cout *pos ; pos; } cout endl; // 相⽐set不同的是count会返回x的实际个数 cout s.count(x) endl; // 相⽐set不同的是erase给值时会删除所有的x s.erase(x); for (auto e : s) { cout e ; } cout endl; return 0; }349. 两个数组的交集 - 力扣LeetCodeclass Solution { public: vectorint intersection(vectorint nums1, vectorint nums2) { setint s1(nums1.begin(), nums1.end()); setint s2(nums2.begin(), nums2.end()); // 因为set遍历是有序的有序值依次⽐较 // ⼩的相等的就是交集 vectorint ret; auto it1 s1.begin(); auto it2 s2.begin(); while(it1 ! s1.end() it2 ! s2.end()) { if(*it1 *it2) { it1; } else if(*it1 *it2) { it2; } else { ret.push_back(*it1); it1; it2; } } return ret; } };142. 环形链表 II - 力扣LeetCode数据结构初阶阶段我们通过证明⼀个指针从头开始⾛⼀个指针从相遇点开始⾛会在⼊⼝点相遇理解证明都会很⿇烦。这⾥我们使⽤set查找记录解决⾮常简单⽅便这⾥体现了set在解决⼀些问题时的价值完全是降维打击。class Solution { public: ListNode *detectCycle(ListNode *head) { setListNode* s; ListNode* cur head; while(cur) { auto ret s.insert(cur); if(ret.second false) return cur; cur cur-next; } return nullptr; } };