C++效率掌握之STL库:vector函数全解

文章目录

  • 1.为什么要学习vector?什么是vector?
  • 2.vector类对象的常见构造
  • 3.vector类对象的容量操作
  • 4.vector类对象的迭代器
  • 5.vector类对象的元素修改
  • 6.vector类对象的元素访问
  • 7.vector迭代器失效问题
  • 希望读者们多多三连支持
  • 小编会继续更新
  • 你们的鼓励就是我前进的动力!

本篇是 STL 库专题之 vector ,该类在算法题中广泛应用,既有数组的特性,又有简单的遍历,增删查改的操作函数,大大减少了传统数组的繁琐

1.为什么要学习vector?什么是vector?

vector 是标准模板库(STL)提供的一个容器类,它是动态数组的一种实现。这意味着它可以像普通数组一样存储一组相同类型的元素,并且能根据需要自动调整自身的大小,例如,你可以创建一个存储整数的 vector,然后不断往里面添加或删除元素,它会自动管理内存空间

vector 类是和 STL 库一起问世的,string 函数是在 STL 库之前创造的,为了一致性简便性,vectorlist 等类都减少了一部分不必要的函数,也将 string 加入了 STL

在这里插入图片描述

vector 的主要特征可总结为:

  1. vector 是表示可变大小数组的序列容器。
  2. 就像数组一样,vector 也采用的连续存储空间来存储元素。也就是意味着可以采用下标对 vector 的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理
  3. 本质讲,vector 使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector 并不会每次都重新分配大小
  4. vector 分配空间策略:vector 会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的
  5. 因此,vector 占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增长
  6. 与其它动态序列容器相比(dequelist and forward_list),vector 在访问元素的时候更加高效,在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起 listforward_list 统一的迭代器和引用更好

2.vector类对象的常见构造

在这里插入图片描述

vector作为一个类也有构造函数,析构函数,=运算符重载,我们重点介绍构造函数里的功能

函数名功能说明
vector()无参构造
vector(size_type n, const value_type& val = value_type())构造并初始化n个val
vector (const vector& x)拷贝构造
vector (InputIterator first, InputIterator last)使用迭代器进行初始化构造

💻代码测试示例:

#include <iostream>
#include <vector>
using namespace std;int main()
{vector<int> first;                                vector<int> second(4, 100);                       vector<int> third(second.begin(), second.end());  vector<int> fourth(third);int myints[] = { 16,2,77,29 };vector<int> fifth(myints, myints + sizeof(myints) / sizeof(int));cout << "The contents of fifth are:";for (vector<int>::iterator it = fifth.begin(); it != fifth.end(); ++it)cout << ' ' << *it;cout << '\n';return 0;
}

⌨️代码输出示例:

在这里插入图片描述

3.vector类对象的容量操作

在这里插入图片描述

vector 中同样对数组实现了容量操作,只不过相比 string ,删掉了 lenth 这类作用不大的函数

函数名功能说明
size返回数组有效数据个数
max_size返回的是 vector 理论上能够容纳的最大有效数据
resize将有效数据的个数增加或减少 n 个,多出的空间用默认值,少的截断即可
capacity返回空间总大小,即容量
reserve为数组增加预留空间,即增加预留容量
empty检测数组是否为空,是返回 true ,否则返回 false
shrink_to_fit请求 vector 对象将其容量缩小到和当前有效数据个数相匹配的大小

🔥值得注意的是:

  1. capacity 的代码在 vsg++ 下分别运行会发现,vscapacity 是按 1.5 倍增长的,g++ 是按 2 倍增长的。这个问题经常会考察,不要固化的认为,vector 增容都是 2 倍,具体增长多少是根据具体的需求定义的,vsPJ 版本 STLg++SGI 版本 STL
  2. reserve 只负责开辟空间,如果确定知道需要用多少空间,reserve 可以缓解 vector 增容的代价缺陷问题
  3. resize 在开空间的同时还会进行初始化,影响 size

💻代码测试示例:

