IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> STL(标准模板库) -> 正文阅读

[数据结构与算法]STL(标准模板库)

概念:

STL:标准模板库,是C++标准库的重要组成部分,STL,英文全称 standard template library,中文可译为标准模板库或者泛型库,其包含有大量的模板类和模板函数,STL 是一些容器、算法和其他一些组件的集合,所有容器和算法都是总结了几十年来算法和数据结构的研究成果,注意,这里提到的容器,本质上就是封装有数据结构的模板类,例如 list、vector、set、map 等,

由概念便可以知道,STL中的所有数据结构都是以模板的方式创建的

容器(数据结构),算法(算法),迭代器(算法访问容器元素的工具),

C++ STL 一共提供了六大组件,包括?容器,算法,迭代器,仿函数,配接器和配置器?,彼此可以组合套用。

容器通过配置器取得数据存储空间;

算法通过迭代器存取容器内容;

仿函数可以协助算法完成不同的策略变化;

配接器可以应用于容器、仿函数和迭代器。

  1. 容器:包括各种数据结构,如vector,queue, deque,,set, map,用来存放数据,分为序列式容器和关联式容器,实现的角度来讲是一种类模板。

容器可分为:序列式容器,关联式容器

序列式:容器中的元素有顺序关系

关联式:容器中的元素不要求有顺序关系

2、算法:各种常用的算法,问题的解法,如sort (插入,快排,堆排序), search (二分查找),从实现的角度来讲是一种方法模板。

3、迭代器:从实现的角度来看,迭代器是一种将 operator,operator->,operator++,operator-等指针相关操作赋予重载的类模板,所有的 STL 容器都有自己的迭代器。是容器和算法的粘合剂,算法要通过迭代器才可以访问容器中的元素,迭代器会通过自己的方法找到容器中的元素,

4、仿函数:从实现的角度看,仿函数是一种重载了 operator() 的类或者类模板。可以帮助算法实现不同的策略。

5、配接器:一种用来修饰容器或者仿函数或迭代器接口(参数)的东西。

6、配置器:负责空间配置与管理,从实现的角度讲,配置器是一个实现了动态空间配置、空间管理,空间释放的类模板。

vector(向量)

怎么使用:

  1. 包含头文件vector和命名空间std

vector 容器以类模板 vector<T>( T 表示存储元素的类型)的形式定义在 <vector> 头文件中,并位于 std 命名空间中。

  1. 五种创建容器方法:

(1)先创建空容器,再添加容器容量和元素

(2)创建的同时初始化容器元素

vector<T> v5{a,b,c...}

vector<T> v5={a,b,c...}

  1. 创建的同时指定容器容量,不给出容器元素

vector<T> v4(n)
说明:包含n个重复执行了值初始化的对象(即值为0)

  1. 创建的同时指定容器容量和重复元素

vector<T> v3(n,val)
说明:包含n个重复的val元素

(5)通过存储元素类型相同的其它 vector 容器,也可以创建

的 vector 容器,例如:

vector<T> v1

vector<T> v2(v1)

vector<T> v2 = v1

如果不想复制其它容器中所有的元素,可以用一对指针或者迭代器来指定初始值的范围,例如:

纯文本复制

  1. int?array[]={1,2,3};
  2. std::vector<int>values(array,?array+2);//values 将保存{1,2}
  3. std::vector<int>value1{1,2,3,4,5};
  4. std::vector<int>value2(std::begin(value1),std::begin(value1)+3);//value2保存{1,2,3}


vector模板的成员函数:

函数成员

函数功能

begin()

返回指向容器中第一个元素的迭代器

end()

返回指向容器最后一个元素所在位置后一个位置的迭代器,通常和 begin() 结合使用。

rbegin()

返回指向最后一个元素的迭代器。

rend()

返回指向第一个元素所在位置前一个位置的迭代器。

cbegin()

和?begin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。

cend()

和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。

crbegin()

和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。

crend()

和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。

size()

返回实际元素个数。

max_size()

返回元素个数的最大值。这通常是一个很大的值,一般是 232-1,所以我们很少会用到这个函数。

resize()

