C++的STL学习笔记

简介: C++的STL学习笔记

vetor(数组)

迭代器

迭代器就相当于STL中的指针,按照定义方式,可以分为下面四类:

  • 正向迭代器:容器类名::iterator 迭代器名; begin(); end();
  • 常正向迭代器:容器类名::const_iterator 迭代器名; cbegin(); cend();
  • 反向迭代器:容器类名::reverse_iterator 迭代器名; rbegin(); rend();
  • 常反向迭代器:容器类名::const_reverse_iterator 迭代器名; crbegin(); crend();

迭代器用法示例:

通过迭代器可以读取它指向的元素,*迭代器名就表示迭代器指向的元素。

  • 对正向迭代器进行++操作时,迭代器会指向容器中的后一个元素;
  • 反向迭代器进行++操作时,迭代器会指向容器中的前一个元素;
#include<vector>
#include<iostream>
using namespace std;
int main(){
  vector<int> v; //v是存放int类型变量的可变长数组,开始时没有元素
    for(int n = 0; n < 5; n++)
        v.push_back(n); //push_back函数在vector容器尾部添加一个元素
    
    //定义正向迭代器
    vector<int>::itertor i; 
    for(i = v.begin(); i != v.end(); ++i){ //用迭代器遍历容器
        cout << *i << " "; //*i 就是迭代器i指向的元素
        *i *= 2; //每个元素变为原来的2倍
    }
    cout << endl;
    
    //定义常正向迭代器
    for(vector<int>::const_itartor i = v.cbegin(); i != v.cend(); ++i) 
        cout << *i << " ";
    
    //定义反向迭代器
    for(vector<int>::reverse_itartor i = v.rbegin(); i != v.rend(); ++i) 
        cout << *i << " ";
    
    //定义反向迭代器
    for(vector<int>::const_reverse_itartor i = v.crbegin(); i != v.crend(); ++i) 
        cout << *i << " ";
    return 0;
}

程序输出结果:

0 1 2 3 4
0 2 4 6 8
8 6 4 2 0
8 6 4 8 0

第12行和第23行相当如下:

CDemo CDemo::operator++ ()
{  //前置++
    ++n;
    return *this;
}
CDemo CDemo::operator ++(int k)
{  //后置++
    CDemo tmp(*this);  //记录修改前的对象
    n++;
    return tmp;  //返回修改前的对象
}

按照功能分类:

容器 迭代器功能
vector 随机访问
deque 随机访问
list 双向
set/multiset 双向
map/multimap 双向
stack 不支持迭代器
queue 不支持迭代器
priority_queue 不支持迭代器

例如,vector的迭代器是随机迭代器,因此遍历vector容器有以下几种做法。【实例】遍历vector容器。

#include<iostream>
#include<vector>
using namespace std;
int main()
{
    vector<int> v(100); //v被初始化成有100个元素
    for(int i = 0; i < v.size(); i++) //size返回元素个数
        cout << v[i]; //像普通数组一样使用vector容器
    vector<int>::iterator i;
    
    //用于双向迭代器,双向迭代器不支持 “<”进行比较
    for(i = v.begin(); i != end(); i++) //用!=比较两个迭代器
        cout << *i ;
    
    //用于单向迭代器
    for(i = v.begin(); i < v.end(); i++) //用 < 比较两个迭代器
        cout << *i;
    i = v.begin();
    while(i < v.end()){//间隔一个输出
        cout << *i;
        i += 2; //随机访问迭代器支持 “+= 整数” 的操作
    }
}

迭代器的辅助函数

STL中有用于操作迭代器的三个函数模板,它们是:

advance(p, n);    //使迭代器p向前或向后移动元素
distance(p, q);   //计算两个迭代器之间的距离,即迭代器p经过多少次++操作后和迭代器q相等。如果调用p时已经指向q的后面,则这个函数会陷入死循环。
iter_swap(p, q);  //用于交换两个迭代器p、q指向的值

实际函数操作如下:

#include<list>
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
    int a[5] = {1, 2, 3, 4, 5};
    list<int> lst(a, a + 5);
    list<int>::iterator p = list.begin();
    advance(p, 2);  //p向后移动两个元素,指向3
        cout << "1)" << *p << endl; //输出1)3
    advance(p, -1); //p向前移动一个元素,指向2
      cout << "2)" << *p << endl; //输出2)2
  
    list<int>::iterator q = list.end();
      q--;  //q指向 5
    cout << "3)" << distance(p, q) << endl; //输出 3)3
    iter_swap(p, q);  //交换 2 和 5
      cout << "4)";
    for(p = lst.begin(); p != lst.end(); p++)
        cout << *p << ednl;
    return 0;
}

程序输出结果:

1)3
2)2
3)3
4)1 5 3 4 2

vetor的定义和特性

在c++中,vector是一个动态数组容器,可以存储一系列相同类型的元素。它是标准库==== 中定义的模板类。

vetor的定义和结构非常简单,它由以下几个重要的部分组成:

模板类声明: vetor是一个模板类,因此在使用之前需要包含头文件.声明一个vetor对象的通用语法如下:

vetor<T> vec; //这里的T是要存储在vector中的元素类型
//T可以为int、char、double......

容器大小: vector是一个动态数组,可以根据需要自动调整大小。它会根据元素的数量动态分配内存空间。

