c\c++——STL库的学习(1)

一、容器的分类

  • 序列式容器(每个元素有固定位置,取决于插入 时机和地点,和元素值无关)

           vector(向量)list(列表)stack(栈)queue(队列)dequeue(双队列)

  • 关联式容器(元素位置取决于特定的排序准则,和插入顺序无关)

           set(集合) multiset(多重集合) map(映射) multimap(多重映射)

二、vector容器

1、简介

(1)将元素置于一个动态数组中加以管理

(2)随机存取(下标访问)

(3)尾部插入删除迅速O(1),中部和头部较费时

2、构造方法

int b[5] = {1, 2, 3, 4, 5}; 
//vector(begin,end)左闭右开
    vector<int> v1(b + 1, b + 5); 
    for(int i = 0;i<4;i++){
        cout<<v1[i];
    }// v5元素为 2, 3, 4,  5

//vector(n,element)将n个ele拷贝给本身
// 声明一个长度为5,所有值为1的vector
    vector<int> v2(5, 1);//v2为1 1 1 1 1

//拷贝构造函数,将v2的内容拷贝到v3
    vector<int> v3(v2)//v6:1 1 1 1 1

3、赋值

​int main() {
    // 元素类型为int的vector,名称为v1
    vector<int> v1;

    // 声明一个长度为5的v2,
    vector<int> v2(5);

   // 另一种声明方式
    vector<int> v3 = {4, 5, 6, 7};

    
   vector<int> v2,v3,v4,v5;
   //vector.assign(beg,end)左闭右开
    int arr[]={0,1,2,3,4,5};
    vector<int> v1;
    v1.assign(arr,arr+6);
    for(int i=0;i<v1.size();i++){
        cout<<v1[i];
    }//输出012345

   //将v1复制到v2
   v2.assign(v1.begin(),v1.end());//输出012345

   //可以只复制某一区间
   v3.assign(v1.begin()+2,v1.end()-1);//234

   //将4个10赋值给本身
   v4.assign(4,10);//10 10 10 10

  //直接等于赋值
   v5=v4;
    
}

4、vector大小

(1)vector.size()返回容器中元素的个数

(2)vector.empty()判空--返回 bool类型

(3)  vector.resize()重新指定长度

 vector<int> v1={1,2,3};
    v1.resize(5);//12300
    v1.resize(8,4);//12300444

5、vector元素的访问方式

//下标访问
vector<int> v1 = {0,1,2,3,4}
v1[1];//1

//循环遍历
for(int i = 0;i<vi.size();i++){
   cout<<v1[i];
}

//迭代器
for(int x:v1){
    cout<<x<<" ";
}

6、vector插入和删除push_back、pop_back、insert、erase

vector<int> v1 = {0,1,2,3,4}

//尾部的插入删除
//插入元素5
v1.push_back(5);//0 1 2 3 4 5
//删除末尾
v1.pop_back();//0 1 2 3 4

//其他位置的插入
v1.insert(v1.begin()+1,2);//注意第一个参数为指针,在下标为1的位置插入元素2
//打印:0 2 1 2 3 4
v1.insert(v1.begin()+1,2,1);//在下标为1的位置插入2个1
//打印:0 1 1 2 1 3 4
int b[]={40,50,60,70,80,90};
v1.insert(v1.begin()+1,b+1,b+5);//插入一个区间
//打印:0 50 60 70 80 1 1 2 1 3 4;

//删除
vector<int> v = {0, 1, 2, 3, 4, 5, 6};
v.erase(v.begin() + 1, v.begin() + 4); // 删除[1, 4)范围的下标,主要左闭右开即[1, 3]
for (int x : v) cout << x << ' '; // 输出为:0 4 5 6

7、交换两个vector

//交换v1和v2的内容
v1.swap(v2);

三、vector容器的iterator类型

vector<int>::iterator it;//变量名为it

vector容器的迭代器属于“随机访问迭代器”:迭代器依次可以移动多个位置

1、基本使用方法

