当前位置:   article > 正文

STL基础_stl算法基础

stl算法基础

目录

1 STL

1.1 STL的诞生

1.2 STL基本概念

1.3 STL六大组件

1.4 容器、算法与迭代器的认识

1.5 vector容器示例

1.5.1 存放内置数据类型

1.5.2 存放自定义数据类型

1.5.3 vector容器嵌套vector容器


1 STL

1.1 STL的诞生

一直以来,软件界面临一个问题:代码重复利用。*就像他写某个功能的代码,我也要用但是没拿到手上,必须我再写一份一样的,这样就重复写了,不仅浪费时间还让我们很难受。*

C++面向对象泛型编程的思想,目的就是提高复用性

为了建立数据结构与算法的一套标准STL就诞生了。

1.2 STL基本概念

STL:Standerd Template Library,标准模板库

广义上,STL分为:container容器,algorithm算法,iterator迭代器

  • 容器和算法通过迭代器进行连接

  • STL几乎所有的代码都使用了类模板或函数模板

1.3 STL六大组件

大体分为六大组件:容器、算法、迭代器、仿函数、适配器(配接器)、空间配置器

  • 容器:各种数据结构,如vectorlistdequesetmap等,用来存放数据

  • 算法:各种常用算法,如sortfindcopyfor_each

  • 迭代器:作为容器与算法中间的黏着剂

  • 仿函数:行为类似函数,可作为算法的某种策略

  • 适配器:用来修饰容器或仿函数或迭代器接口

  • 空间配置器:进行空间的配置与管理

1.4 容器、算法与迭代器的认识

容器container:存放数据地方

STL容器就是将一些使用最广泛的数据结构实现出来

常用的数据结构:数组、链表、树、栈、队列、集合、映射表

这些容器又分为:

  • 序列式容器:强调值的排序,其中每个元素有其固定的位置

  • 关联式容器:二叉树结构,各元素之间没有严格的物理上的顺序关系


算法algorithm:解决问题的方法

以有限的步骤解决逻辑或数学上的问题

分为

  • 质变算法:运算过程中会改变区间中元素的内容,例如拷贝、替换、删除等

  • 非质变算法:运算过程中不改变区间中元素的内容,如查找、计数、遍历、寻找极值等


迭代器iterator:容器与算法之间的黏着剂,算法通过迭代器才能访问容器中的元素

  • 提供一种方法,使其能够按序查找某个容器所含的各个元素,而又无需暴露该容器内部的表示方式

  • 每个容器都有其专属的迭代器

  • 迭代器的使用非常类似于指针

种类:

种类功能支持的运算
输入迭代器对数据只读访问只读,支持++、==、!=
输出迭代器对数据只写访问只写,支持++
前向迭代器读写操作,并能向前推进迭代器读写,支持++、==、!=
双向迭代器读写操作,并能向前或向后推进读写,支持++、--
随机访问迭代器读写操作,可以以跳跃方式随机访问任意数据读写,支持++、--、[n]、-n、<、<-、>、>=

常用的迭代器是双向迭代器随机访问迭代器

1.5 vector容器示例

类似于数组

1.5.1 存放内置数据类型

  • 容器:vector

  • 算法:for_each

  • 迭代器:vector<int>::iterator

首先包含头文件<vector>

 #include<vector>

然后:

  1.  int main()
  2.  {
  3.   // 创建一个vector容器,类似于数组
  4.   vector<int> v;
  5.   // 使用vector的pushback函数插入数据
  6.   v.push_back(1);
  7.   v.push_back(2);
  8.   v.push_back(3);
  9.   v.push_back(4);
  10.   // 通过迭代器访问容器中的数据
  11.   // 方法 1
  12.   vector<int>::iterator v_Begin = v.begin();// 起始迭代器,指向容器中第一个元素
  13.   vector<int>::iterator v_End = v.end();// 结束迭代器,指向容器中最后一个元素的后面一个元素
  14.   // 遍历访问
  15.   while (v_Begin != v_End)
  16.   {
  17.   cout << *v_Begin << " ";
  18.   v_Begin++;
  19.   }
  20.   return 0;
  21.  }

img

  • 这是第一种访问数据的方法

img

  • 然后我们使用第二种访问数的方法,直接把他们写在一起

  1.   // 方法 2
  2.   for (vector<int>::iterator v_begin = v.begin(); v_begin != v.end(); v_begin++)
  3.   {
  4.   cout << *v_begin << " ";
  5.   }

img

  • 然后是第三种方式,我们使用内置算法for_each

首先包含标准算法头文件<algorithm>

 #include<algorithm>// 标准算法头文件

使用for_each函数

  1.   // 方法 3
  2.   for_each(v.begin(), v.end(), my_print);
  3.   //     起始位置   结束位置 调用的函数