元素访问: 可以通过索引来访问vector中的元素。索引从0开始,最后一个元素的索引是size() - 1。可以使用[ ]运算符或at()函数来访问元素

元素添加和删除: 可以使用push_back()函数在vector中元素的数量,使用empty()函数检查vector是否为空。还可以使用resize()函数调整vector的大小

迭代器: vector提供了迭代器,可以用于遍历容器中的元素,可以使用begin()函数获取一个元素的迭代器,使用end() 函数获取指向最后一个元素之后位置的迭代器。

vector的常用函数

push_back(): 将元素添加到vector的末尾

void push_back(const T& value);

pop_back(): 删除vector末尾的元素

void pop_back();//一定要保证vector非空

begin() 和 end(): 返回指向vector第一个元素和最后一个元素之后位置的迭代器

例子:

vector<int> vec = {10, 20, 30};
for(auto it = vec.begin(); it != vec.end(); ++it){
    cout << *it << " ";
}

vector排序去重

排序: 要对vector进行排序,可以使用标准库中的sort函数,该函数位于头文件中。

#include<algorithm>
vector<T> vec = {. . .};
//这里T是vector 中元素的类型
sort(vec.begin(),vec.end());
//sort函数接受两个迭代器参数,表示要排序的范围
//vec.begin()返回指向vector第一个元素的迭代器
//vec.end()返回指向最后一个元素之后位置的迭代器

示例

#include<iostream>
#include<vector>
#include<algorlthm>
int main(){
  vector<int> vec = {5, 2, 8, 1, 9};
    sort(vec.begin(),vec.end());
    for(const auto& num : vec){
        cout << num << " ";
    }
    return 0;
}

输出

1 2 5 8 9

去重: 要去除vector中的重复元素,可以使用unique函数。该函数位于头文件中。

#include<algorithm>
vector<T> vec = { . . .};
sort(vec.begin(),vec.end());
auto last = =unique(vec.begin(),vec.end());
vec.erase(last,vec.end());

首先,需要对vector进行排序,以便相同的元素相邻。然后,,unique函数将重复的元素移动到vector的末尾,并返回一个指向重复的迭代器。最后,可以使用vec.erase函数将重复元素从vector中删除

示例:

#include<iostream>
#include<vector>
#include<algorlthm>
int main(){
  vector<int> vec = {2, 1, 3, 2, 4, 1, 5, 4};
    sort(vec.begin(),vec.end());
    auto last = =unique(vec.begin(),vec.end());
  vec.erase(last,vec.end());
    
    for(const auto& num : vec){
        cout << num << " ";
    }
    return 0;
}
//注意vector中的重复元素被去除,只保留了不重复的元素。

输出:

1 2 3 4 5

queue(队列)

queue队列

queue是一种先进后出(FIFO)的数据结构

queue提供了一组函数来操作和访问元素,但它的功能相对简单

queue的定义和结构如下:

template<class T, class Container = deque<T>>
class queue;
//T:表示存储在queue中的元素的类型
//Container:表示底层容器的类型,默认为deque。也可以使用其他容器类型,如list

queue的内部实现使用了底层容器来存储元素,并且只能通过特定的函数来访问和操作元素,以下是一些queue的常用函数:

#include<queue>             //queue容器的头文件
queue<int> q;             //声明
struct node {int x, y, z;}; 
queue<node> qq;             //声明一个结构体类型的队列容器
q.push(111);              //将111插入队尾 O(1)
q.pop();                //将队头元素删除 O(1)
int x = q.front();            //返回队头元素 O(1)
int y = q.back();           //返回队尾元素 O(1)

priority_queue按照元素从大到小排序

tempplate<class T, class Container = vector<T>,
     class Compare  = less<typename //比较函数
             Container::value_type>>
class priority_queue;
//T:表示存储在queue中的元素的类型
//Container:表示底层容器的类型,默认为deque。也可以使用其他容器类型,如deque
//Compare:表示元素之间的比较函数对象的类型,默认为less,即按照元素的值进行比较

priority_queue的内部实现使用了底层容器来存储元素,并且只能通过特定的函数来访问和操作元素。以下是一些priority_queue的常用函数:

函数 描述 时间复杂度
push(x) 将元素x插入到优先队列中 O(logN)
pop() 弹出有限队列中的顶部元素 O(logN)
top() 返回优先队列中的顶部元素 O(1)
empty() 检查优先队列是否为空 O(1)
size() 返回优先队列中元素的个数 O(1)

几种优先队列修改比较函数的方法

struct Compare{
    bool operator()(int a, int b){
        //自定义的比较函数,按照逆序排列
        return a > b;
    }
}
int main(){
    priority_queue<int, vector<int>,Compare> pq;
    auto compare = [](int a, int b){
        //自定义的比较函数,按照逆序排序
        return a > b;
    }
    priority_queue<int, vector<int>,Compare> pq(compare);
}

如果优先队列中的元素类型比较简单,可以直接使用

greater来修改比较方法.

priority_queue<int, vector, greater> pq;

greater函数对象定义在头文件中

deque双端队列

deque(双端队列)是一个容器,它允许在两端进行高效的插入和删除操作。

