Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

L11笔记 #51

Open
hycvegedog opened this issue May 21, 2022 · 1 comment
Open

L11笔记 #51

hycvegedog opened this issue May 21, 2022 · 1 comment

Comments

@hycvegedog
Copy link

纯属试水)

  • 命名空间

  • 定义了一堆内容(常量、变量、结构、类、函数……)的地方。

  • 定义一个命名空间,方法和定义一个类差不多,只不过不需要末尾分号。

  • 使用时:空间名::变量名。

  • using声明:

    • 使用整个:using namespace A;
    • 使用部分:using 空间名::变量名
  • STL初步

  • 标准模板库。含有算法、容器、函数、迭代器四个组件。

  • 模板编写,分离数据和操作。

  • 命名空间是std。可以用std::名字 来使用stl的函数或对象。

  • STL容器:简单容器

(1) Pair

  • 两个数据first&second,类型可以不一样。
  • Std::pair<int, double> t; 模板写法,创建实例对象前先说清参数类型
  • 获取数据/修改数据:通过first, second两个成员。
  • 创建:auto t = std::make_pair(1, 4); 用make_pair函数。(Make_pair 也是std里的一个函数)
  • 比较:先比first再比second。前提是类型可以比(两个pair的first是可比类型)

(2)tuple

  • 若干成员组成的元组,高级版pair。

  • 获取数据:get函数。v0 = std::get<0>(tuple1); 上面尖括号里面是下标,不可以是变量。

  • 下标需要在编译时确定:不能设定运行时可变的长度,不能当做数组。

  • 创建:make_tuple. 参数表里是n个数据。这个n决定了tuple的长度。auto t = std::make_tuple(“abc”, 7.8, 123, ‘3’);

  • 创建/修改数据:tie函数可以返回左值引用的元组。

std::string x; double y; int z;

std::tie(x, y, z) = std::make_tuple(“abc”, 7.8, 123);

//等价于 x = "abc"; y = 7.8; z = 123

std::tie(x, y, z) 就是tuple的左值引用。(x,y,z就是数据成员的左值引用)

这样可以给x,y,z赋值。改变他们时,tuple也就变了

  • P22示例:

在这样操作之后,xval和halfx的值就被更新了。

这里maketuple是作为了传递返回值的工具。

​ 额外示例:

#include<tuple>
#include <iostream>
int main(){
//创建元组
std::tuple<int, char, double>tp(2, 'b', 1.9);
auto data0 = std::get<0>(tp);//获得里面的元素
auto data1 = std::get<1>(tp);
auto data2 = std::get<2>(tp);
std::cout<<data0<<" "<<data1<<" "<<data2<<" "<<std::endl;

auto tup1 = std::make_tuple("hello", 'a', 1.3);
std::cout<<std::get<0>(tup1)<<" "<<std::get<1>(tup1)<<" "<<std::get<2>(tup1)<<std::endl;

const char * a;
char b;
double c;
std::tie(a, b, c) = tup1;
std::cout << a << "  " << b << "  " << c << std::endl;
std::tie(std::ignore, b, c) = tup1;
std::cout<<std::get<0>(tup1)<<" "<<std::get<1>(tup1)<<" "<<std::get<2>(tup1)<<std::endl;//这并不导致ignore的那个东西在源tuple里没有
// tie: 用于拆开tuple
// 如果不想要某一位的值,可以直接将其用ignore代替。

int aa = 5;
int &bb = aa;
char *p = "hello";
char *&pp = p;


auto tup2 = std::forward_as_tuple(bb, pp);
auto data5 = std::get<0>(tup2);
std::cout <<"****"<< data5 << std::endl;
// forward_as_tuple: 用于接受右值引用数据生成tuple

//上述代码创建了一个tuple<int &&, char (*&)>类型的元组。

//意思就是可以使用右值作为参数,而前面讨论的tie函数就只能接受左值

std::tuple<float, std::string> tup3(3.14, "pi");
std::tuple<int, char> tup4(10, 'a');

auto tup5 = tuple_cat(tup3, tup4);

//将tup1和tup2连起来就成了tup3

}
//结果:
2 b 1.9 
hello a 1.3
hello  a  1.3
hello a 1.3
****5
  • STL容器:序列容器

(1)vector

  • 自动扩展容量的数组。循序。

  • 可以替代原生数组。

  • 可以直接用下标访问。

  • 创建:和创建类模板的实例没有区别。在尖括号里指明数据的类型。std::vector x

  • 取长度:x.size();

  • 清空:x.clear();

  • 末尾加入元素:x.push_back(component);

  • 删除末尾元素:x.pop_back();

  • 在中间添加或删除:x.insert(x.begin()+1, 数据); x.erase(x.begin()+1);

    • 迭代器:一种遍历元素,检查元素的数据类型
    • 类似指针。
    • Begin()函数返回指向第一个元素的迭代器。
    • End()函数返回指向最后一个元素之后的位置的迭代器。
    • 下一/n个元素:++iter或iter++; iter+=n;
    • 上一/n个元素:--iter; iter-=n;
    • 访问/修改元素:*为解引用运算符(当成指针看待),他的特点是可以对元赋值(返回的是左值引用。)*iter=5; 把当前指向的数据改成5.
    • 虽然iter的类型不是int,但是两个iter的差是int。
    • 遍历vector:
      图片
      图片

    • **上面两种写法走的都是迭代器;但如果这么写走的就是元素了:(for auto i: vec)

      这样i就是元素的类型而不是迭代器。

  • erase函数:删除迭代器指向的元素而不是迭代器本身。例如:

