A3阶段 第三课 向量和链表

2025年6月21日

学习时长

约1.5小时

难度

A3阶段/CSP-J

标签

数据结构

讲师

王骏峣

向量

向量(vector)是可以动态增长的数组,其长度会根据元素个数实时更新

原理:

vector在内部使用一个连续的内存块来存储元素,当需要增加元素时,会判断当前元素数量是否超过了容量,若是,则会重新分配一块更大的内存,并将原有元素复制到新的内存块中,然后释放原有内存块 连续内存块的优势:可以O(1)地访问vector中任意一个元素

向量的使用

代码 说明
向量的使用
#include <vector>;
导入头文件
向量的使用
vector<int> v;
定义一个向量,并规定其内部元素的类型
向量的使用
v.push_back(x);
在末尾插入一个元素x
(注:vector支持在任意位置插入元素,但需要移动后面的元素,时间复杂度O(n),基本不用)
向量的使用
v[i] = x;
将第i个元素修改为x
向量的使用
v[i]
访问第i个元素
(注意:vector下标从0开始)
向量的使用
v.empty()
查询v是否为空
向量的使用
v.size()
查询v的元素个数
向量的使用
v.clear();
清空v

vector的遍历

方法1

向量的遍历
for (int i : v){//按顺序遍历v中的每一个元素,将其保存在i中
//使用i访问元素
}

方法2

向量的遍历
for (int i = 0;i < v.size();i ++){//顺序
//使用下标(v[i])访问元素
}
for (int i = v.size() - 1;i >= 0;i --){//逆序
//使用下标(v[i])访问元素
}

例题

第一题 存包柜

前往

第二题 [NOIP2016 普及组] 海港

前往

学习要点总结

  1. vector是动态改变大小的数组
  2. 下标访问法类比数组
  3. 使用push_back()函数在尾部添加元素
  4. 其他函数类比其他STL容器

链表

不仅存储元素的值,还存储元素顺序的数据结构

结构体模拟链表

定义结构体链表

模拟链表
struct node{//节点
int val; //记录节点的值
int pre, nxt; //记录上一个节点和下一个节点
} a[N];

val存储当前节点的信息,它也可以是多个变量或一个复杂的数据类型
pre和nxt用来保存每一个节点的前继节点编号和后继节点编号

注意:下标的顺序并不链表的顺序


想要顺利地遍历链表,还需要额外的head变量存储链表首元素的下标,tail变量保存链表尾元素的下标


首节点的pre和尾节点的nxt可以设为-1,方便代码实现

链表的遍历

遍历链表
int i = head;
while(i != -1){
cout << a[i].val;
i = a[i].nxt;
}//顺序

int i = tail;
while(i != -1){
cout << a[i].val;
i = a[i].pre;
}//逆序

链表的插入

链表的插入
//一般情况
a[C].pre = A;
a[C].nxt = a[A].nxt;
a[a[A].nxt].pre = C;
a[A].nxt = C;

//特殊情况
//在首节点前插入元素
a[C].nxt = head;
a[C].pre = -1;
a[head].pre = C;
head = C;

//在尾节点后插入元素
a[C].pre = tail;
a[C].nxt = -1;
a[tail].nxt = C;
tail = C;

链表的插入时间复杂度为O(1)

链表的删除

链表的删除
a[a[C].pre].nxt = a[C].nxt;
a[a[C].nxt].pre = a[C].pre;

如果删除的是头或尾节点,那么特判改head和tail就好了

链表的优劣

链表和数组、vector一样可以用来存储元素
优势:可以O(1)地插入或删除任意一个元素
数组和vector需要O(n)

劣势:不支持快速查找第i个元素,只能从头到尾遍历查找,复杂度O(n)
数组和vector支持O(1)查找第i个元素
原因:数组和vector中的元素在内存中是连续存放的,只需要首地址+偏移量就能找到第i个元素的地址,而链表中的元素在内存中不是连续存放的

根据题型需要,选择合适的数据结构

第三题 队列安排

前往