template<class T, class Allocator = allocator<T>
class deque;
//T表示存储在deque中的元素的类型
//Allocator:表示用于分配内存的分配器类型,默认为allocator
函数 描述 时间复杂度
push_back(x) 在尾部插入元素x 平摊O(1)
push_front(x) 在头部插入元素x 平摊O(1)
pop_back() 弹出尾部元素 平摊O(1)
pop_front() 弹出头部元素 平摊O(1)
front() 返回头部元素 O(1)
back() 返回尾部元素 O(1)
empty() 检查deque是否为空 O(1)
size() 返回deque中元素的个数 O(1)
clear() 清空deque中所有的元素 O(N)
insert(pos,x) 在指定位置pos插入元素 平摊O(N)
erase(pos) 移除指定位置pos处的元素 平摊O(N)
erase(first,last) 移除(first,last)范围内的元素 平摊O(N)

set

set集合

set 是一种容器,用于存储一组唯一的元素,并按照一定的排序规则进行排序。set中的元素是按照升序排序的,默认情况下,它使用元素的比较运算符(<)来进行排序。

set的定义结构如下:

template<class key, class Compare = less<key>,
    class Allocator = allocator<key>>
class set;
  • key: 表示存储在set中的元素的类型。
  • Compare: 表示元素之间的比较函数对象的类型,默认为less,即按照元素的值进行比较。
  • Allcoator: 表示用于分配内存的分配器类型,默认为allocator.

set的内部实现使用了红黑树(一种自平衡的二叉搜索树)来存储元素,并爆出元素的有序性,这使得在set中插入、删除和查找元素的时间复杂度都是对数时间,即O(log n).

set中的元素是唯一的,即不允许重复的元素存在,当插入一个重复的元素时,set会自动忽略该元素。

set函数

s.insert(key);      //向set中插入一个元素key。
s.erase(key);     //从set中移除指定的元素key。
s.find(key);      //查找set中是否存在指定的元素key,如果存在则返回指向该元素的迭代器,否则返回set::end()。
s.lower_bound(key);   //返回指向第一个不小于给定键值key的元素的迭代器。
s.upper_bound(key);   //返回指向第一个大于给定键值key的元素的迭代器。
s.equal_range();        //返回一个返回,其中包含所有给定的元素
s.size();               //返回集合中元素的数量
s.empty();              //检查集合是否为空
s.clear();        //清空set中的所有元素。
s.begin();        //指向集合中最小元素的迭代器
s.end();        //指向集合中最大元素的下一个位置的迭代器
s.rebegin();            //返回指向集合末尾位置的逆向迭代器
s.rend();               //返回指向集合起始位置的逆向迭代器
s.swap();               //交换两个集合
s.count(key);     //返回set中与指定元素key相等的元素的个数,由于set中不允许有重复的元素,因此返回值只能是0或1。

修改set比较方法的常见手段,后面的multiset类似

#include<iostream>
#include<set>
using namespace std;
int main(){
  set<int,greater<int>> mySet;
    
    mySet.insert(25);
    mySet.insert(17);
    mySet.insert(39);
    mySet.insert(42);
    
    for(const auto& elem : mySet){
        cout << elem << " ";
    }
    cout << endl;
    
    return 0;
}
#include<iostream>
#include<set>
using namespace std;
struct MyCompare{
    bool operator()(const int& a, const int& b) const{
        //自定义比较逻辑
        return a > b;//改为逆序
    }
};
int main(){
    set<int, MyCompare> mySet; //mYCompare是仿函数
    
    mySet.inster(25);
    mySet.inster(17);
    mySet.inster(39);
    mySet.inster(42);
    
    for(const auto& elem : mySet){
        cout << elem << " ";
    }
    cout << endl;
    
    return 0;
}

multiset多重集合

multiset 是一种容器,它与set类似,用于存储一组元素,并按照一定的排序规则进行排序。

不同之处在于,multiset容器允许存储重复的元素

multiset的定义和结构与set类似,如下所示:

template <class Key, class Compare = less<key>,
      class Allocator = allocator<key>>
class multiset;
  • key: 表示存储在set中的元素的类型。
  • Compare: 表示元素之间的比较函数对象的类型,默认为less,即按照元素的值进行比较。
  • Allcoator: 表示用于分配内存的分配器类型,默认为allocator.

multiset的内部实现也使用红黑树来存储元素,并保持元素的有序性。与set不同的是,multiset中的元素可以重复出现

multiset函数

s.insert(key);      //向set中插入一个元素key。
s.erase(key);     //从set中移除指定的元素key。
s.find(key);      //查找set中是否存在指定的元素key,如果存在则返回指向该元素的迭代器,否则返回set::end()。
s.lower_bound(key);   //返回指向第一个不小于给定键值key的元素的迭代器。
s.upper_bound(key);   //返回指向第一个大于给定键值key的元素的迭代器。
s.size();               //返回集合中元素的数量
s.empty();              //检查集合是否为空
s.clear();        //清空set中的所有元素。
s.begin();        //指向集合中最小元素的迭代器
s.end();        //指向集合中最大元素的下一个位置的迭代器
s.rebegin();            //返回指向集合末尾位置的逆向迭代器
s.rend();               //返回指向集合起始位置的逆向迭代器
s.swap();               //交换两个集合
s.count(key);     //返回set中与指定元素key相等的元素的个数,由于set中不允许有重复的元素,因此返回值只能是0或1。

unordered_set无序集合

