【C/C++】学习STL标准模板库 001概述+vector 快到碗里来(◕ᴗ◕✿)

【绝知此事要躬行 还得自己try一try】

什么是STL?

STL(Standard Template Library, 标准模板库)是惠普实验室开发的一系列软件的同统称,是C++标准库的核心,它提供了一系列软件方案,利用先进、高效的算法来管理数据。程序员无需了解STL的原理,就可以想用数据结构与算法领域中的这一个革新成果。

STL从广义上可分为三类

(1)算法(algorith)

(2)容器(container)

(3)迭代器(iterator)

什么是容器?

容器可分为三类

序列式容器 

即线性排列(类似数组的存储方式)来存储某一指定类型的数据(如int、double、char等),该容器不会对存储的元素按照大小进行排序。常见的序列式容器有array(数组容器)、vector(向量容器)、deque(双端队列容器)和list(链表容器)

关联式容器 

关联式容器在存储元素的同时,还会为各元素分配一个键(键值对的键),默认情况下会对元素进行升序排序。当我们知道了一个元素所对应的键的值<key, value>,那么就可以直接通过该键的值来找到目标元素value,而无需遍历整个元素。常见的关联式容器有set(集合容器)、multiset(多重集合)、map(映射集合)和 multimap(多重映射集合)

无序联式容器 

无序联式容器,又称为哈希容器。和关联式容器一样采用键值对的方式存储,不同的地方在于它不会对元素进行排序它更加擅长通过key来查找value的值。常见的无序关联容器有unordered_setunordered_multisetunordered_map unordered_multimap

简述总结

使用STL可以让我们事半功倍,得到一些高效的代码,它同样能完成我们所需要的功能,通常比自己编写的代码所完成得效果还要好。

什么是迭代器

  • 迭代器是一个“可以遍历STL容器全部或部分元素”的对象,通常用来表示容器中的某一个位置。迭代器在STL中起着粘合剂的作用,其可以将STL的各个部分结合在一起。C++更趋向于使用迭代器而不是下标操作,因为标准库为每一种标准容器都定义了一种迭代器类型,而只有少数容器(如vector)支持下标操作访问容器元素。
  • 所有容器都会提供一些基本的成员函数,其中最重要的就是begin()和end(),这两个函数的返回值都是迭代器,可以通过他们遍历容器中所有的元素。
  • begin(): 返回一个迭代器,指向容器的第一个元素
  • end(): 返回一个迭代器,指向最后一个元素的下一个位置

  • 由begin()和end()形成的区间是一个左闭右开区间[begin(), end()),表示从第一个元素开始,到最后一个元素(指向最后一个元素的下一个位置但不包括那个位置)
  • 如果容器为空,则begin()等于end()

迭代器的定义和初始化(vector向量集合为例)

  • 其他集合也是如此对应的操作
vector<int> v; // 定义一个存储int类型变量的向量容器
vector<char> v2; // 定义一个存储char类型变量的向量容器
vector<double> v3; // 定义一个存储double类型变量的向量容器
// 定义一个指向vector向量容器的迭代器 
vector<int>::iterator it_0;
// 定义一个迭代器it_1指向v的第一个元素
vector<int>::iterator it_1 = v.begin();
// 定义一个迭代器it_2指向v的最后一个元素的下一个位置
vector<int>::iterator it_2 = v.end(); 

  编程实践

// Created by Liu Xianmeng on 2022/11/24
#include <bits/stdc++.h>
using namespace std;
int main() {
    vector<int> v; // 定义一个存储int类型变量的向量容器
    for(int i=0; i<3; ++i){
        v.push_back(i); // 向v中插入1、2、3
    }
    vector<int>::iterator it; // 声明一个指向存储int的vector的迭代器
    for(it=v.begin(); it!=v.end(); ++it){
        // 取it迭代器指向的元素的值 这儿(*it)与C语言的指针非常相似
        printf("%d ", *it);
    }
    printf("\n"); // 换个行
    for(int e : v){ // 这里的用法e直接指代v中的元素
        printf("%d ", e);
    }
    return 0;
}

    /**
     * 打印结果:
     * 0 1 2
     * 0 1 2
     */