#include <iostream>
#include <vector>
using namespace std;int main()
{vector<int> v(10, 1);cout << "size:" << v.size() << endl;cout << "max_size:" << v.max_size() << endl;v.resize(15);cout << "resize:" << v.size() << ' ' << "v:";for (size_t i = 0; i < v.size(); ++i){cout << v[i] << ' ';}cout << endl;v.reserve(20);cout << "reserve:" << v.capacity() << endl;cout << "capacity:" << v.capacity() << endl;cout << "empty:" << v.empty() << endl;v.shrink_to_fit();cout << "shrink_to_fit:" << v.capacity() << endl;return 0;
}

⌨️代码输出示例:

在这里插入图片描述

4.vector类对象的迭代器

在这里插入图片描述

vector 的迭代器和 string 的基本使用方法一致

函数名功能说明
begin + end迭代器:begin 获取开头一个数据 + end 获取最后一个数据下一个位置
rbegin + rend反向迭代器:rbegin 获取最后一个数据 + end 获取开头一个数据上一个位置
cbegin + cendbegin + end 一样,但是常量迭代器只读
crbegin + crendrbegin + rend 一样,但是反向常量迭代器只读

💻代码测试示例:

#include <iostream>
#include <vector>
using namespace std;int main()
{vector<int> v(10);for (size_t i = 0; i < 10; ++i){v[i] = i;}cout << "迭代器:";vector<int>::iterator it1 = v.begin();while (it1 != v.end()){cout << *it1 << ' ';it1++;}cout << endl;cout << "反向迭代器:";vector<int>::reverse_iterator it2 = v.rbegin();while (it2 != v.rend()){cout << *it2 << ' ';it2++;}cout << endl;return 0;
}

⌨️代码输出示例:

在这里插入图片描述

5.vector类对象的元素修改

在这里插入图片描述

vector 相对于 string 增加了 emplace,去除了多余的 append

函数名功能说明
assign将新的内容赋值给数组
push_back数组尾插有效数据
pop_back数组尾删有效数据
insert在容器的指定位置插入元素
erase从容器里移除指定的元素或元素范围
swap交换两个 vector 对象的内容
clear移除 vector 对象中存储的所有字符
emplace在容器的指定位置直接构造元素
emplace_back在容器的末尾直接构造一个新元素

💻代码测试示例:

#include <iostream>
#include <vector>
using namespace std;int main()
{vector<int> v{ 0,1,2,3,4,5,6,7,8,9 };cout << "v:";vector<int>::iterator it1 = v.begin();while (it1 != v.end()){cout << *it1 << ' ';it1++;}cout << endl;v.assign(10, 0);cout << "assign:";vector<int>::iterator it2 = v.begin();while (it2 != v.end()){cout << *it2 << ' ';it2++;}cout << endl;v.push_back(5);cout << "push_back:";vector<int>::iterator it3 = v.begin();while (it3 != v.end()){cout << *it3 << ' ';it3++;}cout << endl;v.pop_back();cout << "pop_back:";vector<int>::iterator it4 = v.begin();while (it4 != v.end()){cout << *it4 << ' ';it4++;}cout << endl;v.insert(v.begin() + 2, 3, 1);cout << "insert:";vector<int>::iterator it5 = v.begin();while (it5 != v.end()){cout << *it5 << ' ';it5++;}cout << endl;v.erase(v.begin() + 2, v.begin() + 5);cout << "erase:";vector<int>::iterator it6 = v.begin();while (it6 != v.end()){cout << *it6 << ' ';it6++;}cout << endl;vector<int> vv{ 1,3,4,5,6,7,8,9 };cout << "vv:";vector<int>::iterator it7 = vv.begin();while (it7 != vv.end()){cout << *it7 << ' ';it7++;}cout << endl;swap(v, vv);cout << "swap:" << ' ' << "v:";vector<int>::iterator it8 = v.begin();while (it8 != v.end()){cout << *it8 << ' ';it8++;}cout << ' ' << "vv:";vector<int>::iterator it9 = vv.begin();while (it9 != vv.end()){cout << *it9 << ' ';it9++;}cout << endl;v.emplace(v.begin(), 100);cout << "emplace:";vector<int>::iterator it10 = v.begin();while (it10 != v.end()){cout << *it10 << ' ';it10++;}cout << endl;v.emplace_back(100);cout << "emplace_back:";vector<int>::iterator it11 = v.begin();while (it11 != v.end()){cout << *it11 << ' ';it11++;}cout << endl;v.clear();cout << "clear:";vector<int>::iterator it12 = v.begin();while (it12 != v.end()){cout << *it12 << ' ';it12++;}cout << endl;return 0;
}