unordered_set 是一种容器,用于存储一组唯一的元素,并且没有特定的顺序。unorderde_set容器使用哈希表来实现元素的存储和访问,因此元素的插入、删除和查找的时间复杂度都是常数时间,即O(1)。

unordered_set的定义和结构如下:

template <class key, class Hash = Hash<key>,
      class keyEqual = equal_to<key>,
      class Allocator = allocator<key>>
class unordered_set;
  • key: 表示存储在set中的元素的类型。
  • Hash: 表示用于计算元素哈希值的哈希函数对象的类型,默认为hash,使用key类型默认哈希函数
  • keyEqual: 表示用于比较元素是否相等的函数对象的类型,默认为equal_to,使用key类型的默认相等比较函数
  • Allcoator: 表示用于分配内存的分配器类型,默认为allocator.
  • unordered_set 中的元素是唯一的,即不允许重复的元素的存在。当插入一个重复的元素时,unoredered_set会自动忽略该元素。

unordered_set函数

s.insert(key);      //向set中插入一个元素key。
s.erase(key);     //从set中移除指定的元素key。
s.find(key);      //查找set中是否存在指定的元素key,如果存在则返回指向该元素的迭代器,否则返回set::end()。
s.count(key);     //返回set中与指定元素key相等的元素的个数,由于set中不允许有重复的元素,因此返回值只能是0或1。
s.size();               //返回集合中元素的数量

代码示例:

#include <iostream>  
#include <set>  
  
using namespace std;  
  
int main() {  
    set<int> mySet;  
      
    // 插入元素  
    mySet.insert(5);  
    mySet.insert(2);  
    mySet.insert(8);  
    mySet.insert(2); // 重复元素,不会被插入,因为set自动去重  
      
    // 遍历集合  
    cout << "Set elements: ";  
    for (const auto& elem : mySet) {  
        cout << elem << " ";  
    }  
    cout << endl; // 应该输出:2 5 8(注意顺序可能因实现而异,但一定是升序)  
      
    // 查找元素  
    int searchValue = 5;  
    auto it = mySet.find(searchValue);  
    if (it != mySet.end()) {  
        cout << searchValue << " found in the set." << endl;  
    } else {  
        cout << searchValue << " not found in the set." << endl;  
    }  
      
    // 移除元素  
    int removeValue = 2;  
    mySet.erase(removeValue); 
      
    // 再次遍历集合  
    cout << "Set elements after removal: ";  
    for (const auto& elem : mySet) {
        cout << elem << " ";  
    }  
    cout << endl; // 应该输出剩余的元素,例如:5 8(顺序可能因实现而异)  
      
    // 清空集合  
    mySet.clear();  
      
    // 检查集合是否为空  
    if (mySet.empty()) {  
        cout << "Set is empty." << endl;  
    } else {  
        cout << "Set is not empty." << endl;  
    }  
      
    return 0;  
}

set板子

