STL学习第一章 了解STL

知识内容:

1.STL介绍

2.C++基础知识复习

3.C++中的模板简单介绍

4.STL组成部分

一、STL介绍

1.什么是STL?

学过C++的应该都听说过STL,那么什么是STL呢?STL是Standard Template Library的简称,翻译为标准模板库,是惠普实验室开发的一系列软件的统称。它是由Alexander Stepanov、Meng Lee和David R Musser在惠普实验室工作时所开发出来的。从根本上说,STL是一些“容器”的集合,这些“容器”有list,vector,set,map等,STL也是算法和其他一些组件的集合。这里的“容器”和算法的集合指的是世界上很多聪明人很多年的杰作。STL的目的是标准化组件,这样就不用重新开发,可以使用现成的组件。STL现在是C++的一部分,因此不用安装额外的库文件,只用在使用STL时包含相应头文件就行了。

2.STL组成部分

在C++标准中,STL被组织为下面的13个头文件:<algorithm>、<deque>、<functional>、<iterator>、<array>、<vector>、<list>、<forward_list>、<map>、<unordered_map>、<memory>、<numeric>、<queue>、<set>、<unordered_set>、<stack>和<utility>

STL可分为容器(containers)、迭代器(iterators)、空间配置器(allocator)、配接器(adapters)、算法(algorithms)、仿函数(functors)六个部分,我将在下面详细解释。

二、C++基础知识复习

要学习STL,毫无疑问C++基础必须掌握,在这就稍微复习一下C++的基础知识

1.C++基本输入输出:

1 #include <iostream>
2 using namespace std;
3
4 int main()
5 {
6     int n;
7     cin << n;    //C++基本输入
8     cout << "You enter " << n << endl;   //C++基本输出
9 }

2.C++引用:

C++定义引用的表示方法与定义指针相似,只是用&代替了*。引用是c++对C语言的重要扩充。引用就是某一变量(目标)的一个别名,对引用的操作与对变量直接操作完全一样。引用的声明方法:类型标识符 &引用名=目标变量名;

 1 //交换两个数的值
 2 #include <iostream>
 3 using namespace std;
 4
 5 void swap_number(int &i, int &j)
 6 {
 7     int temp = i;
 8     i = j;
 9     j = temp;
10 }
11
12 int main()
13 {
14     int a, b;
15     cin >> a >> b;
16     swap_number(a, b);
17     cout << a << " " << b << endl;
18     return 0;
19 }

3.C++类的基础知识:

类: 具有相同行为和属性的对象的集合

构造函数: 类的对象创建时就会被自动调用

析构函数: 类的对象销毁时就会被自动调用

成员变量、成员函数 -> 通过对象来访问

static成员变量: 一个类所有对象共享的数据,不属于某个对象

static成员函数: 一个类所有对象共享的函数,不能访问非static成员变量,不属于某个对象,应用于单例模式中

类的访问控制: private、protected、public

继承: 一个类共享另一个类或多个类的数据或方法,私有成员不会被继承

3种继承: public继承、protected继承、private继承,用的最多的是public继承

4.绑定:

静态绑定: 编译阶段确定函数调用  例如: 函数重载

动态绑定: 运行时确定函数调用  例如: 虚函数

5.多态:

多态一词最初来源于希腊语,意思是具有多种形式或形态的情形,在C++中是指同样的消息被不同类型的对象接收时导致不同的行为,这里讲的消息就是指对象的成员函数的调用,而不同的行为是指不同的实现。也就是调用了不同的函数。

6.操作符重载:

C++中可以实现操作符重载,通俗地讲就是在某些时候改变运算符的功能