vector

vector简介

  • vector是一个不定长数组,它把一些常用的操作“封装”在vector类型的内部。用户看不见但能像访问数组那样对元素进行随机访问,还能在尾部快速插入、删除元素。vector还具有内存自动管理的功能,对于元素的插入和删除,可以动态地调整所占的内存空间。
  • 使用vector,需要包含vector头文件【#include <vector>
  • vector的下标和数组一样,都是从0开始的。也就是说,如果vector容器的大小是n,那么元素的下标是 [0,n-1] . 对于vector容器的定义,可以事先定义一个固定的大小,之后再对其大小进行调整;也可以不定义大小,使用push_back() 方法从尾部插入数据;还可以使用insert() 在某个元素位置前插入新的元素。

创建vector对象

vector<int> v; // 创建一个存储int类型元素的vector
// 创建的时候可以自定指定大小(如果装入的元素超过10个,它会自动扩容)所有元素自动初始化为0
vector<int> v1(10); 
vector<int> v2(10,6); // 10指定大小,6指定初始化值(所有元素自动初始化为6)
vector<int> v3(v2); // 创建一个和v2完全一样的v3(复制)

【必知必会操作】push_back(elem) 在v的尾部添加一个元素elem

【必知必会操作】

begin()  返回一个迭代器,指向v的第一个元素

end()  返回一个迭代器,指向v的最后一个元素的下一个位置

rbegin()  返回一个迭代器,指向v的最后一个元素

rend() 返回一个迭代器,指向v的第一个元素的前一个位置

【必知必会操作】insert(...) 注意传入的pos参数是迭代器

  • insert(pos, elem) 返回插入的元素位置的迭代器(期间,vector会自动扩张一个元素的空间,将pos指向的元素及后面的元素向后顺移一个位置,然后将elem放在pos指向的位置)
  • insert(pos, n, elem) 从v的pos下标处插入n个elem,其他元素向后顺移,返回指向插入的第一个位置的迭代器
  • insert(pos,first,last) 从v的pos下标处插入另一个集合的[first, last)取余的所有元素,返回指向插入的第一个位置的迭代器

【必知必会操作】erase(...)

  • erase(pos) 删除pos迭代器指定位置的元素,并返回所删除元素的位置的下一个位置
  • erase(first, last) 删除[first, last)返回的元素,并返回指向last位置的迭代器(注意:删除元素只会改变vector集合的size,即实际包含的元素的个数;而不会影响capacity,即vector容量的大小)

【必知必会操作】clear() 清空v中的元素

【必知必会操作】size() 求v当前包含元素多少个元素

【必知必会操作】empty() 判断v是否为空 返回布尔值

【必知必会操作】对v进行排序

  • sort(v.begin(), v.end())  对v进行升序排序
  • sort(v.rbegin(), v.rend())  对v进行降序排序

【综合运用】