#define fi first
#definese second
constint INF  Xfffffff:
constint mod = 1e9 + 7;
int N = 2e5 + 10;
void Solved(){
  set<int> st;
    for(int i=10;i>0;i--) st.insert(i);
  
    //for(const auto&i:st) cout << i<< endl;
  for(set<int>::iterator it = st.begin();it != st.end();it ++ ){
         cout << *it << endl;
    }
    signed main(void){
        IOS
    int ALL =1:
    cin >>ALL;
        while(ALL --) Solved();
        // cout<< fixed;/制以小数形式显示
        //cout<< setprecision(n)://保留n位小数
    return 0;
    }

stack(栈)

stack的定义和结构

stack是一种后进先出(LIFO)的数据结构,使用前需要包含头文件。

stack提供了一组函数来操作和访问元素,但它的功能相对较简单。

stack的定义和结构如下:

template <class T, class CONtainer = deque<T>>
class stack;

stack的常用函数

stack<int> stk;
stk.push(x);//将x加入栈中,即入栈操作 
stk.pop();//出栈操作(删除栈顶),只是出栈,没有返回值
stk.top();//返回第一个元素(栈顶元素)
stk.size();//返回栈中的元素个数
stk.empty();//当栈为空时,返回 true

stack不能遍历

如果将数组的元素依次放入栈,再依次取出,则可以将数组翻转

代码示例:

#include <iostream>  
#include <stack>  
  
using namespace std;  
  
int main() {  
    stack<int> myStack;  
      
    // 向栈中插入元素  
    myStack.push(10);  
    myStack.push(20); 
  myStack.push(30); 
  myStack.push(40);  
      
    //获取栈顶元素
  cout << "栈顶元素:" << myStack.top() << endl;
  
  //弹出栈顶元素
  myStack.pop();
  
  //再次获取栈顶元素
  cout << "弹出一个元素后的栈顶元素:" << myStack.top() << endl;
   
      
    // 检查栈是否为空  
    if (myStack.empty()) {  
        cout << "栈为空" << endl;  
    } else {  
        cout << "栈不为空" << endl;  
    }  
    
    //获取栈的大小
  cout << "栈的大小:" << myStack.size() << endl;
   
    return 0;  
}

map(映射)

map容器是一个键值对 key - value 的映射。其内部实现是一棵以key为关键码的红黑树。map的key和value可以是任意类型,其中key必须定义“小于号”运算符

map的定义和结构如下:

template<class key, class T, class Compare = less<key>,
     class Allocator = allocator<pair<const key, T>>>
class map;
map<long long, bool> vis;
 map<string, int> hash;
 map<pair<int, int>, vector<int> > test;

在很多时候,map容器被当作Hash表使用,建立从复杂信息key(如字符串)到简单信息value(如一定范围内的整数)的映射。

因为map基于平衡树实现,所以它的大部分操作的时间复杂度都在O(log n)级别,比Hash函数实现的传统Hash表慢。

map函数(常用)

map<string, int> h;
undered_map<string, int> operator;
h.insert()        //插入键值对到map中。有多种形式的insert()函数重载,可以接受单个键值对、迭代器范围或者初始化列表作为参数。
h.erase()       //从map中删除指定键的键值对。有多种形式的erase()函数重载,可以接受单个键、迭代器范围或者删除满足特定条件的键值对。
h.find()        //查找指定键的位置,并返回指向该位置的迭代器。如果键不存在,则返回map的end()迭代器。
h.count()       //返回指定键在map中的个数。由于map中的键是唯一的,因此返回值只能是0或1。
              //判断key是否存在
h.size()        //返回元素个数
h.begin()       //返回元素个数
h.end()         //返回元素个数
h.empty()       //检查map是否为空。如果map为空,则返回true,否则返回false。
h.clear()       //清空map,删除所有的键值对。
h.lower_bound()     //返回指向第一个不小于指定键的元素位置
h.upper_bound()     //返回指向第一个大于指定键的元素位置

multimap

multimap是一种关联容器,类似于map,但允许存储多个具有相同键值对

multimap容器根据键来自动进行排序,并且可以通过键快速查找对应的值

multimap定义结构:

template<class key, class T, class Compare = less<key>,
     class Allocator = allocator<pair<const key, T>>>
class multimap;

函数:

map<string, int> h;
undered_map<string, int> operator;
h.insert()        //插入键值对到map中。有多种形式的insert()函数重载,可以接受单个键值对、迭代器范围或者初始化列表作为参数。
h.erase()       //从map中删除指定键的键值对。有多种形式的erase()函数重载,可以接受单个键、迭代器范围或者删除满足特定条件的键值对。
h.find()        //查找指定键的位置,并返回指向该位置的迭代器。如果键不存在,则返回map的end()迭代器。
h.count()       //返回指定键在map中的个数。由于map中的键是唯一的,因此返回值只能是0或1。
h.size()        //返回map中键值对的个数。
h.empty()       //检查map是否为空。如果map为空,则返回true,否则返回false。
h.clear()       //清空map,删除所有的键值对。
operator[]        //访问指定键的值。如果键存在,则返回对应的值;如果键不存在,则会插入一个新的键值对,关联的值被默认构造。

如果多次查找的key不存在,当时间一长,容器里会多很多无用的0值,占用内存。

在使用 [ ] 操作符之前,最好先用find函数检查key的存在性

使用map容器的示例代码

#include<iostream>
#include<map>
using namespace std;
int main(){
    //创建并初始化map
    map<int, string> myMap = {{1,"Apple"},{2,"Banana"},{3,"Orange"}};
    
    //插入元素
    myMap.insert(make_pair(4,"Grapes"));
    
    //查找和访问元素
    cout << "Value at key 2: " << myMap[2] << endl;
    
    //遍历并打印map中的元素
    for(const auto& pair : myMap){
        cout << "key: " << pair.first << ",Value: " << pair.cond << endl;
    }
    
    //删除元素
    myMap.erase(3);
    
    //判断元素是否存在
    if(myMap.count(3) == 0){
        cout << "key 3 not found." << endl;
    }
    
    //删除元素
    myMap.erase(3);
    
    //判断元素是否存在
    if(myMap.count(3) == 0){
        cout << "key 3 not found." << endl;
    }
    
    //清空map
    myMap.clear();
    
    //判断map是否为空
    if(myMap.empty()){
        cout << "Map is empty." << endl;
    }
    return 0;
}

使用multimap容器的示例代码

#include<iostream>
#include<map>
using namespace std;
int main(){
    //创建并初始化multimap
    map<int, string> myMultimap = {{1,"Apple"},{2,"Banana"},{3,"Orange"}};
    
    //插入元素
    myMultimap.insert(make_pair(4,"Grapes"));
    
    //查找和访问元素
    auto range = myMultimap.equal_range(2);
    for(auto it = rang.first; it != range.second; +it){
      cout << "key:" << it->first << ",Value:" << it->second <<endl;
    }
    
    //遍历并打印Multimap中的元素
    for(const auto& pair : myMultimap){
        cout << "key: " << pair.first << ",Value: " << pair.cond << endl;
    }
    
    //删除元素
    myMultimap.erase(3);
    
    //判断元素是否存在
    if(myMultimap.count(3) == 0){
        cout << "key 3 not found." << endl;
    }
    
    //清空map
    myMultimap.clear();
    
    //判断map是否为空
    if(myMultimap.empty()){
        cout << "Map is empty." << endl;
    }
    return 0;
}

使用unordered_map容器的示例代码

#include <iostream>
#include <unordered_map>
#include <string>
int main() {
    // 创建一个unordered_map容器
    std::unordered_map<int, std::string> myMap;
    // 插入键值对
    myMap.insert({1, "one"});
    myMap.insert({2, "two"});
    myMap[3] = "three";
    // 访问值
    std::cout << myMap[1] << std::endl;  // 输出: one
    // 检查键是否存在
    if (myMap.count(2) > 0) {
        std::cout << "Key 2 exists." << std::endl;
    }
    // 遍历键值对
    for (const auto& pair : myMap) {
        std::cout << pair.first << ": " << pair.second << std::endl;
    }
    
    // 删除键值对
    myMap.erase(3);
    return 0;
}

bitset

bitset可看作一个多位二进制,每8位占用一个字节,相当于采用了状态压缩的二进制数组,并支持基本的位运算。在估算程序运行的时间时,我们一般以32位整数的运算次数位基准,因此n位bitset执行一次位运算的复杂度可视为n/32,效率较高

bitset声明时可初始化,可用unsigned或string型来赋值。当用unsing long值作为bitset对象的初始值时,该值将转化为二进制的位模式。 而bitset对象中的位集作为这种位模式的副本。如果bitset类型长度大于unsigned long值的二进制位数,则其余的高阶位置为0如果bitet类型长度小于unsigned long值的二进制位数,则只使用unsigned值中的低阶位,超过bitet类型长度的高阶位将被丢弃

操作符

~s : 返回对bitset s按位取反的结果

&,|,^ : 返回丢两个位数相同的bitset执行按位与、或、异或运算的结果

“>>”,“<<”: 返回把一个bitset右移、左移若干位的结果

==,!= : 比较两个bitset代表的二进制数是否相等

bitset支持[ ]操作符,bitset[i]表示二进制的第i位,可以赋值或取值。

//头文件
#include<bitset>
//声明/初始化
bitset<n> s;      //表示一个n位的二进制数,每位都是0
bitset<n> s(m)      //表示一个n位的二进制数,位m的二进制表示
string s;
bitset<n> s(str)    //将string行转化位bitset型,前提时str为01字符串
bitset<n> s(s, a, b)  //将字符串s的下标a开始,长度为b的子字符串与bitset进行转换

bitset和string是反向转化的,但仅限与string型小于bitset位数的部分,超出bitset位数的部分将被抛弃,在bitset位数内,string反向转换位bitset型。

bitset与整型数转换时,bitset从第0位开始存储整型数二进制下的最低位,当整型数的二进制位数超过bitset位数时,超出部分将不会被读进。

遇到整型数或者string型转bitset型时,当整型数二进制或string长度小于bitset时,bitset的高阶补0。

举个例子:

整型数15,二进制为0100,0001,正常转换为8位bitset型为1000,0010, string型转换同理

但是如果0100,0001转换为4位bitset型则为: 1000,因为bitset是从15的二进制的第0位开始储存

string型的"01000001"转换位4位bitset型则为: 0010,因为bitset是将string的前四位反向读取,而string的后四位抛弃了

常用内置函数

b.any()           //b中是否存在为1的二进制位
b.none()          //b中不存在置为1的二进制位
b.count()         //b中置为1的二进制位的个数
b.size()          //b中二进制位的个数
b.test(x)         //b中在x处的二进制是否位1?
b.set()           //把b中所有二进制位都置为1
b.set(x)          //把b中在x处的二进制位置为1
b.reset()         //把b中所有二进制位都置为0
b.reset(x)          //把b中在x处的二进制位置为0
b.flip()          //把b中所有二进制位逐位取反
b.flip(x)         //把b中在x处的二进制位取反
b.to_uiong()        //用b中同样的二进制位返回一个unsigned long值
cout << b << endl;      //直接输出b

srring(字符串)

string字符串,是c++中的一个类,也可以看作是一个字符串容器,可以说是非常好用。它可以直接将两个字符串进行比较。另外其内置函数功能也是十分齐全。

#include<cstring>
string str;
str.push_back('s');//在末尾添加字符's'
str.pop_back();//删除最后一个元素
str.front();//返回第一个元素
str.back();//返回最后一个元素
str.clear();//清空容器
str.empty();//容器为空时返回true,否则返回flase
str.erase(3);//删除str[3]~str[n - 1],返回str
str.erase(2, 3);//删除str[2]~str[2+3-1]
str.erase(str.begin());//删除指向的元素, 返回迭代器, 指向下一元素
str.erase(str.begin(), str.end());//删除区间内的元素, 返回迭代器, 指向下一元素
str.find('s');//返回字符 ‘s’ 在 str 中首次出现的位置
str.find('s', 2);//返回字符 ‘s’ 在 str[2]~str[n-1] 中首次出现的位置
str.find(ch);//返回字符串 ch 在 str 中首次出现的位置
str.find(ch, 4);//返回 ch 在 str[4]~str[n-1] 中首次出现的位置
str.find(ch, 4, 3);//返回 ch[0]~ch[3-1] 在 str[4]~str[n-1] 中首次出现的位置
str.find(str1);//返回 str1 在 str 中首次出现的位置
str.find(str1, 2);//返回 str1 在 str[2]~str[n-1] 中首次出现的位置
str.substr(2);//返回 str[2]~str[n-1], 不对 str 进行操作
str.substr(2,3);//返回 str[2]~str[2+3-1]

stringstream

srd::stringstream 是C++标准库中的一个类,它提供了字符串流的功能,可以将数据以字符串的形式进行输入和输出。std::stringstream 可以将各种类型的数据转换为字符串,并且可以从字符串中提取数据。

#include<iostream>
#include<algorithm>
#include<sstream>
using namespace std;
int main(){
    //1、创建一个对象,向对象输入字符串,输入字符串后直接进行字符串拼接
    stringstream ss;
    ss << str;
    ss1 << "fre";
    ss3 << "gre";
    cout << ss1.str() << edml;
    
    //2、创建时使用字符串初始化,进行字符串拼接时,首先把原本的字符串覆盖掉,之后再进行拼接。
    stringstream ss(str);
    
    //3、输出时需调用str()函数
    cout << ss.str() << endl;
    
    //4、利用stringstream去除字符串空格,streamstring 默认是以空格来分割字符串
    stringstream ss("2 dfjho 43");
    cout << ss.str() << endl;
    string str;
    while (ss >> str){
        cout << str << endl;
    }
    //5、利用 streamstring 指定字符分割字符串
    string source = "abc,123,<!>";
    stringstream ss(source);
    cout << ss.str() << endl;
  cout<< endl;
    string str;
    while (getline(ss, str, ',')){
        cout << str << endl;
    }
}
}

