网站备案负责人照片,平面设计网站大全有哪些,织梦添加网站名称添加新变量,凉山州住房和城乡建设局门户网站目录
前言
一、string类
二、初始化
1、无参或带参
2、用字符串变量初始化
3、用字符串初始化
4、指定数量字符
三、容量操作
1、size
2、push_back
3、append编辑
4、运算符
5、reserve
6、resize
四、迭代器
1、正向迭代器
2、反向迭代器
3、const迭代器…目录
前言
一、string类
二、初始化
1、无参或带参
2、用字符串变量初始化
3、用字符串初始化
4、指定数量字符
三、容量操作
1、size
2、push_back
3、append编辑
4、运算符
5、reserve
6、resize
四、迭代器
1、正向迭代器
2、反向迭代器
3、const迭代器 正向反向
五、OJ练习
反转字符
找出字符串中出现一次的字符 前言
string类模板如下为什么会有好几个呢 这些不同的string类模板是为了处理不同的字符编码和字符集。每个模板都专门用于处理特定类型的字符数据。 std::string这是最常见的string类模板用于处理ASCII字符集。它使用单字节字符表示适用于大多数常规字符串操作。 std::wstring这是宽字符版本的string类模板用于处理Unicode字符。它使用wchar_t类型来表示字符适用于需要处理多语言字符集的情况。 std::u16string这是用于处理UTF-16编码的字符串的模板。UTF-16使用16位编码表示字符适用于处理较大的字符集如大部分Unicode字符。 std::u32string这是用于处理UTF-32编码的字符串的模板。UTF-32使用32位编码表示字符适用于处理包含所有Unicode字符的字符集。
这些不同的string类模板提供了对不同字符编码和字符集的支持以便在处理不同类型的文本数据时能够正确地表示和操作字符。通过选择适当的string类模板可以确保在不同的应用场景中正确处理和操作字符数据。 我们先来了解一下计算机存储字符的方式 计算机中都是二进制形式无法直接存储字母和符号这时就需要一个映射表ASCll就诞生了。 为了可以在计算机上显示多个国家的文字unicode诞生了 统一码Unicode也叫万国码、单一码由统一码联盟开发是计算机科学领域里的一项业界标准包括字符集、编码方案等。
统一码是为了解决传统的字符编码方案的局限而产生的它为每种语言中的每个字符设定了统一并且唯一的二进制编码以满足跨语言、跨平台进行文本转换、处理的要求。
Unicode字符编码方案分为UTF-8、UTF-16和UTF-32它们被设计用于在计算机系统中表示和处理不同范围的Unicode字符。 UTF-8UTF-8是一种变长编码方案它使用1到4个字节来表示不同的Unicode字符。它是最常用的Unicode编码方案之一因为它可以兼容ASCII字符集并且在表示常见字符时比较节省空间。UTF-8适用于在存储和传输文本数据时节省空间的情况特别是在互联网和计算机网络中广泛使用。 UTF-16UTF-16是一种定长或变长编码方案它使用16位编码来表示Unicode字符。对于大部分常见的Unicode字符UTF-16使用16位编码表示但对于一些较少使用的字符它需要使用两个16位编码来表示。UTF-16适用于需要处理较大字符集的情况如多语言文本处理和国际化应用。 UTF-32UTF-32是一种定长编码方案它使用32位编码来表示Unicode字符。每个Unicode字符都使用32位编码表示无论字符是否常见。UTF-32适用于需要处理包含所有Unicode字符的字符集的情况如某些特定领域的文本处理和字符级操作。
这些不同的Unicode编码方案提供了不同的权衡和适用性根据具体的需求和应用场景可以选择适当的编码方案来表示和处理Unicode字符。 其中UTF-8使用的最多 。 我们中国也有针对汉字的GBK编码对一些生僻字提供了支持。 一、string类
文档介绍 字符串是表示字符序列的类标准的字符串类提供了对此类对象的支持其接口类似于标准字符容器的接口但添加了专门用于操作单字节字符字符串的设计特性。 string类是使用char(即作为它的字符类型使用它的默认char_traits和分配器类型(关于模板的更多信息请参阅basic_string)。 string类是basic_string模板类的一个实例它使用char来实例化basic_string模板类并用char_traits和allocator作为basic_string的默认参数(根于更多的模板信息请参考basic_string)。 注意这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列这个类的所有成员(如长度或大小)以及它的迭代器将仍然按照字节(而不是实际编码的字符)来操作。 总结 string是表示字符串的字符串类 该类的接口与常规容器的接口基本相同再添加了一些专门用来操作string的常规操作。 string在底层实际是basic_string模板类的别名typedef basic_stringchar, char_traits, allocator string; 不能操作多字节或者变长字符的序列。 在使用string类时必须包含#include头文件string以及using namespace std; 二、初始化 默认构造函数 string()创建一个空字符串对象。 复制构造函数 string(const string str)通过复制另一个字符串对象 str 来创建一个新的字符串对象。 子字符串构造函数 string(const string str, size_t pos, size_t len npos)从字符串对象 str 的指定位置 pos 开始创建一个新的字符串对象长度为 len。如果未提供 len 参数默认创建到字符串末尾的子字符串。 从C-String构造函数 string(const char* s)从以空字符结尾的C字符串 s 创建一个新的字符串对象。 从序列构造函数 string(const char* s, size_t n)从C字符串 s 的前 n 个字符创建一个新的字符串对象。 填充构造函数 string(size_t n, char c)创建一个包含 n 个字符 c 的新字符串对象。 范围构造函数 template class InputIterator string(InputIterator first, InputIterator last)通过迭代器范围 [first, last) 中的字符创建一个新的字符串对象。这个构造函数可以接受不同类型的迭代器例如指针、容器的迭代器等。 1、无参或带参 既可以无参初始化 也可以带参初始化。 int main()
{string s1;string s2(hello world);string s3 hello;return 0;
} 我们也可以通过[ ]操作符访问字符串某个位置。 #includestring
int main()
{string s2(hello world);for (size_t i 0; i s2.size(); i) {s2[i];}cout s2 endl;return 0;
}
我们可以通过流插入运算符输出string类对象。 这是因为string类中对流插入运算符进行了重载流提取也进行了重载。 int main()
{string s2;cin s2;for (size_t i 0; i s2.size(); i) {s2[i];}cout s2 endl;return 0;
} 2、用字符串变量初始化 用一个字符的指定位置开始指定字符个数为另一个字符初始化。 int main()
{string s3 hello;string s4(s3, 2, 3);cout s4 endl;return 0;
} 如果取字符的个数超过字符总长度则取到末尾即可。 int main()
{string s3 hello;string s4(s3, 2, 3);cout s4 endl;string s5(s3, 2, 10);cout s5 endl;return 0;
} 第三个参数取字符整数可以缺省那么从指定位置开始取到末尾结束。 int main()
{string s3 hello;string s4(s3, 2, 3);cout s4 endl;string s5(s3, 2);cout s5 endl;return 0;
} 3、用字符串初始化 也可以把要赋值的字符串直接放在第一个参数位置第二个参数为赋值字符个数。 int main()
{string s7(hello world, 5);cout s7 endl;string s8(hello world, 5 , 6);cout s8 endl;return 0;
}
第一个构造函数中除字符串如果只有一个参数则默认从字符串第一个字符开始赋值第二个参数大小长度。第二个构造函数中除字符串如果有两个参数第一个参数为指定起始位置第二个参数为指定的初始化长度长度大于实际字符串的长度则截断为实际字符串的长度。 4、指定数量字符
int main()
{string s9(10, $);cout s9 endl;return 0;
} 三、容量操作
1、size size()与length()底层实现原理完全相同都用于获取字符串 有效字符长度 引入size()的原因是为了与其他容器的接口保持一致一般情况下基本都是用size()。 int main()
{string s1(hello world);cout s1.size() endl;cout s1.length() endl;return 0;
} 下面两个了解即可 max_size()函数返回一个无符号整数表示字符串对象可以容纳的最大字符数。这个值通常取决于系统的限制因此可能会因操作系统和编译器而异。capacity()函数返回一个无符号整数表示字符串对象当前分配的内存空间大小。这个值可能大于字符串实际包含的字符数因为字符串类通常会预留一些额外的空间以便进行扩展。 int main()
{string s1(hello world);cout s1.max_size() endl;cout s1.capacity() endl;return 0;
} 64位下输出结果 2、push_back 添加单个字符到字符串末尾 int main()
{string s1(hello);s1.push_back( );s1.push_back(!);cout s1 endl;return 0;
} 3、append 我们还可以使用append在字符串末尾添加单个字符或字符串 这种是最常用的形式。 int main()
{string s1(hello);s1.push_back( );s1.push_back(!);cout s1 endl;s1.append(world);cout s1 endl;
} 4、运算符 我们还可以使用运算符在字符串末尾添加字符或字符串底层是调用push_back或append在string尾部追加字符时s.push_back(c) / s.append(1, c) / s c三种的实现方式差不多一般情况下string类的操作用的比较多操作不仅可以连接单个字符还可以连接字符串。 int main()
{string s1(hello);s1 ;s1 !;s1 world;cout s1 endl;
} 5、reserve
先看下面代码
int main()
{size_t sz s.capacity();cout making s grow:\n;cout capacity changed: sz \n;for (int i 0; i 100; i){s.push_back(c);if (sz ! s.capacity()){sz s.capacity();cout capacity changed: sz \n;}}
}
上述演示了如何使用push_back()函数向字符串对象中添加字符并观察字符串的容量变化
首先在main()函数中声明了一个size_t类型的变量sz并将其初始化为字符串对象s的容量假设s是之前已经定义的字符串对象。然后通过使用cout对象和运算符输出一条提示信息making s grow:。接下来使用一个循环从0到99逐个向字符串对象s中添加字符c。在每次添加字符之后通过比较之前记录的容量sz和当前字符串对象s的容量来判断容量是否发生了变化。如果容量发生了变化将新的容量值赋给sz并使用cout对象和运算符输出一条提示信息capacity changed:以及新的容量值。 这里输出的容量不包括 \0也就是实际容量要再加1. 在监视中可以看到实际上将字符存入了_Buf数组中。 在C的实现中std::string类通常使用两个数组来存储字符串的字符。当字符串的长度小于等于15个字符时字符串的字符被存储在一个名为_Buf的内部固定大小数组中该数组长度为16。这样可以避免动态内存分配提高性能。 当字符串的长度超过15个字符时字符串的字符将被存储在一个名为_Ptr的动态分配的数组中该数组的长度将根据需要进行动态调整。这样可以容纳更长的字符串并且可以根据需要动态分配内存。 这种设计可以在字符串较短时节省内存并在字符串较长时提供足够的存储空间。具体的实现可能会因编译器和标准库的不同而有所差异但这种区分短字符串和长字符串的策略是常见的优化技术之一 vs下string的结构string总共占28个字节内部结构稍微复杂一点先是有一个联合体联合体用来定string中字符串的存储空间 当字符串长度小于16时使用内部固定的字符数组来存放 当字符串长度大于等于16时从堆上开辟空间 union _Bxty
{ // storage for small buffer or pointer to larger onevalue_type _Buf[_BUF_SIZE];pointer _Ptr;char _Alias[_BUF_SIZE]; // to permit aliasing
} _Bx;
这种设计也是有一定道理的大多数情况下字符串的长度都小于16那string对象创建好之后内 部已经有了16个字符数组的固定空间不需要通过堆创建效率高。 其次还有一个size_t字段保存字符串长度一个size_t字段保存从堆上开辟空间总的容量 最后还有一个指针做一些其他事情。 故总共占1644428个字节。 输出查看一下string类对象s的大小 string s;cout sizeof(s) endl; 可以看到是28那么它在堆上起始就是大小32。 观察扩容情况可以发现从大小32开始每次1.5倍扩容。 在已知所需空间大小时我们可以使用reserve提前开辟空间减少扩容提高效率。 使用reverse一次性开辟100个字符空间。
int main()
{string s;s.reserve(100);size_t sz s.capacity();cout making s grow:\n;cout capacity changed: sz \n;for (int i 0; i 100; i){s.push_back(c);if (sz ! s.capacity()){sz s.capacity();cout capacity changed: sz \n;}}
}
这时就不需要一次次扩容了。 对string操作时如果能够大概预估到放多少字符可以先通过reserve把空间预留好。 6、resize resize将字符串大小调整为n个字符的长度。 如果n小于当前字符串长度则将当前值缩短到前n个字符删除第n个字符以外的字符。如果n大于当前字符串长度则通过在末尾插入尽可能多的字符来扩展当前内容以达到n的大小。如果指定了填充字符c则新元素被初始化为c的副本否则它们是值初始化的字符(空字符)。
int main()
{// 扩容string s1(hello world);s1.reserve(100);cout s1.size() endl;cout s1.capacity() endl;// 扩容初始化string s2(hello world);s2.resize(100);cout s2.size() endl;cout s2.capacity() endl;return 0;
}
resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个不同的是当字符个数增多时resize(n)用0来填充多出的元素空间resize(size_t n, char c)用字符c来填充多出的元素空间。注意resize在改变元素个数时如果是将元素个数增多可能会改变底层容量的大小如果是将元素个数减少底层空间总大小不变。
reserve(size_t res_arg0)为string预留空间不改变有效元素个数当reserve的参数小于string的底层空间总大小时reserver不会改变容量大小。 四、迭代器
1、正向迭代器 begin指向字符串第一个字符end指向字符串最后一个字符的后一个位置功能和指针类似。 int main()
{string s1(hello world);string::iterator it s1.begin();while (it ! s1.end()) {cout *it ;it;}return 0;
} 范围for底层就是调用迭代器实现的。 int main()
{string s1(hello world);string::iterator it s1.begin();while (it ! s1.end()) {cout *it ;it;}cout endl;for (auto ch : s1) {cout ch ;}cout endl;
} 2、反向迭代器 rbegin指向字符串最后一个字符rend指向字符串的第一个字符的前一个位置。 int main()
{string::reverse_iterator rit s1.rbegin();while (rit ! s1.rend()) {cout *rit ;rit;}cout endl;return 0;
} 3、const迭代器 正向反向 const正向反向迭代器只能遍历和读数据。 int main()
{string s1(hello world);string::const_iterator it s1.begin();while (it ! s1.end()) {cout *it ;it;}cout endl;string::const_reverse_iterator rit s1.rbegin();while (rit ! s1.rend()) {cout *rit ;rit;}cout endl;cout s1 endl;return 0;
} 这时可以借助auto自动推导类型。 int main()
{//string::const_iterator it s1.begin();auto it s1.begin();while (it ! s1.end()) {cout *it ;it;}cout endl;//string::const_reverse_iterator rit s1.rbegin();auto rit s1.rbegin();while (rit ! s1.rend()) {cout *rit ;rit;}cout endl;return 0;
} 五、OJ练习
反转字符
917. 仅仅反转字母 - 力扣LeetCode 采用快速排序的思路。 class Solution {
public:string reverseOnlyLetters(string s) {size_t begin 0, ends.size()-1;while(beginend){while(beginend!isalpha(s[begin]))begin;while(beginend!isalpha(s[end]))--end;swap(s[begin],s[end]);begin;--end;}return s;}
};
找出字符串中出现一次的字符 387. 字符串中的第一个唯一字符 - 力扣LeetCode 采用计数排序的思路。 class Solution {
public:int firstUniqChar(string s) {int count[26]{0};for(auto ch:s){count[ch-a];}for(int i0;is.size();i){if(count[s[i]-a]1)return i;}return -1;}
};