【C++】认识标准库STL(1)

从今天开始,我们进入STL的学习进程,了解基础STL的用法和原理,废话少说,发车!


1. STL简介

STL(standard template libaray-标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的 组件库,而且是一个包罗数据结构与算法的软件框架。

2.string类

1.认识

官网的string类的介绍

Cplusplus.com https://cplusplus.com/

在使用string类时,必须包含#include头文件以及using namespace std;

2.auto和范围for

auto关键字
在这里补充2个C++11的小语法,方便我们后面的学习。
在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,后来这个不重要了。C++11中,标准委员会变废为宝赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。
用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&, 当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际 只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
auto不能作为函数的参数,可以做返回值,但是建议谨慎使用。
auto不能直接用来声明。

复制代码
// 不能做参数
void func2(auto a)
{}

// 可以做返回值,但是建议谨慎使用
auto func3()
{
    return 3;
}

// 编译报错:rror C3531: "e": 类型包含"auto"的符号必须具有初始值设定项
auto e;

// 编译报错:error C3538: 在声明符列表中,"auto"必须始终推导为同一类型
auto cc = 3, dd = 4.0;

// 编译报错:error C3318: "auto []": 数组不能具有其中包含"auto"的元素类型
auto array[] = { 4, 5, 6 };

范围for
对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11中引入了基于范围的for循环。for循环后的括号由冒号 " :" 分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围,自动迭代,自动取数据,自动判断结束。 范围for可以作用到数组和容器对象上进行遍历 范围for的底层很简单,容器遍历实际就是替换为迭代器,这个从汇编层也可以看到。

3. string类的常用接口说明(注意下面我只讲解最常用的接口)

1. string类对象的常见构造

|----------------------------------|---------------------------|
| (constructor)函数名称 | 功能说明 |
| string() (重点) | 构造空的string类对象,即空字符串 |
| string(const char* s) (重点) | 用C-string来构造string类对象 |
| string(size_t n, char c) | string类对象中包含n个字符c |
| string(const string&s) (重点) | 拷贝构造函数 |

复制代码
void Teststring()
{
    string s1; // 构造空的string类对象s1
    string s2("hello bit"); // 用C格式字符串构造string类对象s2
    string s3(s2); // 拷贝构造s3
}

2. string类对象的容量操作

成员函数 功能 核心特点
size() 返回有效字符个数 length()完全等价
length() 返回有效字符个数 面向字符串习惯
capacity() 返回当前内存容量 已分配空间,capacity >= size
max_size() 返回理论最大容纳字符数 系统限制,几乎不用
empty() 判断字符串是否为空 为空返回 true,推荐替代size()==0
成员函数 功能 关键区别
reserve(n) 预分配容量 只改容量、不改有效长度;只扩容、不缩容
resize(n) 改变有效字符长度 截断 / 扩充字符串,同时可能改变容量
resize(n, c) 改变长度,指定填充字符 新增位置用字符c填充
成员函数 功能 内存变化
clear() 清空所有有效字符 size=0,容量不变,不释放内存
shrink_to_fit() 收缩容量适配实际长度 capacity = size,释放多余空间(C++11)

注意:
1. size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接
口保持一致,一般情况下基本都是用size()。
2. clear()只是将string中有效字符清空,不改变底层空间大小。
3. resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不 同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。
注意: resize在改变元素个数时,如果是将元素个数 增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
4. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参 数小于string的底层空间总大小时,reserver不会改变容量大小。

3. string类对象的访问及遍历操作

函数名称 功能说明
operator[](重点) 返回 pos 位置的字符,支持 const string 类对象调用
begin() + end() begin() 获取第一个字符的迭代器;end() 获取最后一个字符下一个位置的迭代器
rbegin() + rend() rbegin() 获取最后一个字符的反向迭代器;rend() 获取第一个字符前一个位置的反向迭代器
范围 for C++11 支持,更简洁的新式遍历方式,底层用迭代器实现

4. string类对象的修改操作

函数名称 功能说明
push_back 在字符串后尾插字符 c
append 在字符串后追加一个字符串
operator+=(重点) 在字符串后追加字符或字符串
c_str(重点) 返回 C 语言格式的 const char * 字符串
find + npos(重点) 从 pos 位置向后查找字符 / 子串,找到返回下标,失败返回 npos
rfind 从 pos 位置向前逆向查找字符 / 子串,返回对应位置
substr 从 pos 位置开始,截取 n 个字符并返回新字符串
insert 在指定位置插入字符或字符串
erase 删除指定位置、指定长度的字符
replace 替换指定区间的字符内容
swap 交换两个 string 对象内容
pop_back 删除字符串末尾字符

注意:
1. 在string尾部追加字符时,s.push_back(c) / s.append(1, c) / s += 'c'三种的实现方式差 不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可
以连接字符串。
2. 对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留
好。

5. string类非成员函数

函数名称 功能说明
operator+ 字符串拼接,返回拼接后的新字符串
operator>> / operator<< 流插入、流提取,实现 string 的输入输出
relational 运算符(==、!=、<、> 等) 按字典序比较两个 string 对象大小
getline(重点) 读取一行字符串,可读取空格,避免 cin 截断

6. vs和g++下string结构的说明

注意:下述结构是在32位平台下进行验证,32位平台下指针占4个字节。

vs下string的结构

string总共占28个字节,内部结构稍微复杂一点,先是有一个联合体,联合体用来定义
string中字符串的存储空间:
当字符串长度小于16时,使用内部固定的字符数组来存放
当字符串长度大于等于16时,从堆上开辟空间
这种设计也是有一定道理的,大多数情况下字符串的长度都小于16,那string对象创建
好之后,内部已经有了16个字符数组的固定空间,不需要通过堆创建,效率高。
其次:还有一个size_t字段保存字符串长度,一个size_t字段保存从堆上开辟空间总的
容量
最后:还有一个指针做一些其他事情。
故总共占16+4+4+4=28个字节。

g++下string的结构

G++下,string是通过写时拷贝实现的,string对象总共占4个字节,内部只包含了一个
指针,该指针将来指向一块堆空间,内部包含了如下字段:
空间总大小
字符串有效长度
引用计数

指向堆空间的指针,用来存储字符串。

复制代码
struct _Rep_base
{
    size_type         _M_length;
    size_type         _M_capacity;
    _Atomic_word      _M_refcount;
};

3.题目运用

917. 仅仅反转字母https://leetcode.cn/problems/reverse-only-letters/

给你一个字符串 s ,根据下述规则反转字符串:

  • 所有非英文字母保留在原有位置。
  • 所有英文字母(小写或大写)位置反转。

返回反转后的 s

题解:

复制代码
class Solution {
public:
    bool isletters(char& ch)
    {
        if(ch >= 'A' && ch <= 'Z')
        return true;
        if(ch >= 'a' && ch <= 'z')
        return true;

        return false;
        
    }
    string reverseOnlyLetters(string s) {
        if(s.empty())
        return s;
        int begin=0,end=s.size()-1;
        while(begin<end)
        {
            while(begin<end && !isletters(s[begin]))
            {
                begin++;
            }
            while(begin<end && !isletters(s[end]))
            {
                end--;
            }
            swap(s[begin],s[end]);
            begin++;
            end--;
        }  
         return s;
    }
    
};

387. 字符串中的第一个唯一字符https://leetcode.cn/problems/first-unique-character-in-a-string/

给定一个字符串 s ,找到 它的第一个不重复的字符,并返回它的索引 。如果不存在,则返回 -1

题解:

复制代码
class Solution {
public:
    int firstUniqChar(string s) {
        int count[256];
        for(int i=0;i<s.size();i++)
        {
            count[s[i]]++;
        }
        for(int j=0;j<s.size();j++)
        {
            if(count[s[j]]==1)
            return j;
        }
        return -1;
    }
};

相关推荐
炘爚1 小时前
C++(整理合集)
开发语言·c++
buhuizhiyuci1 小时前
[QT]QT入门的项目创建和项目代码的介绍
开发语言·qt
jieyucx1 小时前
Go 语言函数入门:定义、参数、返回值
c++·算法·golang·入门·函数
Codector1 小时前
在Ubuntu中使用Edge侧边栏无法添加和查看同步的侧边栏问题解决
笔记·ubuntu·develop
想成为优秀工程师的爸爸1 小时前
第二十四篇技术笔记:郭大侠学DoIP - 从“偶睡破庙”到“天字一号”
网络·笔记·网络协议·tcp/ip·信息与通信
XMYX-01 小时前
20 - Go 互斥锁:Mutex 与并发安全
开发语言·golang
天才少女爱迪生1 小时前
【迪士尼机器人】硬件接入记录(自用笔记版)
笔记
郝学胜-神的一滴1 小时前
深入epoll封装:event_set与event_add核心原理剖析
linux·服务器·开发语言·网络·c++·unix
啦啦啦_99991 小时前
2. 梯度下降算法分类 & 梯度下降与正规方程对比
人工智能·算法·分类