std::stringstream还提供了其他一些功能,如clear()函数用于重置字符串流的状态,str()函数用于获取字符串流的内容,以及seekg()seekp()函数用于设置读写位置。

std::stringstream对于将数据转换为字符串或从字符串中提取数据非常有用,尤其在需要处理字符串形式的数据时。

pair(二元组)

pair的定义和结构

在C++中,pair是一个模板类,用于表示一对值的组合。它位于<utility> 头文件中。

pair类的定义如下:

template<class T1, class T2>
struct pair{
    T1 first; //第一个值
    T2 second;  //第二个值
    
    //构造函数
    pair();
    pair(const T1& x, const T2& y);
    
    //比较运算符重载
    bool operator == (const pair& rhs) const;
    bool operator != (const pair& rsh) const;
    
    //其他成员函数的特征
    ......
}

C++内置二元组,其中包含两个元素,分别是first、second。在比较大小中,以第一元first尾第一关键字,第二元second尾第二关键字。

pair<int> a;                //a为int型的二元组
a.first = 1; a.second = 2;
pair<int, pair<int, int>> b;
b.first = 1;
b.second.first = 2; b.second.second = 3;

list

list的定义和结构

list是一种双向链表容器,它是标准模板库STL提供的一种序列容器,list容器以节点(node) 的形式存储元素,并使用指针将这些节点链接在一起,形成一个链表结构。

