C++的STL模块

C++

3. STL

3.1 STL介绍

概念:STL(Standard Template Library, 标准模板库),是C++标准库的一部分,提供了一些通用的模板类和模板函数,用于实现各种数据结构,如链表、向量、栈、队列、集合、映射等。STL提供了丰富的数据结构和算法,可以减少开发人员编写代码的时间和空间开销,提高开发效率。
STL从广义上分为:容器(Container)、迭代器(Iterator)、算法(Algorithm),容器和算法之间通过迭代器进行无缝连接。STL几乎所有的代码都采用了模板类或者模板函数,这相比传统的由函数和类组成的库来说提供了更好的代码复用机会。
STL六大组件

  1. 容器:各种数据结构。STL提供了多种容器,如vector、list、deque、set、map、stack、queue等,这些容器都实现了一些基本的数据结构操作,如插入、删除、查找、排序等。
  2. 算法:各种常用的算法,如sort、find、copy、for_each、transform、remove、replace等。
  3. 迭代器:用于遍历容器的指针,扮演了容器和算法之间的胶合作用。共有五种类型,从实现角度看,迭代器是一种将operator*、operator->、operator++、operator–等指针相关操作予以重载的class template,所有STL容器都附带有自己专属的迭代器,只有容器的设计者才知道如何遍历自己的元素。原生指针(native opinter)也是一种迭代器。
  4. 仿函数:行为类似函数,可作为算法的某种策略。从实现角度来看,仿函数是一种重载了operator()的class或者class template。
  5. 适配器:一种用于修饰容器或者仿函数或者迭代器接口的东西。
  6. 空间配置器:负责空间的配置与管理。从实现角度看,容器是一个实现了动态空间配置、空间管理、空间释放的class template。

优点
STL是C++标准库的一部分,不需要额外安装。
STL的一个重要特性是将数据和操作分离。数据由容器类别加以管理,操作则由可定制的算法定义。迭代器在两者之间进行无缝连接,以使算法可以和容器交互运作。程序员不需要思考STL具体地实现过程,只要熟练使用即可。

高可重用性:STL中几乎所有的代码都采用了模板类和模板函数的方式实现。
高性能:如map可以高效地从十万条记录里面查找出指定的记录,因为map是采用红黑树的变体实现的。
高移植性:如在项目A上用STL编写的模块,可以直接移植到项目B上。

3.2 容器、算法、迭代器介绍

3.2.1 容器

STL容器就是将运用最广泛的一些数据结构实现出来。
常用的数据结构:数组(array)、链表(list)、树(tree)、栈(stack)、队列(queue)、集合(set)、映射表(map),根据数据在容器中的排列特性,可以分为序列式容器和关联式容器。

序列式容器强调值的排序,序列式容器中的每个元素都有固定的位置,除非用删除或者插入的操作改变这个位置。Vector容器、Deque容器、List容器等。
关联式容器是非线性的树结构,更准确地说是二叉树结构。各元素之间没有严格的物理上的顺序关系,也就是说元素在容器中并没有保存元素置入容器时的逻辑顺序。在值中选择一个值作为关键字key,这个关键字对值起到索引的作用,方便查找。Set/multiset容器、Map/multimap容器。

容器可以嵌套容器。

3.2.2 算法

STL收录的算法经过了数学上的效能分析与证明,是极具复用价值的,包括常用的排序、查找等。特定的算法往往搭配特定的数据结构,算法与数据结构相辅相成。
算法分为:质变算法非质变算法

质变算法:算法操作的元素会改变,例如sort、reverse、rotate、unique、replace、remove等。
非质变算法:算法操作的元素不会改变,例如find、count、copy、for_each、transform、remove_copy等。

3.2.3 迭代器

迭代器:提供一种方法,使之能够依序寻访某个容器所含的元素,而又无需关心这些元素的底层存储方式。
迭代器种类:

类型 描述 支持的操作
输入迭代器 提供对数据的只读访问 只读,支持++、==、!=
输出迭代器 提供对数据的只写访问 只写,支持++
前向迭代器 提供读写操作,并能向前推进迭代器 读写,支持++、==、!=
双向迭代器 提供读写操作,并能向前和向后操作 读写,支持++、–
随机访问迭代器 提供读写操作,并能任意移动迭代器 读写,支持++、–、[n]、-n、<、<=、>、>=

3.3 STL中的容器

3.3.1 string容器

C风格字符串(以空格符结尾的字符数组)太过复杂,不适合大程序开发,所以C++标准库定义了一种string类。
C++的字符串与C语言的字符串比较:

  • C语言:char*是一个指针。
  • C++:
    • string是一个类,内部封装了char*,用来管理这个容器。
    • string类中封装了很多的功能函数,例如:find、copy、delete、replace、insert等。
    • 不用考虑内存释放和越界的问题。

string管理char*所分配的内存。每一个string的复制,取值都由string类负责维护,不用担心复制越界和取值越界等。

3.3.1.1 string容器的构造
// string构造
void test1(){
    // 无参构造,创建一个空字符串
    string str1; // 等于string str = string();

    //通过一个string去构造另一个string
    string str2 = string("hello world");

    //通过一个char(字符)数组去构造一个string
    const char* array = "hello world";
    string str3 = string(array);

    // 通过指定数量的指定字符,构造一个字符串
    string str4 = string(5,'A'); // 内容是:AAAAA
};
3.3.1.2 string的赋值