// Created by Liu Xianmeng on 2022/11/24
#include <bits/stdc++.h>
using namespace std;
int main() {
    srand(time(NULL));
    vector<int> v(10); // 初始大小设置为10
    printf("v的大小为:%d\n", v.size());
    for(int i=0; i<10; ++i) v[i] = i+1;
    printf("v的元素值为:");
    for(int e:v) printf("%d ", e); // 遍历打印元素的值
    v.erase(v.begin() + 4); // 擦除v[4]元素
    printf("\n删除v[4]后的大小为:%d\n", v.size());
    printf("删除v[4]后的元素遍历为:");
    for(int e:v) printf("%d ", e);
    v.push_back(rand()%100);v.push_back(rand()%100);
    v.push_back(rand()%100);v.push_back(rand()%100);
    printf("\n添加随机数后的元素遍历为:");
    for(int e:v) printf("%d ", e);
    sort(v.begin(), v.end());
    printf("\n升序排序后的元素遍历为:");
    for(int e:v) printf("%d ", e);
    sort(v.rbegin(), v.rend());
    printf("\n降序排序后的元素遍历为:");
    for(int e:v) printf("%d ", e);
    v.clear(); // 清空元素
    printf("\n清空元素后的v大小为:%d", v.size());
    printf("\nv.empty = %s", v.empty()==true?"true":"false");
    return 0;
    /**
     * 【打印结果】
     * v的大小为:10
     * v的元素值为:1 2 3 4 5 6 7 8 9 10
     * 删除v[4]后的大小为:9
     * 删除v[4]后的元素遍历为:1 2 3 4 6 7 8 9 10
     * 添加随机数后的元素遍历为:1 2 3 4 6 7 8 9 10 59 85 91 22
     * 升序排序后的元素遍历为:1 2 3 4 6 7 8 9 10 22 59 85 91
     * 降序排序后的元素遍历为:91 85 59 22 10 9 8 7 6 4 3 2 1
     * 清空元素后的v大小为:0
     * v.empty = true
     */
}

  编程实践

问题 1: 约瑟夫问题

时间限制: 1.000 Sec  内存限制: 128 MB

题目描述

有 m 个人,其编号分别为 1~m。按顺序围成一个圈,现在给定一个数 n,从第一个人开始依次报数,报到 n 的人出圈,然后再从下一个人开始,继续从 1 开始依次报数,报到 n 的人再出圈,……如此循环,直到最后一个人出圈为止。编程输出所有人出圈的顺序。

输入

一行两个正整数 m 和 n,之间用一个空格隔开,1≤m<100,1≤n≤32767。

输出

输出 m 行,每行一个正整数,表示依次出圈的人的编号。

样例输入 Copy

8 5

样例输出 Copy

5
2
8
7
1
4
6
3

问题1约瑟夫问题 分析与解答【AC代码】

/**
 * created by Liu Xianmeng on 2022/12/5
 * 【分析】用vector来存储m个人的编号 当有一个人出圈的时候 size()自动减一 比用数组更加省心
 * 编号和n的计数一起增大 当编号超过v.size() 编号恢复为1 继续计数 直到n的计数到n
 * (这时候会有一人的编号从v中删除 n的计数重新从1开始)
 */
#include <bits/stdc++.h>
using namespace std;
int main(){
    int m,n;
    scanf("%d %d", &m, &n);
    // 初始m个人围成一圈 报数个数为n
    vector<int> v;
    for(int i=1; i<=m; ++i){
        v.push_back(i);
    }
    int number = 1; // 记录人员的编号
    int cnt_n = 1;  // 记录当前报号
    while(v.size()>0){
        while(cnt_n != n){ // 只要cnt_n不等于n 则一直报号
            ++number;
            if(number == v.size()+1) // 处理循环
                number = 1;
            ++cnt_n;
        }// 循环结束 说明此时cnt_n === n
        cnt_n = 1; // 恢复1 重新从1开始报数
        // while循环退出 说明报数刚好报到n 这个时候v删除一个元素
        printf("%d\n", v[number-1]);
        v.erase(v.begin() + (number-1));
        // 删除一个元素后 要考虑number的赋值 如果在报号cnt==n的时候 number==v.size()怎么办?->置number=1 否则不用管
        if(number == v.size()+1){
            number = 1;
        }
    }
    return 0;
}

deque

【C/C++】深入了解STL标准模板库 002 deque (double-ended queue, 双端队列) 快到碗里来(◕ᴗ◕✿)_BigXMeng的博客-CSDN博客

set

【C/C++】深入了解STL标准模板库 003 set集合 快到碗里来(◕ᴗ◕✿)_BigXMeng的博客-CSDN博客

>.<(后续更新... )

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值