list容器的特点包括:

  • 双向性:每个节点都包含指向前一个节点和后一个节点的指针,因此可以在常数时间内在链表中的任意位置进行插入、删除和访问操作。
  • 动态大小:链表的大小可以根据需要动态扩展或收缩,不需要预先 指定容器的大小。
  • 不连续存储:链表中的节点可以在内存中的任意位置分布,不要求连续存储,因此插入和删除操作不会导致元素的移动
    list容器提供了一系列成员函数和迭代器来操作和访问链表中的元素,包括插入、删除、访问、反转等操作。可以使用迭代器来遍历链表中的元素。
    展示list容器
#include<iostream>
#include<list>
using namespace std;
int main(){
  list<int> myList;
    
    //在链表尾部插入元素
    myList.push_back(1);
    myList.push_back(2);
    myList.push_back(3);
    
    //在链表头部插入元素
    myList.push_front(0);
    
    //遍历链表并输出元素
    for(int num : myList){
        cout << num << " ";
    }
    cout << endl;
    
    return 0;
}
  • list常用函数
list<int> myList;
myList.push_back();   //将元素插入到链表的末尾
myList.push_front();  //将元素插入到链表的开头
myList.pop_back();    //移除链表末尾的元素
myList.pop_front();   //移除链表开头的元素
myList.size();      //返回链表中元素的个数
myList.empty();     //检查链表是否为空
myList.clear();     //清空链表的所有元素
myList.front();     //返回链表中第一个元素的引用
myList.back();      //返回链表中最后一个元素的引用
myList.begin();     //返回指向链表第一个元素的迭代器
myList.end();     //返回指向链表末尾的下一个位置的迭代器
myList.insert();    //在指定位置之前插入一个或多个元素
myList.erase();     //从链表中移除指定位置的一个或多个元素
  • 代码示例:
#include<bits/stdc++.h>
using namespace std;
int main()
{
    //创建一个List<int> 对象myList
    list<int> myList;
    
    //向myList尾部添加元素
    for(int i = 1; i <= 5; i++)
    {
        myList.push_back(i);
    }
    
    //从头到尾输出myList中的元素
    for(const auto &i : myList)
        cout << i << " ";
    cout << endl;
    
    //将myList中的元素反转
    reverse(myList.begin(), myList.end());
    
    for(const auto &i : myList)
        cout << i << " ";
    cour << endl;
    
    //在第一个元素的后一个位置加上元素0
    myList.insert(++myList.begin(), 0);
    
    for(const auto &i : myList)
        cout << i << " ";
      cout << endl;
    
    myList.erase(++ ++ myList.begin(), --myList.end());
    
    //输出myList的大小
    cout << myList.size() << "\n";
    
    //从头到位输出myList中的元素
    for(const auto &i : myList)
        cout << i << " ";
      cout << "\n";
    
    return 0;
}
  • 结果