int main(){
    vector<int> v1;
    int arr[] = {0,1,2,3,4};
    v1.assign(arr,arr+5);
    //构造一个迭代器对象
    vector<int>::iterator it;
    it = v1.begin();
    //通过循环的方式使用迭代器遍历v1中的元素
    for(it=v1.begin();it!=v1.end();it++){
        cout<<*it<<" ";//*解引用
    }//0 1 2 3 4 5

    it=v1.begin();
    it=it+2;
    cout<<*it<<endl;//2
    
    return 0;
}

四、string(最常用的容器之一)

1、基础声明

// 方式一
string s1;

// 方式二
string s2 = "123";

// 方式三,初始化为由3个c组成的字符串
string s3(3, 'c');

// 方式四 相当于方式二
string s4("123");

// 方式五,和方式四是等价的
char chr[] = "abc";
string s5(chr);

2、访问遍历方式(和vector差不多)

string s = "abc";
cout << s[2] << endl; // 输出:c

// 遍历
for (int i = 0; i < 3; ++i) cout << s[i] << ' ';
cout << endl;

// c++11方式
for (char c : s) cout << c << ' ';//注意式char

3、函数

(1)push_back和pop_back
(2)size函数,length函数(其效果和用法和size一样)resize函数
(3)clear函数
(4)empty函数
(5)begin和end函数
(6)各种比较运算符,string还多了+和+=的操作
(7)swap函数
(8)front和back函数

(9)find函数(从前往后找返回下标)refind(从后往前找)

int main(){
    string s = "abcdef";

// 从下标为0开始找第一次出现的字符'e',返回下标
cout << s.find('e') << endl; // 输出为 4

// 从下标3开始找第一个字符'c',找不到返回size_t最大值
cout << s.find('c', 3) << endl;

// 但在判断是否找到可以用这种方式
//string::npos,是一个常量,其值可以理解为-1,但由于它是无符型,固真正意义表示的是无穷大
if (s.find('3', 3) == string::npos) {
    cout << "not find!!!" << endl;
}

// 从下标0开始找字符串"bc"
cout << s.find("bc") << endl; // 输出为 1

// 从下标1开始找
cout << s.find("ef", 1) << endl; // 输出为 4
}

//参考https://blog.csdn.net/hao_6_6/article/details/118612536
(10)substr()用于截取string的一个子串,返回值为string
int main(){
    string s = "abcdef";
    //下标从2开始到末尾
    cout<<s.substr(2)<<endl;//cdef

    //截取下标从2开始长度为2
    cout<<s.substr(2,2)<<endl;//cd

    //下标从2开始长度为无穷
     cout<<s.substr(2,-1)<<endl;//cdef

}
(11)replace函数:用于将字符串中的指定范围的子串来替换指定的子串,并返回替换后的结果
 string s = "abcdef";
 //从下标为2开始,长度为3的字串替换成ggg,注意一定要打“ggg“
     cout<<s.replace(2,3,"ggg")<<endl;//abgggf
//从下标1开始长度为3的子串替换成 "123" 的下标从1开始长度为2的子串
     cout<<s.replace(1,3,"123",1,2)<<endl;//a23gf
//从下标从1开始长度为3的子串替换成 5个 @,注意是单引号’@‘
     cout<<s.replace(1,3,5,'@')<<endl;//a@@@@@f
(12)append()尾部添加字符串
string s = "abcdef";

// 在 s 串尾部插入 "123"
s.append("123");
cout << s << endl; // abcdef123

string x = "123456";
s = "abcdef";

// 此方法和上一种写法是等价的
s.append(x);
cout << s << endl; // abcdef123456

// 在上一种方法的基础上加个范围, 即 取 x 串下标从3开始长度为2的子串添加到 s 尾部
s = "abcdef";
s.append(x, 3, 2);
cout << s << endl; // abcdef45
 (13)insert(插入任意位置)
string a = "abcdef";
string b = "123456";

// 从 a 串中下标2开始后面插入b串
a.insert(2, b);
cout << a << endl; // ab123456cdef

a = "abcdef";
// 从 a 串中下标2开始后面插入b串中下标从3开始长度为2的子串
a.insert(2, b, 3, 2);
cout << a << endl; // ab45cdef
(14)to_string函数
  • 用于将整数类型转换成string类型
  • 可传入的参数有int、long long、double等