​ auto it = vec.begin();

​ vec.erase(it);//删除它指向的元素,不是删除迭代器

  • 迭代器的失效:

    • 当迭代器不再指向本应指向的元素时,称此迭代器失效。
    • 调用insert/erase后,所修改位置之后的所有迭代器失效。(原先的内存空间存储的元素被改变)

​ 调用push_back等修改vector大小的方法时,可能会使所有迭代器失效(为什么?)(因为Push_back到了一定程度之后,可能会造成数组的整体移动,导致所有的内存地址发生改变。)

  • 因此在遍历过程中添加元素可能导致迭代器失效。其实就是,当size==capacity时,继续push_back会导致迭代器失效。

    vector<int> vec = {1,2,3,4,5};
       auto first = vec.begin();
       auto second = vec.begin() + 1;
       auto third = vec.begin() + 2;
       auto ret = vec.erase(second);
       //first指向1,second和third失效
       //ret指向3(当前在second的位置)
  • 上面的解释: erase的返回值也是迭代器。当删除second时,删除的不是那个叫做second的迭代器,而是它指向的元素2. 这时2后面的元素3顶上来,替代了2的位置。因此ret作为erase(second)的返回值,其实指向的就是原先second指向的位置,这个位置上现在是顶上来的3.

  • 在修改过容器后,不使用之前的迭代器。

(2)list 链表

  • 定义:std::list l; 跟前面都一样,尖括号用来实例化。

  • 操作:

    • 插入前端: push_front(数据);

    • 插入末端:push_back(数据);

    • 查询:find函数,返回迭代器。std::find(l.begin(), l.end(), 2);Find的第三个参数是什么意思?应该是从开头到结尾找值为2的元素。会返回查询结果的迭代器。

    • find的使用额外示例:

    • - **int** main(){
      
          list <**int**> L;
      
          L.push_back(1);
      
          L.push_front(0);
      
          L.push_back(2);
      
          list<**int**>::iterator iterPos=find(L.begin(), L.end(), 2); 
      
          *//在这个位置放入4*
      
          L.insert(iterPos, 4);
      
          for(**auto** i: L){
      
        ​    cout<<i<<" ";
      
          }
      
          *//4在2的前面。*
      
          return 0;
      
        }
      //结果:0 1 4 2 
      - 

      find感觉不是很好用,主要困难点在于返回的是迭代器。那我们在实际使用它的时候,一般会和那些接受迭代器做参数的函数一起。

    • 插入指定位置:insert( it(位置), 数据);

  • 不支持下标等随机访问,访问主要依靠迭代器。

  • 插入和删除操作不会导致迭代器失效**(除指向被删除的元素的迭代器外)**

  • STL容器:关联容器

(1)set 无序集合

  • 定义:std::set s;

  • 特点:不重复元素组成的集合。不保持插入顺序,内部按大小排序

  • 操作:

    • 插入(不允许出现重复元素):s.insert(val);
    • 查询值为val的元素:

​ s.find(val); //返回迭代器,这是find的特征。

  • 删除:

​ s.erase(s.find(val)); //导致迭代器失效

  • 统计值为val的元素的数目:返回数字。

      s.count(val);  //val的个数,总是0或1
    

(2)map 关联数组

  • 概念:每个元素由两个数据项组成,map将一个数据项映射到另一个数据项中。(形象的说就是“键值对”)

​ Map是个词典。存储键值对。

​ Key就像是查询项,如下标。称为键。

​ T则是内容。称为值。

  • 元素类型为pair<Key, T>。

  • 可以通过下标(也就是键key)(可以不是整数,可以是各种类型比如string)进行访问。如果元素不存在,则创建对应元素。

  • 可以用insert插入。

  • 其它操作:

    • 查询键为key的元素:

    s.find(key); // 返回迭代器

  • 统计键为key的元素个数:

    s.count(key); // 返回0或1

  • 删除:

    s.erase(s.find(key)); //导致被删元素的迭代器失效

  • STL容器:总结

​ 序列容器与关联容器的区别:

序列容器中的元素有顺序,可以按顺序访问。

关联容器中的元素无顺序,可以按数值(大小)访问。

vector中插入删除操作会使操作位置之后全部的迭代器失效。
@hzhwcmhf
Copy link

hzhwcmhf commented May 23, 2022

我们去年已经有同学整理过笔记 #47
如果只是重复课上内容可能贡献不大,大家可能也不太想看到重复内容。如果有新增部分,欢迎对之前的笔记做一定的补充。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants