【C++】STL学习之旅——初识STL,认识string类

简介: 现在我正式开始学习STL,这让我期待好久了,一想到不用手撕链表,手搓堆栈,心里非常爽

string类

1 STL 简介

现在我正式开始学习STL,这让我期待好久了,一想到不用手撕链表,手搓堆栈,心里非常爽。接下来我们先来介绍一下STL:

STL,英文全称 standard template library,中文可译为标准模板库或者泛型库,其包含有大量的模板类和模板函数,是 C++ 提供的一个基础模板的集合,用于完成诸如输入/输出、数学计算等功能。 STL 最初由惠普实验室开发,于 1998 年被定为国际标准,正式成为 C++ 程序库的重要组成部分。


主要分为这几个版本:HP STL、SGI STL、STLport、PJ STL、Rouge Wave STL 等

其中我们需要重点学习的是SGI版本:

SGI版本由Silicon Graphics Computer Systems,Inc公司开发,继承自HP版本。被GCC(Linux)采用,可移植性好,可公开、修改甚至贩卖,从命名风格和编程 风格上看,阅读性非常高。学习STL 要阅读部分源代码,主要参考的就是这个版本

2 STL怎么学习

网上有句话说:“不懂STL,不要说你会C++”。STL是C++中的优秀作品,有了它的陪伴,许多底层的数据结构以及算法都不需要自己重新造轮子,站在前人的肩膀上,健步如飞的快速开发。那么我们应该如何学习呢?

首先就是关注官方网站 C++中查阅资料。我推荐使用这个:C++库

然后 学好英语很重要,要学会阅读文档,无论学习什么新技术,英语绝对是必不可少的。(程序员的尽头是英语)

3 STL缺陷

  1. STL库的更新太慢了。这个得严重吐槽, 上一版靠谱是C++98,中间的C++03基本一些修订。C++11出来已经相隔了13年,STL才进一步更新。
  2. STL现在都没有支持线程安全。并发环境下需要我们自己加锁。且锁的粒度是比较大的。
  3. STL极度的追求效率,导致内部比较复杂。比如类型萃取,迭代器萃取。
  4. STL的使用会有代码膨胀的问题,比如使用vector/vector/vector这样会生成多份代码,当然这是模板语法本身导致的

4 string

接下来让我们开始学习string类吧:

4.1 初识 string

根据上面我们进行的搜索我们可以了解到 :

  1. string是一个代表字符串的对象。
  2. 标准string类提供了类似标准字符容器的接口,而且添加了单字节操作的特性。
  3. string类 是 basic_string类模版的一个实例,使用char类型来实例化basic_string 模版类。
  4. 注意这个类独立于所使用的编码来处理字节: 如果使用 multi-byte 或 多长度字符(例如UTF-8编码),这个类的所有成员(比如 长度和大小),以及该类的迭代器将仍然在该字节(而不是实际的编码字符)来操作。

可以总结为以下内容:

  1. string是表示字符串的字符串类
  2. 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
  3. string在底层实际是:basic_string模板类的别名,typedef basic_string

allocator>string;

  4,不能操作多字节或者变长字符的序列

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

4.2 初步使用

构造函数

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

来看使用效果:

#include<string>
#include<iostream>
using namespace std;

int main() {
  string s1;
  string s2("Hello!");
  string s3(5,'n');
  string s4(s2);

  cout << s1 << endl;
  cout << s2 << endl;
  cout << s3 << endl;
  cout << s4 << endl;

  return 0;
}

流操作符也在string类中进行了重载,输出很丝滑~

成员函数

成员函数 作用
begin() 返回字符首位置 (迭代器常用 )
end() 返回字符结尾 (迭代器常用)
size(重点) 返回字符串有效字符长度
length 返回字符串有效字符长度
capacity 返回空间总大小
empty (重点) 检测字符串释放为空串,是返回true,否则返回false
clear (重点) 清空有效字符
reserve (重点) 为字符串预留空间
resize (重点) 将有效字符的个数该成n个,多出的空间用字符c填充

来使用一下:

#include<string>
#include<iostream>
using namespace std;