// string赋值

void test2(){
    string str1;
    // 通过等号赋值,等号已经被string进行了运算符重载
    // 通过字符串赋值
    str1 = "hello world";

    // 通过字符数组赋值
    const char* arr = "abc";
    str1 = arr;

    // 通过字符赋值
    str1 = 'a';

    // assign函数。都是&引用,即可以链式操作。
    str1.assign("hello world");
    str1.assign(arr);
    str1.assign(5,'A');
    // string& assign(const char* s, int n); 把字符串s的前n个字符赋值给string
    str1.assign("hello world",5);
    cout << str1 << endl;
    // string& assign(const char* s, int start, int n); 将s从start开始n个字符赋值给字符串
    str1.assign("hello world",3,4); // llo w

}
3.3.1.3 string存取字符操作
// string的存取字符操作
void test3(){
    // 通过下标访问
    // char& operator[](int n); 通过[]访问
    // char& at(int n); 通过at访问
    string str1 = "hello world";
    cout << str1[2] << endl;
    cout << str1.at(4) << endl;
    str1[2] = 'a';
    str1.at(4) = 'a';
    cout << str1 << endl;

    // 使用了&引用(取别名)
    // 使用字符引用返回值,存储字符串中指定下标位字符的引用。
    char& c = str1[4];
    // 修改引用的值,这里引用的是字符串中的字符数组中的指定下标位的元素,所以c改变,数组中也会对应改变。
    c = '!';
    cout << str1 << endl;

    // 注意:
    //      一旦字符串中的字符数组内存重新分配了,使用之前的引用再进行空间访问,可能会出现问题。
    // 重写分配的情况:c++中,字符串长度小于16位时,空间开辟在栈上,超过16位,重新分配内存。
    // c_str: 将C++风格的字符串转换成C风格的字符串(返回的是C++的string类中维护的那个字符数组的指针)
    cout << (int*)str1.c_str() << endl; // 原来地址
    str1 = "12345678901234"; // 重新赋值,长度未超过16位,不会重新分配内存,地址不发生改变
    cout << c << endl; // 输出引用
    str1 = "12345678901234567"; // 重新赋值,长度超过16位,会重新分配内存,地址发生改变
    cout << (int*)str1.c_str() << endl; // 新地址
//    cout << c << endl; //地址改变,引用的c地址已经被释放了
}
3.3.1.4 string拼接
// string拼接
void test4(){
    string str = "hello";
    // +
    string str1 = str + "world";
    // += 后面跟需要加上的字符或字符串或者字符数组
    str += "world";
    // append函数
    // string& append(const char* s);
    str.append("world");
    // string& append(const char* s, int n); 把字符串前n个字符拼接到当前字符串结尾
    str.append("world",5);
    // string& append(const string& str); 把字符串拼接到当前字符串结尾,同 +=
    // string& append(const string& str, int start, int n); 把字符串从start开始n个字符拼接到当前字符串结尾
    str.append("world",3,4);
    // string& append(int n, char c); 把n个字符c拼接到当前字符串结尾
    str.append(5,'A');
    cout << str << endl;

}
3.3.1.5 string查找和替换
// string查找和替换
void test5(){
    string str = "hello world! hello1 world1!";
    // 查找 find:第一次出现的位置,返回首字符的位置下标
    // int find(const string& str, int pos); 从pos位置开始查找字符串str第一次出现的位置,pos默认是0
    // int find(const char* s, int pos); 从pos位置开始查找字符串s第一次出现的位置
    // int find(const char* s, int pos, int n); 从pos位置开始查找字符串s前n个字符第一次出现的位置
    // int find(char c, int pos); 从pos位置开始查找字符c第一次出现的位置
    cout << str.find("world") << endl;
    cout << str.find("world1", 10) << endl;
    cout << str.find("world1", 5, 5) << endl;
    cout << str.find('1') << endl;
    // 如果找不到,返回-1
    cout << str.find("hello2") << endl; //这个却并不是-1
    int res = str.find("hello2"); // 现在是-1
    cout << res << endl;

    // 查找rfind :最后一次出现的位置,从后往前找
    // int rfind(const string& str, int pos) const; // 查找字符串str最后一次出现的位置,pos默认最大值
    // int rfind(const char* s, int pos, int n) const; // 查找字符串s的前n个字符最后一次出现的位置
    // int rfind(const char c, int pos) const; // 查找字符c最后一次出现的位置
    cout << str.rfind("world") << endl;
    cout << str.rfind("world1", 10) << endl; // 从后往前找,从pos往前找,即从10->0的位置找

    // 替换
    // string& replace(int start, int n, const string& str); 从start位置开始,删除n个字符,并用字符串str替换
    // string& replace(int start, int n, const char* s); 从start位置开始,删除n个字符,并用字符串s替换
    cout << str.replace(0,5,"no") << endl; // 返回的是这个string对象本身,即str也会发生改变
    cout << str << endl;
}

3.3.1.6 string的比较
// string比较
void test6(){
    // 字符串大小比较规则:比的是字典顺序(更加深入来说,就是字符在字符集中的映射的数字)
    // 依次比较字符串中的每一位字符,如果字符相同࿰
  • 32
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值