使用运算符重载实现矩阵加减乘:

 1 //矩阵的加减乘
 2 #include <iostream>
 3 using namespace std;
 4 #include <cstdio>
 5 int const N = 2;
 6 int const M = 2;
 7
 8 class Matrix{
 9 private:
10     double ptr[N][M];
11 public:
12     Matrix(double i=0, double j=0, double k=0, double l=0);
13     void Show();
14     Matrix operator+(Matrix a);
15     Matrix operator-(Matrix a);
16     Matrix operator*(Matrix a);
17 };
18
19 Matrix::Matrix(double i, double j, double k, double l)
20 {
21     ptr[0][0] = i;
22     ptr[0][1] = j;
23     ptr[1][0] = k;
24     ptr[1][1] = l;
25 }
26
27 Matrix Matrix::operator+(Matrix a)
28 {
29     Matrix temp;
30     for(int i=0;i<N;i++)
31     for(int j=0;j<M;j++)
32     {
33         temp.ptr[i][j] = this->ptr[i][j] + a.ptr[i][j];
34     }
35     return temp;
36 }
37
38 Matrix Matrix::operator-(Matrix a)
39 {
40     Matrix temp;
41     for(int i=0;i<N;i++)
42     for(int j=0;j<M;j++)
43     {
44         temp.ptr[i][j] = this->ptr[i][j] - a.ptr[i][j];
45     }
46     return temp;
47 }
48
49 Matrix Matrix::operator*(Matrix a)
50 {
51     Matrix temp;
52     for(int i=0;i<N;i++)
53     for(int j=0;j<M;j++)
54     for(int k=0;k<M;k++)
55     {
56         temp.ptr[i][j] += this->ptr[i][k]*a.ptr[k][j];
57     }
58     return temp;
59 }
60
61 void Matrix::Show()
62 {
63     for(int i=0;i<N;i++)
64     {
65         cout << "( ";
66         for(int j=0;j<M;j++)
67         {
68             cout << ptr[i][j] << " ";
69         }
70         cout << ")" << endl;
71     }
72     cout << endl;
73 }
74
75 int main()
76 {
77     Matrix first(1,2,3,4), second(2,6,8,10), total, sub, mul, div;
78     cout << "这是两个矩阵: " << endl;
79     first.Show();
80     second.Show();
81     cout << "两个矩阵相加得: " << endl;
82     total = first + second;
83     total.Show();
84     cout << "两个矩阵相减得: " << endl;
85     sub = first - second;
86     sub.Show();
87     cout << "两个矩阵相乘得: " << endl;
88     mul = first*second;
89     mul.Show();
90
91
92     return 0;
93 }

7.C++的异常处理:

C++中处理异常的机制由检查、抛出和捕获三个部分组成,分别由三种语句来完成: try(检查)、throw(抛出)、catch(捕获),

把需要检查的语句放在try中,throw用在出现异常时发出一个信息,而catch用来捕获异常,并在捕获异常后对其进行处理。

8.C++的命名空间:

(1)定义与解释:

假设这样一种情况,当一个班上有两个名叫 Zara 的学生时,为了明确区分它们,我们在使用名字之外,不得不使用一些额外的信息,比如他们的家庭住址,或者他们父母的名字等等。

同样的情况也出现在 C++ 应用程序中。例如,您可能会写一个名为 xyz() 的函数,在另一个可用的库中也存在一个相同的函数 xyz()。这样,编译器就无法判断您所使用的是哪一个 xyz() 函数。

因此,引入了命名空间这个概念,专门用于解决上面的问题,它可作为附加信息来区分不同库中相同名称的函数、类、变量等。使用了命名空间即定义了上下文。本质上,命名空间就是定义了一个范围。

(2)C++标准库命名空间的使用:

C++标准库内的所有表示符都被定义在一个名为std的命名空间中,使用标识符时可以直接在前面加上std::即可,示例:

1 #include <iostream>
2
3 int main()
4 {
5     std::cout << "C++命名空间第一种使用方法" << std::endl;    return 0;
6 }

但是这样使用命名空间std也有弊端,当程序中使用的标识符较多时,写起来比较麻烦,可以使用 using namespace 指令,这样在使用命名空间时就可以不用在前面加上命名空间的名称。这个指令会告诉编译器,后续的代码将使用指定的命名空间中的名称,示例:

 1 #include <iostream>
 2 using namespace std;
 3
 4 int main()
 5 {
 6     cout << "C++命名空间第二种使用方法" << endl;
 7     cout << "直接使用using namespace指令" << endl;
 8
 9     return 0;
10 }

三、C++中的模板简单介绍

1.C++为什么需要模板功能

C++需要模板这个功能的原因很简单,就是计算机实在是太傻了。在大多数人的眼中,计算机即神秘又能干,而在程序员的眼中,计算机实在是又蠢又笨。

只不过运算的比人类速度快,记忆力好,但是如果我们不给它指令,计算机就什么干不了,就算是给指令, 写一个程序,计算机也不是很灵活。比如说在C++

中同样一个加法,要对不同的数据类型给出不同代码,要写不同的函数,于是有人提出了一种新思想-泛型编程,那么什么是泛型编程呢?

2.泛型编程

泛型编程最初提出的动机很简单,就是要发明一种语言机制,能实现:

(1)一个通用的标准容器库。何为通用的标准容器库?比如用一个list类能存放所有的数据类型的对象:整形、浮点型、字符串类型、自定义对象类型、、、

(2)编写完全一般化并可以重复使用的算法,其效率与针对某特定数据结构设计的算法不相上下。泛型是指在多种数据类型上皆可操作的含义,这样的算法与