int main() {

  string s1("Hello!");

  cout << s1 << endl;
  //有效字符长度
  cout <<"有效字符长度:" << s1.size() << endl;
  //字符串所占空间
  cout << "字符串所占空间:" << s1.capacity() << endl;
  //实际长度(不包括‘\0')
  cout << "实际长度:" << s1.length() << endl;
  //检查是否为空 (为空返回1 不为空返回0)
  cout <<"是否为空:" << s1.empty() << endl;


  //-----------清空试试-------
  cout << "\n---------清空--------\n";
  s1.clear();
  cout << s1 << endl;
  //有效字符长度
  cout << "有效字符长度:" << s1.size() << endl;
  //字符串所占空间
  cout << "字符串所占空间:" << s1.capacity() << endl;
  //实际长度(不包括‘\0')
  cout << "实际长度:" << s1.length() << endl;
  //检查是否为空 (为空返回1 不为空返回0)
  cout << "是否为空:" << s1.empty() << endl;

  //--------更改大小-------
  cout << "\n---------更改有效字符个数--------\n";
  s1.resize(10, 'a');
  cout << s1 << endl;
  //有效字符长度
  cout << "有效字符长度:" << s1.size() << endl;
  //字符串所占空间
  cout << "字符串所占空间:" << s1.capacity() << endl;
  //实际长度(不包括‘\0')
  cout << "实际长度:" << s1.length() << endl;
  //检查是否为空 (为空返回1 不为空返回0)
  cout << "是否为空:" << s1.empty() << endl;
  return 0;
}

看看运行效果:

这样,对string就有了一个大概了解。

有些注意事项:

  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不会改变容量大小

5 小试牛刀

家人们! 上链接!!!:字符串相加

我们来尝试使用我们刚刚学习的string来解决问题:

首先:我们不能简单的进行字符串转换为整数,然后相加,最后转换为字符串。你问我为什么?

请看VCR:

测试用例没问题,但是Leetcode给我们的数据太大了,longlong都没办法容纳。

所以我们使用最朴素的算法:竖式算法

很简单 依次相加 按运算法则进位 得到该位的数值然后插入到string即可。

class Solution {
public:
    string addStrings(string num1, string num2) {
      // 从个位开始,所以取字符串末位
        int i = num1.length() - 1;
        int j = num2.length() - 1;
        // 计算所需变量
        int n1 = 0,n2 = 0 ,carry = 0;
        //答案string对象
        string ans = "";
        //开始计算
        while(i >= 0 || j >= 0 || carry != 0 ){
        //这里一定要写判断,不然会发生数组越界。
            n1 = i >= 0 ? num1[i] - '0' : 0; 
            n2 = j >= 0 ? num2[j] - '0' : 0;
            //得到结构就尾插
            ans.push_back((n1 + n2 + carry) % 10 + '0');
            //迭代
            carry = (n1 + n2 + carry) / 10;
            i--;
            j--;

        }
        //注意因为我们是尾插的,所以要调换头尾顺序才可以
        //这里使用 对称对调法。
        for(int k = 0 ;k<ans.size()/2;k++){
            char tmp = ans[k] ;
            ans[k] = ans[ans.size() - 1 - k];
            ans[ans.size() - 1 - k] = tmp;
        }
        //这个函数更方便,但是不方便解释了在这里
        //reverse(ans.begin(),ans.end());
        return ans;
    }
};

来看效果奥:

牛批!!!!! 过啦!!!!

Thanks♪(・ω・)ノ谢谢阅读!!!

下一篇文章见!!!

相关文章
|
3月前
|
编译器 C++ 容器
【c++丨STL】基于红黑树模拟实现set和map(附源码)
本文基于红黑树的实现,模拟了STL中的`set`和`map`容器。通过封装同一棵红黑树并进行适配修改,实现了两种容器的功能。主要步骤包括:1) 修改红黑树节点结构以支持不同数据类型;2) 使用仿函数适配键值比较逻辑;3) 实现双向迭代器支持遍历操作;4) 封装`insert`、`find`等接口,并为`map`实现`operator[]`。最终,通过测试代码验证了功能的正确性。此实现减少了代码冗余,展示了模板与仿函数的强大灵活性。
99 2
|
15天前
|
对象存储 C++ 容器
c++的string一键介绍
这篇文章旨在帮助读者回忆如何使用string,并提醒注意事项。它不是一篇详细的功能介绍,而是一篇润色文章。先展示重载函数,如果该函数一笔不可带过,就先展示英文原档(附带翻译),最后展示代码实现与举例可以直接去看英文文档,也可以看本篇文章,但是更建议去看英文原档。那么废话少说直接开始进行挨个介绍。
|
3月前
|
存储 算法 C++
【c++丨STL】map/multimap的使用
本文详细介绍了STL关联式容器中的`map`和`multimap`的使用方法。`map`基于红黑树实现,内部元素按键自动升序排列,存储键值对,支持通过键访问或修改值;而`multimap`允许存在重复键。文章从构造函数、迭代器、容量接口、元素访问接口、增删操作到其他操作接口全面解析了`map`的功能,并通过实例演示了如何用`map`统计字符串数组中各元素的出现次数。最后对比了`map`与`set`的区别,强调了`map`在处理键值关系时的优势。
206 73
|
15天前
|
存储 编译器 C语言
关于string的‘\0‘与string,vector构造特点,反迭代器与迭代器类等的讨论
你真的了解string的'\0'么?你知道创建一个string a("abcddddddddddddddddddddddddd", 16);这样的string对象要创建多少个对象么?你知道string与vector进行扩容时进行了怎么的操作么?你知道怎么求Vector 最大 最小值 索引 位置么?
|
3月前
|
缓存 安全 Java
《从头开始学java,一天一个知识点》之:字符串处理:String类的核心API
🌱 **《字符串处理:String类的核心API》一分钟速通!** 本文快速介绍Java中String类的3个高频API:`substring`、`indexOf`和`split`,并通过代码示例展示其用法。重点提示:`substring`的结束索引不包含该位置,`split`支持正则表达式。进一步探讨了String不可变性的高效设计原理及企业级编码规范,如避免使用`new String()`、拼接时使用`StringBuilder`等。最后通过互动解密游戏帮助读者巩固知识。 (上一篇:《多维数组与常见操作》 | 下一篇预告:《输入与输出:Scanner与System类》)
98 11
|
3月前
|
存储 算法 C++
【c++丨STL】set/multiset的使用
本文深入解析了STL中的`set`和`multiset`容器,二者均为关联式容器,底层基于红黑树实现。`set`支持唯一性元素存储并自动排序,适用于高效查找场景;`multiset`允许重复元素。两者均具备O(logN)的插入、删除与查找复杂度。文章详细介绍了构造函数、迭代器、容量接口、增删操作(如`insert`、`erase`)、查找统计(如`find`、`count`)及`multiset`特有的区间操作(如`lower_bound`、`upper_bound`、`equal_range`)。最后预告了`map`容器的学习,其作为键值对存储的关联式容器,同样基于红黑树,具有高效操作特性。
138 3
|
3月前
|
Java
课时14:Java数据类型划分(初见String类)
课时14介绍Java数据类型,重点初见String类。通过三个范例讲解:观察String型变量、&quot;+&quot;操作符的使用问题及转义字符的应用。String不是基本数据类型而是引用类型,但使用方式类似基本类型。课程涵盖字符串连接、数学运算与字符串混合使用时的注意事项以及常用转义字符的用法。
|
3月前
|
存储 JavaScript Java
课时44:String类对象两种实例化方式比较
本次课程的主要讨论了两种处理模式在Java程序中的应用,直接赋值和构造方法实例化。此外,还讨论了字符串池的概念,指出在Java程序的底层,DOM提供了专门的字符串池,用于存储和查找字符串。 1.直接赋值的对象化模式 2.字符串池的概念 3.构造方法实例化
|
4月前
|
存储 算法 C++
【c++丨STL】priority_queue(优先级队列)的使用与模拟实现
本文介绍了STL中的容器适配器`priority_queue`(优先级队列)。`priority_queue`根据严格的弱排序标准设计,确保其第一个元素始终是最大元素。它底层使用堆结构实现,支持大堆和小堆,默认为大堆。常用操作包括构造函数、`empty`、`size`、`top`、`push`、`pop`和`swap`等。我们还模拟实现了`priority_queue`,通过仿函数控制堆的类型,并调用封装容器的接口实现功能。最后,感谢大家的支持与关注。
184 1
|
7月前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
223 2