⌨️代码输出示例:

在这里插入图片描述

6.vector类对象的元素访问

在这里插入图片描述

vector的本质是数组,固然是要[]运算符重载

函数名功能说明
operator[ ]像数组一样,使用方括号语法来访问其内部数据
at访问指定位置元素
back返回容器中最后一个元素的引用
front返回容器中第一个元素的引用

💻代码测试示例:

#include <iostream>
#include <vector>
using namespace std;int main()
{vector<int> v{ 0,1,2,3,4,5,6,7,8,9 };cout << "operator[ ]:" << v[5] << endl;cout << "at:" << v.at(5) << endl;cout << "back:" << (v.back() = 10) << ' ' << "v:";vector<int>::iterator it1 = v.begin();while (it1 != v.end()){cout << *it1 << ' ';++it1;}cout << endl;cout << "front:" << (v.front() = -1) << ' ' << "v:";vector<int>::iterator it2 = v.begin();while (it2 != v.end()){cout << *it2 << ' ';++it2;}cout << endl;return 0;
}

⌨️代码输出示例:

在这里插入图片描述

7.vector迭代器失效问题

迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了封装,比如:vector 的迭代器就是原生态指针 T* 。因此迭代器失效,实际就是迭代器底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间,造成的后果是程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃)

🚩会引起其底层空间改变的操作,都有可能是迭代器失效,比如:resizereserveinsertassignpush_back

#include <iostream>
using namespace std;
#include <vector>
int main()
{vector<int> v{1,2,3,4,5,6};auto it = v.begin();// 将有效元素个数增加到100个,多出的位置使用8填充,操作期间底层会扩容// v.resize(100, 8);// reserve的作用就是改变扩容大小但不改变有效元素个数,操作期间可能会引起底层容量改变// v.reserve(100);// 插入元素期间,可能会引起扩容,而导致原空间被释放// v.insert(v.begin(), 0);// v.push_back(8);// 给vector重新赋值,可能会引起底层容量改变v.assign(100, 8);/*出错原因:以上操作,都有可能会导致vector扩容,也就是说vector底层原理旧空间被释放掉,
而在打印时,it还使用的是释放之间的旧空间,在对it迭代器操作时,实际操作的是一块已经被释放的
空间,而引起代码运行时崩溃。解决方式:在以上操作完成之后,如果想要继续通过迭代器操作vector中的元素,只需给it重新
赋值即可。*/while(it != v.end()){cout<< *it << " " ;++it;}cout<<endl;return 0;
}

🚩指定位置元素的删除操作erase

#include <iostream>
using namespace std;
#include <vector>
int main()
{int a[] = { 1, 2, 3, 4 };vector<int> v(a, a + sizeof(a) / sizeof(int));// 使用find查找3所在位置的iteratorvector<int>::iterator pos = find(v.begin(), v.end(), 3);// 删除pos位置的数据,导致pos迭代器失效。v.erase(pos);cout << *pos << endl; // 此处会导致非法访问return 0;
}

erase 删除 pos 位置元素后,pos 位置之后的元素会往前搬移,没有导致底层空间的改变,理论上讲迭代器不应该会失效,但是:如果 pos 刚好是最后一个元素,删完之后 pos 刚好是 end 的位置,而 end 位置是没有元素的,那么 pos 就失效了。因此删除 vector 中任意位置上元素时,vs 就认为该位置迭代器失效了

以下代码的功能是删除vector中所有的偶数,请问那个代码是正确的,为什么?