数据结构相分离,其中的算法是泛型的,不与任何特定数据结构或对象类型联系在一起,从而提供了工作效率。

3.C++的模板

我们为了让程序更加智能化,C++很需要泛型这种新的编程方式,于是引入了模板这个功能,也就是说在C++中引入了关键字template

使用模板是为了实现泛型,可以减轻编程的工作量,增强函数的重用性。

比如说将两个变量相加的函数add,如果不是用模板来实现,我们需要针对不同的类型写多个功能相同的函数,例如int、float等,而使用了模板后只需使用以下一个函数即可:

1 template <class T>
2 T add(T m, T n)
3 {
4     return m+n;
5 }

调用时可以说明类型,例如: add<int>(3,5);  但是也可以不用使用类型,函数会根据参数的类型自动确定类型: add(3,5);

当然,还可以自定义数据类型,甚至自己定义的类

四、STL组成部分

STL可分为容器(containers)、算法(algorithms)、迭代器(iterators)、仿函数(functors)、配接器(adapters)、空间配置器(allocator)六个部分

1、容器

作为STL的最主要组成部分--容器,分为向量(vector),双端队列(deque),表(list),队列(queue),堆栈(stack),集合(set),多重集合(multiset),映射(map),多重映射(multimap)。


容器


特性


所在头文件


向量vector


可以用常数时间访问和修改任意元素,在序列尾部进行插入和删除时,具有常数时间复杂度,对任意项的插入和删除就有的时间复杂度与到末尾的距离成正比,尤其对向量头的添加和删除的代价是惊人的高的


<vector>


双端队列deque


基本上与向量相同,唯一的不同是,其在序列头部插入和删除操作也具有常量时间复杂度


<deque>


表list


对任意元素的访问与对两端的距离成正比,但对某个位置上插入和删除一个项的花费为常数时间。


<list>


队列queue


插入只可以在尾部进行,删除、检索和修改只允许从头部进行。按照先进先出的原则。


<queue>


堆栈stack


堆栈是项的有限序列,并满足序列中被删除、检索和修改的项只能是最近插入序列的项。即按照后进先出的原则


<stack>


集合set


由节点组成的红黑树,每个节点都包含着一个元素,节点之间以某种作用于元素对的谓词排列,没有两个不同的元素能够拥有相同的次序,具有快速查找的功能。但是它是以牺牲插入删除操作的效率为代价的


<set>


多重集合multiset


和集合基本相同,但可以支持重复元素具有快速查找能力


<set>


映射map


由{键,值}对组成的集合,以某种作用于键对上的谓词排列。具有快速查找能力


<map>


多重集合multimap


比起映射,一个键可以对应多了值。具有快速查找能力


<map>

2、算法

算法部分主要由头文件<algorithm>,<numeric>和<functional>组成。<algorithm>是所有STL头文件中最大的一个,它是由一大堆模版函数组成的,可以认为每个函数在很大程度上都是独立的,其中常用到的功能范 围涉及到比较、交换、查找、遍历操作、复制、修改、移除、反转、排序、合并等等。<numeric>体积很小,只包括几个在序列上面进行简单数学运算的模板函数,包括加法和乘法在序列上的一些操作。<functional>中则定义了一些模板类,用以声明函数对象。

STL的算法也是非常优秀的,它们大部分都是类属的,基本上都用到了C++的模板来实现,这样很多相似的函数就不用自己写了,只要用函数模板就可以了。

我们使用算法的时候,要针对不同的容器,比如:对集合的查找,最好不要用通用函数find(),它对集合使用的时候,性能非常的差,最好用集合自带的find()函数,它针对了集合进行了优化,性能非常的高。

3、迭代器

它的具体实现在<itertator>中,我们完全可以不管迭代器类是怎么实现的,大多数的时候,把它理解为指针是没有问题的(指针是迭代器的一个特例,它也属于迭代器),但是,决不能完全这么做。


迭代器功能


输入迭代器

Input iterator


、Reads forward


istream


输出迭代器

Output iterator


向前写

Writes forward


ostream,inserter


前向迭代器

Forward iterator


向前读写

Read and Writes forward


双向迭代器

Bidirectional iterator


向前向后读写

Read and Writes forward and

backward


list,set,multiset,map,mul

timap


随机迭代器

Random access iterator


随机读写

Read and Write with random

access


vector,deque,array,string

4、仿函数

(1)仿函数的概念:

仿函数(functor),就是使一个类的使用看上去象一个函数。其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了。