改变实际元素的个数。resize(10):指定容量,不指定多出来的元素,系统默认用0代替(注意:此时被0代替的位置也有元素0);resize(10,23):指定容量,多出来的用23填补;如果指定的容量比原来小,多出来的则被删除,被删除的迭代器将失效

capacity()

返回当前容量.(不是容量元素个数),capacity 一般大于size的原因是为了避免 每次增加数据时都要重新分配内存,所以一般会 生成一个较大的空间,以便随后的数据插入,capacity返回的是以元素个数为单位的容量

empty()

判断容器中是否有元素,若无元素,则返回 true;反之,返回 false。

reserve()

为容器预留容量空间(注意预留的是容量空间,不要拿size()的返回值和reserve()的返回值作比较)。容器每一次存储新的内存,都会从新开辟新的空间如果提前知道容器元素个数和容器容量,可以提前为容器预留容量空间,reserve只适用于vector和string

shrink _to_fit()

将内存减少到等于当前元素实际所使用的大小。

operator[ ]

重载了?[ ] 运算符,可以向访问数组中元素那样,通过下标即可访问甚至修改 vector 容器中的元素。

at()

使用经过边界检查的索引访问指定位置的元素。

front()

返回第一个元素的引用。

back()

返回最后一个元素的引用。

data()

返回指向容器中第一个元素的指针。

assign()

用新元素替换原有内容。

push_back()

一次在序列的尾部添加一个元素。

pop_back()

移出序列尾部的元素。

insert()

在指定的位置插入一个或多个元素。insert(++v1.begin(),50)

erase()

移出一个元素或一段元素。erase(v1.begin(),v1.end())

clear()

移出所有的元素,容器大小变为 0。

swap()

交换两个容器的所有元素。

emplace()

在指定的位置直接生成一个元素。

emplace_back()

在序列尾部生成一个元素。

resize()增加容器元素个数才可以增加容器元素,reserve()增加容器容量,不可以增加容器元素

仅通过 reserve() 成员函数增加 value 容器的容量,其大小并没有改变;但通过 resize() 成员函数改变 value 容器的大小,它的容量可能会发生改变。另外需要注意的是,通过 resize() 成员函数减少容器的大小(多余的元素会直接被删除),不会影响容器的容量。

圆括号 () 和大括号 {} 是有区别的,前者(vector<int>v(20) )表示元素的个数,而后者(vector<int>v{20} ) 则表示 vector 容器中只有一个元素 20。

我们可能需要将容器的容量和大小保存在变量中,要知道 vector<T> 对象的容量和大小类型都是 vector<T>::size_type 类型。因此,当定义一个变量去保存这些值时,可以如下所示:

  1. vector<int>::size_type cap =?value.capacity();
  2. vector<int>::size_type size =?value.size();

size_type 类型是定义在由 vector 类模板生成的 vecotr 类中的,它表示的真实类型和操作系统有关,在 32 位架构下普遍表示的是 unsigned int 类型,而在 64 位架构下普通表示 unsigned long 类型。

迭代器的使用:

什么是迭代器:

迭代器就是地址

迭代器和?C++?的指针非常类似,它可以是需要的任意类型,通过迭代器可以指向容器中的某个元素,如果需要,还可以对该元素进行读/写操作。

注意迭代器不是引用,可以用迭代器作实参传递去改变容器内容,但是形参不要定义为引用,直接定义为:

template<typename I>

void container_change(I i){};

?vector 支持迭代器的成员函数

成员函数

功能

begin()

返回指向容器中第一个元素的正向迭代器;如果是 const 类型容器,在该函数返回的是常量正向迭代器。

end()

返回指向容器最后一个元素之后一个位置的正向迭代器;如果是 const 类型容器,在该函数返回的是常量正向迭代器。此函数通常和 begin() 搭配使用。

rbegin()

返回指向最后一个元素的反向迭代器;如果是 const 类型容器,在该函数返回的是常量反向迭代器。

rend()

返回指向第一个元素之前一个位置的反向迭代器。如果是 const 类型容器,在该函数返回的是常量反向迭代器。此函数通常和 rbegin() 搭配使用。

cbegin()

和 begin() 功能类似,只不过其返回的迭代器类型为常量正向迭代器,不能用于修改元素。

cend()

和 end() 功能相同,只不过其返回的迭代器类型为常量正向迭代器,不能用于修改元素。