#include <iostream>
using namespace std;
#include <vector>
int main()
{vector<int> v{ 1, 2, 3, 4 };auto it = v.begin();while (it != v.end()){if (*it % 2 == 0)v.erase(it);++it;}return 0;
}
int main()
{vector<int> v{ 1, 2, 3, 4 };auto it = v.begin();while (it != v.end()){if (*it % 2 == 0)it = v.erase(it);else++it;}return 0;
}

显然第二个是正确的

使用 v.erase(it) 删除元素后,迭代器 it 会失效,v.erase(it) 删除元素时,erase 函数会返回一个指向被删除元素之后元素的迭代器,这意味着在调用 v.erase(it) 之后,it 不再指向原来的迭代器,所以需要将这个返回值赋给 it,可以保证 it 始终指向一个有效的元素,从而避免了迭代器失效的问题

🚩Linux下,g++编译器对迭代器失效的检测并不是非常严格,处理也没有vs下极端

// 1. 扩容之后,迭代器已经失效了,程序虽然可以运行,但是运行结果已经不对了
int main()
{vector<int> v{ 1,2,3,4,5 };for (size_t i = 0; i < v.size(); ++i)cout << v[i] << " ";cout << endl;auto it = v.begin();cout << "扩容之前,vector的容量为: " << v.capacity() << endl;// 通过reserve将底层空间设置为100,目的是为了让vector的迭代器失效 v.reserve(100);cout << "扩容之后,vector的容量为: " << v.capacity() << endl;// 经过上述reserve之后,it迭代器肯定会失效,在vs下程序就直接崩溃了,但是linux下不会// 虽然可能运行,但是输出的结果是不对的while (it != v.end()){cout << *it << " ";++it;}cout << endl;return 0;
}
程序输出:
1 2 3 4 5
扩容之前,vector的容量为: 5
扩容之后,vector的容量为 : 100
0 2 3 4 5 409 1 2 3 4 5
// 2. erase删除任意位置代码后,linux下迭代器并没有失效
// 因为空间还是原来的空间,后序元素往前搬移了,it的位置还是有效的
#include <vector>
#include <algorithm>
int main()
{vector<int> v{ 1,2,3,4,5 };vector<int>::iterator it = find(v.begin(), v.end(), 3);v.erase(it);cout << *it << endl;while (it != v.end()){cout << *it << " ";++it;}cout << endl;return 0;
}
程序可以正常运行,并打印:
4
4 5// 3: erase删除的迭代器如果是最后一个元素,删除之后it已经超过end
// 此时迭代器是无效的,++it导致程序崩溃
int main()
{vector<int> v{ 1,2,3,4,5 };// vector<int> v{1,2,3,4,5,6};auto it = v.begin();while (it != v.end()){if (*it % 2 == 0)v.erase(it);++it;}for (auto e : v)cout << e << " ";cout << endl;return 0;
}
========================================================
// 使用第一组数据时,程序可以运行
[sly@VM - 0 - 3 - centos 20220114]$ g++ testVector.cpp - std = c++11
[sly@VM - 0 - 3 - centos 20220114]$ . / a.out
1 3 5
======================================================== =
// 使用第二组数据时,程序最终会崩溃
[sly@VM - 0 - 3 - centos 20220114]$ vim testVector.cpp
[sly@VM - 0 - 3 - centos 20220114]$ g++ testVector.cpp - std = c++11
[sly@VM - 0 - 3 - centos 20220114]$ . / a.out
Segmentation fault

从上述三个例子中可以看到:SGI STL中,迭代器失效后,代码并不一定会崩溃,但是运行结果肯定不对,如果 it 不在 beginend 范围内,肯定会崩溃的

与vector类似,string在插入+扩容操作+erase之后,迭代器也会失效

#include <string>
void TestString()
{string s("hello");auto it = s.begin();// 放开之后代码会崩溃,因为resize到20会string会进行扩容// 扩容之后,it指向之前旧空间已经被释放了,该迭代器就失效了// 后序打印时,再访问it指向的空间程序就会崩溃//s.resize(20, '!');while (it != s.end()){cout << *it;++it;}cout << endl;it = s.begin();while (it != s.end()){it = s.erase(it);// 按照下面方式写,运行时程序会崩溃,因为erase(it)之后// it位置的迭代器就失效了// s.erase(it); ++it;}
}