(15)stoi函数:将string 转换成int类型

其类似的还有stol、stof、stod、stoll、stold、stoull等,分别对应返回值为long、double、long long、long double、unsigned long long

 int a = 1;
     long long b = 2;
     double c = 3.1415926;

     string x = to_string(a);
     string y = to_string(b);
     string z = to_string(c);

     string s = "123";
     int S = stoi(s);
(16)getline读入一行
string s;
// 值得注意的是,如果此前有换行符需要用getchar吃掉
while (getline(cin, s)) {
    cout << s << endl; // 实现一行一行地读入
}
(17)stringstream流控制
int main(){
    string a = "You make it !",sub;
    stringstream b(a);//将流初始化
    while(b>>sub){
        cout<<sub<<endl;
    }
    return 0;
}
You
make
it
!
string str = "123  90.99";
    stringstream str2;
    str2<<str;//像流一样将str读入到str2

    int x = 0;
    double y = 0.0;
    str2>>x>>y;//像流一样从str2读入到x和y
    cout<<x<<" "<<y<<endl;//123 90.99

五、stack(栈)

1、出栈入栈(先进后出)

//声明
    stack<int> st;
    st.push(1);//从栈顶入栈1
    st.push(2);//入栈2

    //没有迭代器

    cout<<st.top()<<endl;//返回2
    st.pop();//出栈栈顶元素2
    cout<<st.top();//返回1

    //循环出栈
    while(!st.empty()){
        st.pop();
    }
    cout<<st.top();

2、拷贝

stack<int> s1;
    s1.push(1);
    s1.push(3);
    s1.push(5);
    //拷贝构造与赋值
    stack<int> s2(s1);//将s1拷贝到s2
    cout<<s2.top();//输出5

3、stack.empty()

4、stack.size()

六、queue(队列)

1、先进先出

 queue<int> qu;
    //队尾入队
    qu.push(1);
    qu.push(2);
    qu.push(3);
    cout<<qu.size();//3
    //没有迭代器不能遍历
    cout<<qu.front();//输出1
    cout<<qu.back();//输出3

    //队头出队
    qu.pop();
    cout<<qu.front();//输出2

    //想要循环输出
    qu.push(4);
    while(!qu.empty()){
        cout<<qu.front()<<" ";
        qu.pop();//2 3 4
    }

2、拷贝赋值

//接上一段代码的qu
queue<int>qu2(qu);
    //或者
    queue<int>qu3 = qu;
     while(!qu2.empty()){
        cout<<qu2.front()<<" ";
        qu2.pop();//2 3 4
    }
    while(!qu3.empty()){
        cout<<qu3.front()<<" ";
        qu3.pop();//2 3 4
    }

七、deque(双端队列 )

1、简介

  • deque是双端数组而vector是单端的,两者许多操作很相似。
  • deque可以随机存取元素,支持索引值直接存取【】或at()。
  • deque头部尾部添加和删除元素很方便,在中部就比较费时。

2、deque.push_front()头部插入

3、deque.pop_front()头部删除

4、其他操作和vector容器的的操作差不多

八、list(列表)

1、简介

  • list双向链表容器,可以高效地插入删除
  • list不可随机存取元素