我们自己实现my_print函数

  1.  void my_print(int val)
  2.  {
  3.   cout << val << " ";
  4.  }

img

成功输出

for_each函数的原理

img

img

同样的起始地址与结束地址,以及函数

for循环里,起始地址不等于结束地址,调用函数,参数为解引用*起始地址,所以我们函数参数是int val

1.5.2 存放自定义数据类型

  • 创建自定义数据类型class person

  1.  class person
  2.  {
  3.  public:
  4.   person(string name,int age)
  5.   {
  6.   m_age = age;
  7.   m_name = name;
  8.   }
  9.   int m_age;
  10.   string m_name;
  11.  };

创建容器,并创建变量并尾插

  1.  void test01()
  2.  {
  3.   // 创建vector容器v
  4.   vector<person> v;
  5.   // 根据自定义数据类型创建对象
  6.   person p1("Joyce", 21);
  7.   person p2("Tatina", 20);
  8.   person p3("Yomi", 1);
  9.   person p4("nana", 18);
  10.   // 尾插进容器
  11.   v.push_back(p1);
  12.   v.push_back(p2);
  13.   v.push_back(p3);
  14.   v.push_back(p4);
  15.   // 访问数据
  16.   for (vector<person>::iterator v_begin = v.begin(); v_begin != v.end(); v_begin++)
  17.   { // v_begin本质是个指针,可以解引用. 或者-> 访问
  18.   cout << (*v_begin).m_name << "的年龄为" << (*v_begin).m_age << endl;
  19.   cout << v_begin->m_name << "的年龄为" << v_begin->m_age << endl;
  20.   }
  21.  }

img

*v_begin的本质就是 vector后面<>中的person

  • 放指针类型的自定义数据类型

同样的class person自定义数据类型

  1.  class person
  2.  {
  3.  public:
  4.   person(string name,int age)
  5.   {
  6.   m_age = age;
  7.   m_name = name;
  8.   }
  9.   int m_age;
  10.   string m_name;
  11.  };

vector里我们不传入person,而是传入person*,即指针类型

  1.  void test02()
  2.  {
  3.   // 创建vector容器v
  4.   vector<person*> v;
  5.   // 根据自定义数据类型创建对象
  6.   person p1("Joyce", 21);
  7.   person p2("Tatina", 20);
  8.   person p3("Yomi", 1);
  9.   person p4("nana", 18);
  10.   // 尾插进容器,p是指针,所以带上&
  11.   v.push_back(&p1);
  12.   v.push_back(&p2);
  13.   v.push_back(&p3);
  14.   v.push_back(&p4);
  15.   // 访问数据
  16.   for (vector<person*>::iterator v_begin =v.begin(); v_begin != v.end(); v_begin++)
  17.   { // *v_begin还是个指针,所以可以再次解引用*,或者->访问
  18.   cout << (*(*v_begin)).m_name << "的年龄为" << (*(*v_begin)).m_age << endl;
  19.   cout << (*v_begin)->m_name << "的年龄为" << (*v_begin)->m_age << endl;
  20.   }
  21.  }

img

v_begin的本质就是 vector后面<>中的person

1.5.3 vector容器嵌套vector容器

  1.  void test03()
  2.  {
  3.   // 创建大容器v
  4.   vector<vector<int>> v;
  5.   // 创建小容器
  6.   vector<int> v1;
  7.   vector<int> v2;
  8.   vector<int> v3;
  9.   vector<int> v4;
  10.   // 向小容器中加入数据
  11.   int i = -1;
  12.   while (++i != 4)
  13.   {
  14.   v1.push_back(i + 1);
  15.   v2.push_back(i + 2);
  16.   v3.push_back(i + 3);
  17.   v4.push_back(i + 4);
  18.   }
  19.   // 将小容器加入到大容器中
  20.   v.push_back(v1);
  21.   v.push_back(v2);
  22.   v.push_back(v3);
  23.   v.push_back(v4);
  24.   // 通过大容器遍历所有数据
  25.   for (vector<vector<int>>::iterator v_begin = v.begin(); v_begin != v.end(); v_begin++)
  26.   {
  27.   // *v_begin == vector<int> ,所以我们需要再做一次遍历
  28.   for (vector<int>::iterator vv_begin = (*v_begin).begin();vv_begin != (*v_begin).end(); vv_begin++)
  29.   {
  30.   cout << *vv_begin << " ";
  31.   }
  32.   cout << endl;
  33.   }
  34.  }

img

差不多是个二维数组

img

注意 *v_begin的本质就是 vector后面<>中的vector<int>,需要再来一次循环遍历数据,第二次遍历就用的(*v_begin)做对象,也就是(*v_begin).begin()是起始地址,(*v_begin).end()是结束地址,然后再*解引用访问

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小舞很执着/article/detail/920133
推荐阅读
相关标签
  

闽ICP备14008679号