1 2 3 4 5
5 4 3 2 1
5 0 4 3 2 1 
链表大小为:3
5 0

二分查找函数

lower_bound()

lower_bound() 函数定义在头文件中,其语法格式有 2 种,分别为:

//在 [first, last) 区域内查找不小于 val 的元素
ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last, const T& val);
//在 [first, last) 区域内查找第一个不符合 comp 规则的元素
ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last, const T& val, Compare comp);

其中,first 和 last 都为正向迭代器,[first, last) 用于指定函数的作用范围;val 用于指定目标元素;comp 用于自定义比较规则,此参数可以接收一个包含 2 个形参(第二个形参值始终为 val)且返回值为 bool 类型的函数,可以是普通函数,也可以是函数对象。

实际上,第一种语法格式也设定有比较规则,只不过此规则无法改变,即使用 < 小于号比较 [first, last) 区域内某些元素和 val 的大小,直至找到一个不小于 val 的元素。这也意味着,如果使用第一种语法格式,则 [first,last) 范围的元素类型必须支持 < 运算符。

此外,该函数还会返回一个正向迭代器,当查找成功时,迭代器指向找到的元素;反之,如果查找失败,迭代器的指向和 last 迭代器相同。

upper_bound()

pper_bound() 函数定义在头文件中,用于在指定范围内查找大于目标值的第一个元素。该函数的语法格式有 2 种,分别是:

//查找[first, last)区域中第一个大于 val 的元素。
ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last, const T& val);
//查找[first, last)区域中第一个不符合 comp 规则的元素
ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last, const T& val, Compare comp);


相关文章
|
6天前
|
算法 C语言 C++
【c++丨STL】list的使用
本文介绍了STL容器`list`的使用方法及其主要功能。`list`是一种双向链表结构,适用于频繁的插入和删除操作。文章详细讲解了`list`的构造函数、析构函数、赋值重载、迭代器、容量接口、元素访问接口、增删查改操作以及一些特有的操作接口如`splice`、`remove_if`、`unique`、`merge`、`sort`和`reverse`。通过示例代码,读者可以更好地理解如何使用这些接口。最后,作者总结了`list`的特点和适用场景,并预告了后续关于`list`模拟实现的文章。
22 7
|
24天前
|
存储 编译器 C语言
【c++丨STL】vector的使用
本文介绍了C++ STL中的`vector`容器,包括其基本概念、主要接口及其使用方法。`vector`是一种动态数组,能够根据需要自动调整大小,提供了丰富的操作接口,如增删查改等。文章详细解释了`vector`的构造函数、赋值运算符、容量接口、迭代器接口、元素访问接口以及一些常用的增删操作函数。最后,还展示了如何使用`vector`创建字符串数组,体现了`vector`在实际编程中的灵活性和实用性。
49 4
|
25天前
|
C语言 C++ 容器
【c++丨STL】string模拟实现(附源码)
本文详细介绍了如何模拟实现C++ STL中的`string`类,包括其构造函数、拷贝构造、赋值重载、析构函数等基本功能,以及字符串的插入、删除、查找、比较等操作。文章还展示了如何实现输入输出流操作符,使自定义的`string`类能够方便地与`cin`和`cout`配合使用。通过这些实现,读者不仅能加深对`string`类的理解,还能提升对C++编程技巧的掌握。
54 5
|
25天前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
41 2
|
1月前
|
存储 算法 Linux
【c++】STL简介
本文介绍了C++标准模板库(STL)的基本概念、组成部分及学习方法,强调了STL在提高编程效率和代码复用性方面的重要性。文章详细解析了STL的六大组件:容器、算法、迭代器、仿函数、配接器和空间配置器,并提出了学习STL的三个层次,旨在帮助读者深入理解和掌握STL。
48 0
|
10天前
|
存储 编译器 C语言
【c++丨STL】vector模拟实现
本文深入探讨了 `vector` 的底层实现原理,并尝试模拟实现其结构及常用接口。首先介绍了 `vector` 的底层是动态顺序表,使用三个迭代器(指针)来维护数组,分别为 `start`、`finish` 和 `end_of_storage`。接着详细讲解了如何实现 `vector` 的各种构造函数、析构函数、容量接口、迭代器接口、插入和删除操作等。最后提供了完整的模拟实现代码,帮助读者更好地理解和掌握 `vector` 的实现细节。
20 0
|
2月前
|
存储 程序员 C++
C++常用基础知识—STL库(2)
C++常用基础知识—STL库(2)
81 5
|
2月前
|
存储 自然语言处理 程序员
C++常用基础知识—STL库(1)
C++常用基础知识—STL库(1)
73 1
|
2月前
|
算法 安全 Linux
【C++STL简介】——我与C++的不解之缘(八)
【C++STL简介】——我与C++的不解之缘(八)
|
2月前
|
算法 数据处理 C++
c++ STL划分算法;partition()、partition_copy()、stable_partition()、partition_point()详解
这些算法是C++ STL中处理和组织数据的强大工具,能够高效地实现复杂的数据处理逻辑。理解它们的差异和应用场景,将有助于编写更加高效和清晰的C++代码。
45 0