在我们写代码时有时会发现有些功能的实现的代码,会不断的在不同的成员函数中用到,但是又不好将这些代码独立出来成为一个类的一个成员函数。但是又很想复用这些代码。写一个公共的函数,可以,这是一个解决方法,不过函数用到的一些变量,就可能成为公共的全局变量,再说为了复用这么一片代码,就要单立出一个函数,也不是很好维护。这时就可以用仿函数了,写一个简单类,除了那些维护一个类的成员函数外,就只是实现一个operator(),在类实例化时,就将要用的,非参数的元素传入类中。这样就免去了对一些公共变量的全局化的维护了。又可以使那些代码独立出来,以便下次复用。而且这些仿函数,还可以用关联,聚合,依赖的类之间的关系,与用到他们的类组合在一起,这样有利于资源的管理(这点可能是它相对于函数最显著的优点了)。如果在配合上模板技术和policy编程思想,那就更是威力无穷了,大家可以慢慢的体会。

仿函数,又或叫做函数对象,是STL六大组件之一;仿函数虽然小,但却极大的拓展了算法的功能,几乎所有的算法都有仿函数版本。例如,查找算法find_if就是对find算法的扩展,标准的查找是两个元素相等就找到了,但是什么是相等在不同情况下却需要不同的定义,如地址相等,地址和邮编都相等,虽然这些相等的定义在变,但算法本身却不需要改变,这都多亏了仿函数。仿函数(functor)又称之为函数对象(function object),其实就是重载了()操作符的struct,没有什么特别的地方

(2)在C++里,我们通过在一个类中重载括号运算符的方法使用一个函数对象而不是一个普通函数。

 1 class compare_class
 2 {
 3 public:
 4     bool operator()(int A, int B)const{return A < B;}
 5 };
 6
 7 // Declaration of C++ sorting function.
 8 template<class ComparisonFunctor>
 9 void sort_ints(int* begin_items, int num_items, ComparisonFunctor c);
10
11 int main()
12 {
13     int items[]={4, 3, 1, 2};
14     compare_class functor;
15     sort_ints(items, sizeof(items)/sizeof(items[0]), functor);
16
17     return 0;
18 }

(3)为什么要使用仿函数:

仿函数比一般的函数灵活;仿函数有类型识别,可以作为模板参数;执行速度上仿函数比函数和指针要更快的。

5、适配器(配接器)

适配器是用来修改其他组件接口的STL组件,是带有一个参数的类模板(这个参数是操作的值的数据类型)。STL定义了3种形式的适配器:容器适配器,迭代器适配器,函数适配器。

(1)容器适配器:

包括栈(stack)、队列(queue)、优先(priority_queue)。使用容器适配器,stack就可以被实现为基本容器类型(vector,dequeue,list)的适配。可以把stack看作是某种特殊的vctor,deque或者list容器,只是其操作仍然受到stack本身属性的限制。queue和priority_queue与之类似。容器适配器的接口更为简单,只是受限比一般容器要多。

(2)迭代器适配器:

修改为某些基本容器定义的迭代器的接口的一种STL组件。反向迭代器和插入迭代器都属于迭代器适配器,迭代器适配器扩展了迭代器的功能。

(3)函数适配器:

通过转换或者修改其他函数对象使其功能得到扩展。这一类适配器有否定器(相当于"非"操作)、绑定器、函数指针适配器。函数对象适配器的作用就是使函数转化为函数对象,或是将多参数的函数对象转化为少参数的函数对象。

6、空间配置器

空间配置器,也叫内存配置器,空间配置器代表一种特定的内存模型,并提供一种抽象概念,便于将内存的申请转换成对内存的直接调用。配置器主要用于将算法和容器的实现隔离于物理存储细节之外。

原文地址:https://www.cnblogs.com/wyb666/p/8575113.html

时间: 2024-11-08 21:03:37

STL学习第一章 了解STL的相关文章

web学习第一章

web学习第一章 我是大概9月10日开始走上IT之路的,一开始学习了小段时间的自动化办公软件, 昨天我开始学习客户端网页编程,我了解什么是WEB,一些比较老古董的计算模式和发展历史,印象最让我深刻的是WEB应用程序的工作原理,因为老师为了解释这个画来很多遍图,我当时想的是:为什么还有人没懂?我都听困了. 直到老师说要抽人起来画图,我一下就回过神来了,于是乎老师抽人开始了,我看见同学一个个的被抽上去画,我发现我有些东西怎么没看见过,在他们画的同时我就在下面学,错一个,我就记一个. 今天老师还是继续

C++ Primer快速学习 第一章 入门