2、常用操作

  • push_front(val):在头部插入
  • pop_front():在头部删除
  • push_back(val):尾部插入
  • pop_back():尾部删除
  • front()、back():返回头元素、尾元素的引用
 list<int> lt(3,1);//长度为3,值全为1
    lt.push_back(2);//尾部插入2
    lt.push_front(1);
    lt.pop_front();
    //遍历
    for(auto x:lt){
        cout<<x<<" ";
    }//1 1 1 2

    //构造一个迭代器遍历
    list<int>::iterator it;
    for(it=lt.begin();it!=lt.end();it++){
        cout<<*it<<" ";
    }//1 1 1 2
    cout<<endl;
    //存取
    cout<<lt.front()<<" "<<lt.back()<<endl;//1 2
  • insert(iterator, val):在迭代器iterator插入val
  • insert(iterator, count, val):在迭代器iterator前插入count个val
    //lt3:6 6 6
    lt3.insert(lt3.begin(),8);//8 6 6 6
    lt3.insert(lt3.end(),3,9);//8 6 6 6 9 9 9


    list<int>::iterator it3 = lt3.begin();
    for(it3=lt3.begin();it3!=lt3.end();it3++){
        if(*it3 == 9)//让it3指向9的位置
        break;
    }
    if(it3 != lt3.end()){//找到了9
        lt3.insert(it3,7);//插入7
    }
    for(auto x:lt3){
        cout<<x<<" ";//8 6 6 6 7 9 9 9
    }
  • begin()、end()、rebegin()、rend():返回头部和尾部下一位置的迭代器
  • size():大小
  • sort():升序排序
  • clear():清空
  • reverse():翻转链表
  • merge(list2) :用第二个有序的 list 合并一个有序 list
  • swap():lt1.swap(lt2)交换两个容器的内容
    list<int>lt;
    lt.push_front(5);
    lt.push_front(9);
    lt.push_front(1);
    lt.push_front(3);
    list<int>lt2(3,6);

    //升序
    lt.sort();
    for(auto x:lt){
        cout<<x<<" ";
    }//1 3 5 9
     //翻转reverse
    lt.reverse();
    for(auto x:lt){
        cout<<x<<" ";
    }//9 5 3 1
    cout<<endl;
    //交换
    lt.swap(lt2);
    for(auto x:lt){
        cout<<x<<" ";//6 6 6
    }
     cout<<endl;
    //赋值
    list<int> lt3;
    lt3.assign(5,8);//8 8 8 8 8

    lt3=lt;//将lt的值赋给lt3 6 6 6
  • splice(list.iterator, list2, list2.iterator_start, list2.iterator_end):在本list的 iterator后插入list2的从 iterator_start 到 iterator_end, 后面两个可填可以不填,当填了iterator_start,可不填最后一个,时间复杂度O(1)

  • erase(iterator):删除iterator,返回删除前的下一个的迭代器
    erase(iterator_start, iterator_end):删除[iterator_start, iterator_end)范围内的元素,返回删除前的iterator_end
     

九、set(集合)和multiset

1、简介

  • set中所包含的元素是唯一的(即使你重复插入了),集合中的元素按一定的顺序排列,元素插入过程是按照排序规则插入。
  • set采用红黑树(平衡二叉树),插入时候自动排序(logn),插入删除快于vector
  • set不可以直接存取元素
  • mutiset和set的区别:set支持唯一键值,每个元素只能出现一次;mutiset中同一个值可以出现多次。
  • 不可以直接修改值,必须先删除原有数据,再插入新的元素。

2、insert()插入

    //声明
    set<int> s1;

    //插入
    s1.insert(1);
    s1.insert(5);
    s1.insert(3);
    s1.insert(9);
    s1.insert(-2);
    //另一种插入
    set<int> ass = {3, 4, 3, 2, 5};
    ass.insert(1); // 插入一个 1 最终为1 2 3 4 5(自动排序)

    //遍历
    for(int x:s1){
        cout<<x<<" ";
    }
    cout<<endl;
    //迭代器遍历
    //正向迭代器
    set<int>::iterator it;
    for(it=s1.begin();it!=s1.end();it++){
        cout<<*it<<" ";//-2 1 3 5 9set默认升序
    }
    cout<<endl;
    //反向迭代器
    set<int>::reverse_iterator it2;
    for(it2=s1.rbegin();it2!=s1.rend();it2++){
        cout<<*it2<<" ";//9 5 3 1 -2
    }

3、erase()删除

set<int> ass = {3, 4, 3, 2, 5, 1};
ass.erase(3);//1 2 4 5
ass.erase(ass.begin()); // 删除指点迭代器的元素
ass.erasse(ass.begin(), ass.begin() + 2); // 删除连个迭代器范围内的数

4、size()大小

由于set内部保证元素唯一,已有的相同元素无论插入几次都是不会改变size的