总结: 在使用新的 iterator 类型的变量前,对迭代器重新赋值即可


希望读者们多多三连支持

小编会继续更新

你们的鼓励就是我前进的动力!

请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/71223.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

人工智障的软件开发-容器化编码环境就绪-java-env

指令接收&#xff1a;「需要万能开发环境」 系统警报&#xff1a;检测到主人即将陷入"环境配置地狱" 启动救赎协议&#xff1a;构建量子化开发容器 终极目标&#xff1a;让"在我机器上能跑"成为历史文物 需求分析&#xff1a;碳基生物的先天缺陷 人类开发…

kkFileView二开之pdf转图片接口

kkFileView二开之Pdf转图片接口 kkFileView二开系列文章&#xff1a;1 kkFileView源码下载及编译2 Pdf转图片接口2.1 背景2.2 分析2.2 接口开发2.2.1 编写Pdf转图片方法2.2.2 编写转换接口 2.3 接口测试2.3.1 Pdf文件准备2.3.2 pdf2Image 3 部署 kkFileView二开系列文章&#x…

阅读论文笔记《Efficient Estimation of Word Representations in Vector Space》

这篇文章写于2013年&#xff0c;对理解 word2vec 的发展历程挺有帮助。 本文仅适用于 Word2Vect 的复盘 引言 这篇论文致力于探索从海量数据中学习高质量单词向量的技术。当时已发现词向量能保留语义特征&#xff0c;例如 “国王 - 男人 女人≈女王”。论文打算借助该特性&am…

SQL注入(SQL Injection)详解与实战

文章目录 一、什么是SQL注入&#xff1f;二、常见SQL注入类型三、手动注入步骤&#xff08;以CTF题目为例&#xff09;四、CTF实战技巧五、自动化工具&#xff1a;SQLMap六、防御措施七、CTF例题八、资源推荐 一、什么是SQL注入&#xff1f; SQL注入是一种通过用户输入构造恶意…

维护ceph集群

1. set: 设置标志位 # ceph osd set <flag_name> # ceph osd set noout # ceph osd set nodown # ceph osd set norecover 2. unset: 清除标志位 # ceph osd unset <flag_name> # ceph osd unset noout # ceph osd unset nodown # ceph osd unset norecover 3. 标志…

学习threejs,使用PointLight点光源

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.PointLight 二、&…

java连接redis

1.使用 1.创建java工程 2.引入依赖 <dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>5.2.0</version> </dependency> 3. //1.获取jedis对象&#xff0c;把所有对redis的操作都封装到…

论文笔记(七十二)Reward Centering(一)

Reward Centering&#xff08;一&#xff09; 文章概括摘要1 奖励中心化理论 文章概括 引用&#xff1a; article{naik2024reward,title{Reward Centering},author{Naik, Abhishek and Wan, Yi and Tomar, Manan and Sutton, Richard S},journal{arXiv preprint arXiv:2405.0…

强化学习笔记7——DDPG到TD3

前提&#xff1a;基于TD 的方法多少都会有高估问题&#xff0c;即Q值偏大。原因两个&#xff1a;一、TD目标是真实动作的高估。 二&#xff1a;自举法高估。 DDPG 属于AC方法&#xff1a;异策略&#xff0c;适合连续动作空间&#xff0c;因为他的策略网络直接输出的动作&#…

算法——结合实例了解Minimax算法(极小化极大算法)

计算机科学中最有趣的事情之一就是编写一个人机博弈的程序。有大量的例子&#xff0c;最出名的是编写一个国际象棋的博弈机器。但不管是什么游戏&#xff0c;程序趋向于遵循一个被称为Minimax算法&#xff0c;伴随着各种各样的子算法在一块。本篇将简要介绍 minimax 算法&#…

腿足机器人之四- 卡尔曼滤波