很多人说C++Primer不适合于入门,本系列入门文章向大家证明了:这是一个谎言. 第一章 入门 本章介绍 C++ 的大部分基本要素:内置类型.库类型.类类型.变量.表 达式.语句和函数. 1.1. 编写简单的 C++ 程序 每个 C++ 程序都包含一个或多个 函数 ,而且必须有一个命名为 main.函数 由执行函数功能的语句序列组成.操作系统通过调用 main 函数来执行程序, main 函数则执行组成自己的语句并返回一个值给操作系统. 下面是一个简单的 main 函数,它不执行任何功能,只是

Java基础知识二次学习-- 第一章 java基础

基础知识有时候感觉时间长似乎有点生疏,正好这几天有时间有机会,就决定重新做一轮二次学习,挑重避轻 回过头来重新整理基础知识,能收获到之前不少遗漏的,所以这一次就称作查漏补缺吧!废话不多说,开始! 第一章  JAVA简介 时间:2017年4月24日10:23:32 章节:01章_02节 内容:jdk的配置与安装 完成情况:已经完成,cmd中javac提示出相关命令 时间:2017年4月24日10:30:39 章节:01章_04节 内容:输出HelloWorld 完成情况: 已经完成 javac先将

学习第一章 Android系统的编译和移植实例后的心得体会

说起来,去年在岳老师的带领下就接触了嵌入式系统的编译和移植.而现在我们又开始接触Android系统的编译和移植.第一章主要介绍安卓系统的编译和移植技术.其实安卓和嵌入式非常相似. 安卓 移植涉及的主要过程大致分为六步:1.下载安卓linux内核. 2.安装交叉工具链.3.移植安卓linux内核支持EZ6410平台.4.安装安卓SDK.4.获得安卓根文件系统.5.设置系统环境,完成安卓正常启动.虽然步骤不多,但是涉及了很多东西.在开始内核移植之前,先完成工具链的搭建.在移植过程中会发现硬件差异.差

Ruby学习-第一章

第一章 字符串,数字,类和对象 为了证明Ruby真的好用,hello world也能写的如此简洁: puts 'hello world' 1.输入/输出 print('Enter your name') name=gets() puts("Hello #{name}") 注:Ruby是区分大小写的 2.String类 puts("Hello #{name}")中的变量 name是内嵌在整个String里的,通过 #{ } 包裹进行内嵌求值,并用双引号"&q

Netty In Action中文版 学习第一章的重点知识

第一章 大多数都是一些名词,SSL/TLS和Starttls支持,回调,聚合,分散,这些我也不是很明白,也百度了一下这些基础概念,大家也可以去看看实际的内容以及相关的代码,由于本人也是新手对这些词也理解不深刻不在此细说. 下面是一个jar文件搜索的比较好的网址拿出来分享给大家 http://www.findjar.com/index.x?query=xlstojson jar包的搜索地 下面就是工具,作为新人大多数都说用Eclipse就够了,我由于想看开源的源码所以选择了MyEclipse 10

python 学习第一章(python基础编程第二版)

第一章:基础知识 1.双斜线:实现整除的操作符 >>>1//2 0 就算是浮点数,双斜线也会执行整除 >>>1.0//2.0 0.0 2.幂(乘方)运算符:双星 >>>2**3 8 tip:可以用函数pow代替运算符,pow(2,3) 3.十六进制和八进制 十六进制:前面加0x,第一个是数字0 >>>0xAF 175 八进制:在3.0以上版本的python中加0o,首数字是0,第二个是字母o >>>0o10 8 4.

LinQ in Action 学习第一章 例子。

最近用Entity Framework 做了个mvc 的小例子,发现代码中用LinQ 语法还是很多的,决定好好研究一下LinQ,补一下.net 的技术,是不是大家都对这些技术很熟了,,因为项目简单,都没怎么用. 参考书  Linq IN Action  中英文版对照, 也不知道这本是不是最好的介绍LinQ的书,看网上的评价还是可以的. 可以去皮皮书屋下载. 如果有更好的书推荐,欢迎大家留言给我 第一章: 就是对LinQ的简介,还是从写代码开始吧. 一: Hello Linq world: 这个例

Biztalk学习第一章(整体架构)

Biztalk运行时的结构 BizTalk Server 本质上就是消息处理引擎.个人认为在了解Biztalk之前必须要知道的一部分便是BizTalk Server 的整体架构,只有对架构烂熟于心这样才能为往下深入学习做好基础. 首先来看一下Biztalk的整体架构图 如上图所示,完整的绘制了Biztalk在接受端口接收到文件后整个处理文件的过程. 接下来分开叙述:(参照微软官方文档) 接收端口和接收位置 "接收端口"是一个或多个接收位置的集合,是BizTalk Server 的特定入