crbegin()

和 rbegin() 功能相同,只不过其返回的迭代器类型为常量反向迭代器,不能用于修改元素。

crend()

和 rend() 功能相同,只不过其返回的迭代器类型为常量反向迭代器,不能用于修改元素。

vector<int>::iterator//vector<>模板类中的迭代器

vector<>模板和普通数组很相似,也叫单端数组。

vector<>容器和普通数组的区别:

普通数组的容量是固定的,vector<>容器的容量是可以变的,即动态的。

vector<>容量的动态扩展不是在原有空间的基础上增加新空间,而是找到更大的空间,把原数据拷贝到找到的空间,再释放原空间

vector<int>v2(v1.begin(),v1.end());

将v1中所有的数据复制到v2中

同样功能可以用:

vector<int>v2;

v2.assign(v1.begin(),v1.end());

怎么访问vector容器中的元素:

  1. v.at(n)返回容器位置为n的元素的引用(注意第一个位置为0)
  2. vector容器也是数组,可以用v[n]访问

所谓泛型编程就是模板编程,泛型就是广泛可以使用的类型,即模板

五类主要的序列容器:

vector,array,list,deque,forward_list

array容器不是array数组,它如同其他容器拥有自己的成员函数

和其它容器不同,array 容器的大小是固定的,无法动态的扩展或收缩,这也就意味着,在使用该容器的过程无法借由增加或移除元素而改变其大小,它只允许访问或者替换存储的元素。

每一个容器的使用都要包含自己的头文件,头文件在std命名空间中

array容器的头文件:<array>

array容器的初始化:

1,array<double, 10> values;

由此,就创建好了一个名为 values 的 array 容器,其包含 10 个浮点型元素。但是,由于未显式指定这 10 个元素的值,因此使用这种方式创建的容器中,各个元素的值是不确定的(array 容器不会做默认初始化操作)

2,array<double,10>values{};

将所有的元素初始化为 0 或者和默认元素类型等效的值:

3,当然,在创建 array 容器的实例时,也可以像创建常规数组那样对元素进行初始化:array<double, 10> values {0.5,1.0,1.5,,2.0};

这里只初始化了前 4 个元素,剩余的元素都会被初始化为 0.0

array容器成员函数汇总

成员函数

功能

begin()

返回指向容器中第一个元素的随机访问迭代器。

end()

返回指向容器最后一个元素之后一个位置的随机访问迭代器,通常和 begin() 结合使用。

rbegin()

返回指向最后一个元素的随机访问迭代器。

rend()

返回指向第一个元素之前一个位置的随机访问迭代器。

cbegin()

和 begin() 功能相同,只不过在其基础上增加了 const 属性,不能用于修改元素。

cend()

和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。

crbegin()

和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。

crend()

和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。

size()

返回容器中当前元素的数量,其值始终等于初始化 array 类的第二个模板参数 N。

max_size()

返回容器可容纳元素的最大数量,其值始终等于初始化 array 类的第二个模板参数 N。

empty()

判断容器是否为空,和通过 size()==0 的判断条件功能相同,但其效率可能更快。

at(n)

返回容器中 n 位置处元素的引用,该函数自动检查 n 是否在有效的范围内,如果不是则抛出 out_of_range 异常。

front()

返回容器中第一个元素的直接引用,该函数不适用于空的 array 容器。

back()

返回容器中最后一个元素的直接应用,该函数同样不适用于空的 array 容器。

data()

返回一个指向容器首个元素的指针。利用该指针,可实现复制容器中所有元素等类似功能。

fill(val)

将 val 这个值赋值给容器中的每个元素。

array1.swap(array2)

交换 array1 和 array2?容器中的所有元素,但前提是它们具有相同的长度和类型。

访问array容器中单个元素

首先,可以通过容器名[]的方式直接访问和使用容器中的元素,这和?C++?标准数组访问元素的方式相同,例如:

  1. values[4]?=?values[3]?+?2.O*values[1];

此行代码中,第 5 个元素的值被赋值为右边表达式的值。需要注意的是,使用如上这样方式,由于没有做任何边界检查,所以即便使用越界的索引值去访问或存储元素,也不会被检测到。(越界无检索)