腿足机器人之四卡尔曼滤波 概率学基础贝叶斯准则熵 卡尔曼滤波扩展卡尔曼滤波信息滤波器 在机器人&#xff08;四足、人形&#xff09;领域&#xff0c;感知和行动的不确定性可能由多种因素引起&#xff0c;如传感器噪声、外部环境的变化、非精确控制以及实时性算力限制等。 和…

基于AWS云平台的法律AI应用系统开发方案

该方案可实现法律文档处理速度提升300%&#xff0c;关键信息提取准确率可达92%以上&#xff08;基于实际测试数据&#xff09;&#xff0c;适合构建企业级法律智能中台。建议采用分阶段实施策略&#xff0c;优先实现文档解析和智能问答模块。 一、技术栈规划 层级技术组件说明…

使用 GPT-SoVITS 克隆声音,很详细

使用 GPT-SoVITS 克隆声音&#xff0c;很详细 一、前言二、下载三、启动四、克隆声音1、准备克隆音频2、分离人声伴奏3、音频分割4、语音降噪5、ASR工具6、语音文本校对标注工具7、训练模型8、微调训练9、推理 一、前言 最近对文本转语言很感兴趣&#xff0c;但对直接在网站上…

基于Python的Flask微博话题舆情分析可视化系统

2024数据 ✅️标价源码 远程部署加 20 ✅️爬虫可用 有六月数据 ✅️修复bug不会突然打不开网页 系统稳定 系统的功能如下: 1.数据的爬取 2.用户的登录注册 3.热词统计&#xff0c;舆情统计 4.文章统计分析 5.发布地址统计 6.评论统计 7.情感分类统计 编程语言&#xff1a;py…

Pygame中自定义事件处理的方法2-2

在《Pygame中自定义事件处理的方法2-1》中提到了处理自定义事件的方法。通过处理自定义事件&#xff0c;可以实现动画等效果。 1 弹跳小球程序 通过处理自定义事件&#xff0c;可以实现弹跳小球程序&#xff0c;如图1所示。 图1 弹跳小球程序 2 弹跳小球程序原理 实现弹跳小…

【Flink快速入门-5.流处理之多流转换算子】

流处理之多流转换算子 实验介绍 前面实验中介绍的算子已经能够满足我们的大部分开发需求了&#xff0c;但是在实际工作中有时候还会遇到一些业务场景&#xff0c;例如需要摄入多个输入流并将其合并处理&#xff0c;或者需要将一条输入流分割为多条子流&#xff0c;在不同的子…

【STM32】DRV8833驱动电机

1.电机如何转动 只需要给电机两个端子加一正一负的极性就会转起来了&#xff0c;但是要注意的是不要将电机两端直接接在5v和gnd之间&#xff0c;这种电机一般要提供几百毫安的电流&#xff0c;而GPIO口只能提供几毫安&#xff0c;所以我们使用一个DRV8833来驱动 DRV8833输入口…

vue2老版本 npm install 安装失败_安装卡主

vue2老版本 npm install 安装失败_安装卡主 特别说明&#xff1a;vue2老版本安装慢、运行慢&#xff0c;建议升级vue3element plus vite 解决方案1&#xff1a; 第一步、修改npm 镜像为国内镜像 使用淘宝镜像&#xff1a; npm config set registry https://registry.npmmir…

Linux相关概念和易错知识点(27)(认识线程、页表与进程地址空间、线程资源划分)

目录 1.认识线程 &#xff08;1&#xff09;进程与线程的关系 &#xff08;2&#xff09;最小执行流 &#xff08;3&#xff09;轻量级进程&#xff08;LWP&#xff09; ①对task_struct的理解 ②轻量级进程 ③LWP和TCB的区别 2.页表与进程地址空间 &#xff08;1&…

GitHub基本操作及Git简单命令

GitHub简介 GitHub就是一个远程仓库&#xff0c;远程仓库可以理解为就是一个可以保存自己代码的地方&#xff0c;在实际开发当中一个项目往往是有多个人来共同协作开发完成的&#xff0c;那么就需要一个统一代码保存的地方&#xff0c;而GitHub就是起到一个共享和汇总代码的作…