set<int> ass = {3, 4, 3, 2, 5};
    //2 3 4 5
    cout<<ass.size()<<endl;//4
    ass.insert(4);
    cout<<ass.size()<<endl;//4

5、empty()判空

set<int> ass = {3, 4, 3, 2, 5};
cout<<ass.empty();//bool类型 空返回1 非空返回0 

6、count()计数

其实相当于查找某个元素是否在容器内,在则返回1,不在则返回0

set<int> ass = {3, 4, 3, 2, 5};
cout << ass.count(3) << endl; // 1
cout << ass.count(9) << endl; // 0

7、clear()清空

ass.clear();
cout<<ass.size()<<endl;//0

8、lower_bound()和upper_bound()

int main(){
    set<int> ass = {1, 6, 4, 8};
//找到第一个大于等于指定元素
    cout << *ass.lower_bound(3) << endl; // 4
    cout << *ass.lower_bound(6) << endl; // 6
    if (ass.lower_bound(9) == ass.end()) {
        cout << "not found" << endl; // 被执行
    }
//找到第一个大于指定元素
    cout << *ass.upper_bound(3)<<endl;//4
    cout << *ass.upper_bound(6)<<endl;//8
    if(ass.upper_bound(8)==ass.end()){
        cout<<"not fund"<<endl;//not fund
    }
}

9、pair()将两个类型的数捆绑在一起

  • set.equal_range(elem)返回容器中与elem相等的上下限的两个迭代器,上限是闭区间(就是lower_bound的值),下限是开区间(就是upper_bound的值)
  • 函数返回两个迭代器,而这两个迭代器被封装在pair中
  1. pair<T1,T2>(对组),存放两个值的类型,可以不一样(比如一个int,一个char,也可以 是自定义类型)
  2. pair.first是pair里面的第一个值,是T1的类型
  3. pair.second是pair里面的第二个值,是T2的类型

10、swap()交换

//注意不同类型的set不能交换
    set<char> ass1={'a','b','c','d'};
    set<char> ass2={'e','f','g','h'};
    ass1.swap(ass2);
    set<char>::iterator it;
    for(it=ass1.begin();it!=ass1.end();it++){
        cout<<*it<<" ";//e f g h
    }
    set<char>::iterator it2;
   for(it2=ass2.begin();it2!=ass2.end();it2++){
        cout<<*it2<<" ";//a b c d
   }

 十、map(映射表)

1、insert()插入+遍历

map/multimap采用模板类实现,对象的默认构造形式

int main(){
    //声明(key,value)
    map<int,double> m1;
    multimap<int,string> m2 = {
        {1,"abc"},
        {2,"def"},
        {3,"ghi"},
    };
    
    //插入
    m2.insert({4,"jkl"});
    //m2.insert({{4,"jkl"},{5,"mn"}})多组插入
    m2.insert(pair<int,string>(5,"mn"));//注意5是键,“mn”是值
    m2[6]="o";
    
    //遍历1
    map<int,string>:: iterator it;
    for(it=m2.begin();it!=m2.end();it++){

        pair<int,string> p = *it;

        int key = p.first;//first为第一个,即键
        string value = p.second;//second为第二个,即值

        cout<<key<<": "<<value<<endl;
    }
    //遍历2
    for(pair<int,string> p2:m2){
        cout<<p2.first<<": "<<p2.second<<endl;
    }
    //遍历3
    for(auto p3:m2){
        cout<<p3.first<<": "<<p3.second<<endl;
    }
    //遍历4
    for(auto[a,b]:m2){
        cout<<a<<": "<<b<<endl;
    }

    return 0;
}

2、erase()删除

传参传的是key键

 m2.erase(3);
    //遍历4
    for(auto[a,b]:m2){
        cout<<a<<": "<<b<<endl;
    }

3、count()、size()、empty()、clear()lower_bound()、upper_bound()、find()使用方法和set一样。

 map<int,string> m2 = {
        {1,"abc"},
        {2,"def"},
        {3,"ghi"},
    };
map<int,string>::iterator it2 = m2.find(3);
    cout<<(*it2).second<<endl;//注意map内部是一个pair对组
//ghi

  • 27
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值