为了能够有效地避免越界访问的情况,可以使用 array 容器提供的 at() 成员函数,例如 :

2,values.at?(4)?=?values.at(3)?+?2.O*values.at(1);

这行代码和前一行语句实现的功能相同,其次当传给 at() 的索引是一个越界值时,程序会抛出 std::out_of_range 异常。因此当需要访问容器中某个指定元素时,建议大家使用 at(),除非确定索引没有越界。(越界可检索)

3,array 容器提供了 data() 成员函数,通过调用该函数可以得到指向容器首个元素的指针

4,在 <array> 头文件中还重载了 get() 全局函数,该重载函数的功能是访问容器中指定的元素,并返回该元素的引用。需要注意的是,该模板函数中,参数的实参必须是一个在编译时可以确定的常量表达式,所以它不能是一个循环变量。

重载函数get():

形式:get<n>(name)

n为指定容器元素,name为容器名称

LIST--container:

list节点:

list节点是一个双向指针,实质是一个模板结构体

template<class T>

struct _list_node

{
    typedef void* void_pointer;
    void_pointer prev;//previous
    void_pointer next;
    T data;
};

可见,list的节点是一个以结构体形成的双向链表

而且是一个环状的双向链表

所以list的节点不要求连续

list--iterator:

源码:

?list迭代器是一个模板结构体?

因为list的节点不要求一定连续,所以不同于vector以指针作为迭代器

list--container:

list容器是一个模板类

list的所有的函数,迭代器都是这个模板类的成员

list container的成员函数:

1,begin()

2,end()

3,void push_back(const T& x)

功能:插入一个节点作为尾节点

实现原理:

?4,void push_front(const T& x)

插入一个节点作为头节点

和push_back()相对应

5,iterator erase(iterator position)

移除迭代器position所指的节点

6,void pop_front()

移除头节点

7,void pop_back()

移除尾节点

8,void list<T,Alloc>::clear()

清除所有节点(删除整个链表)

9,void list<T,Alloc>::remove(const T& x)

清除数值为x的所有节点

10,void? list<T,Alloc>::?unique()

清除数值相同的连续节点,保留一个

list成员函数列表:

表 2 list 容器可用的成员函数
成员函数功能
begin()返回指向容器中第一个元素的双向迭代器。
end()返回指向容器中最后一个元素所在位置的下一个位置的双向迭代器。
rbegin()返回指向最后一个元素的反向双向迭代器。
rend()返回指向第一个元素所在位置前一个位置的反向双向迭代器。
cbegin()和 begin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
cend()和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
crbegin()?和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
crend()和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
empty()判断容器中是否有元素,若无元素,则返回 true;反之,返回 false。
size()返回当前容器实际包含的元素个数。
max_size()返回容器所能包含元素个数的最大值。这通常是一个很大的值,一般是 232-1,所以我们很少会用到这个函数。
front()返回第一个元素的引用。
back()返回最后一个元素的引用。
assign()用新元素替换容器中原有内容。
emplace_front()在容器头部生成一个元素。该函数和 push_front() 的功能相同,但效率更高。
push_front()在容器头部插入一个元素。
pop_front()删除容器头部的一个元素。
emplace_back()在容器尾部直接生成一个元素。该函数和 push_back() 的功能相同,但效率更高。
push_back()在容器尾部插入一个元素。
pop_back()删除容器尾部的一个元素。
emplace()在容器中的指定位置插入元素。该函数和 insert() 功能相同,但效率更高。
insert()?在容器中的指定位置插入元素。
erase()删除容器中一个或某区域内的元素。
swap()交换两个容器中的元素,必须保证这两个容器中存储的元素类型是相同的。
resize()调整容器的大小。
clear()删除容器存储的所有元素。
splice()将一个 list 容器中的元素插入到另一个容器的指定位置。
remove(val)删除容器中所有等于 val 的元素。
remove_if()删除容器中满足条件的元素。
unique()删除容器中相邻的重复元素,只保留一个。
merge()合并两个事先已排好序的 list 容器,并且合并之后的 list 容器依然是有序的。
sort()通过更改容器中元素的位置,将它们进行排序。
reverse()反转容器中元素的顺序。
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-11-30 15:52:09  更:2021-11-30 15:54:19 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 13:35:56-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码