数据结构
寒假自学了一点数据结构,最近又看了《挑战2》来复习了以下基本的数据结构,以此随笔简单记录之。
数据结构
Intro
数据结构是计算机中存储,组织数据的方式,通常来说,它并不是单指数据集合本身,而是包含以下内容:
- 数据集合,如数组,结构体等。
- 操作,比如栈有压栈,弹出等操作。
- 规则,规定了某种数据结构下在操作数据集合时应该遵守的规则,如栈的 Last In First Out.
链表
Intro
在很多情况下我们经常需要动态地操作数据集合,这时需要根据需要开辟或者释放内存空间,而有时我们要在任意位置插入新数据,在这些情况下,使用数组是非常不方便的,我们需要使用链表来管理数据集合。链表中相邻的节点不像数组那样分布在相邻的空间中,而是可能离散地分布。其中每个节点包含两个信息,本节点的值和指向下一个节点的指针(如果是双链表则还有指向上一个节点的指针), 下面我们用两种方法来模拟链表,一种是使用数组,这种方法还是需要估计空间,但是速度更快,另一种是使用结构体,这种方法不需要估计空间,新建节点时开辟即可,但是速度相对较慢。
单链表
链表中最简单的是单向链表。单向链表包含信息域和指针域。

下面主要介绍用数组模拟的方法,用结构体模拟的方法可以类似得到。
代码和解释
//head表示头节点的下标
//e[i]表示节点[i]的值
//ne[i]表示节点[i]的next指针
//idx存储当前已经用到了哪个点
int e[N],ne[N],idx,head;
//链表的初始化(-1表示空节点)
void initialize(){
head=-1;
idx=0;
}
//头部插入
void add_head(int x){
e[idx]=x;
ne[idx]=head;
head=idx;
idx++;
}
//在第k个插入的数后面插入
void insert(int k,int x){
e[idx]=x;
ne[idx]=ne[k-1];
ne[k-1]=idx;
idx++;
}
//删除第k个插入的数后面的数
void remove(int k){
if(k==0){
head=ne[head];
}
else{
ne[k-1]=ne[ne[k-1]];
}
}
双链表
双链表较单链表稍复杂一些,它的指针域包含 next 和 prev 指针,下面是数组模拟的代码和解释。

代码和解释
//r[]用来存储next指针,l[]存储prev指针,e[]存储节点的值,idx表示当前用到哪个节点
int r[N],l[N],e[N],idx;
//初始化,0表示头节点,1表示尾节点,idx从2开始
void init(){
r[0] = 1;
l[1] = 0;
idx = 2;
}
//在idx为k的点右边插入一个点
void insert(int k,int x){
e[idx] = x;
r[idx] = r[k];
l[r[k]] = idx;
l[idx] = k;
r[k] = idx;
idx++;
}
//删除第k个插入的点
void Delete(int k){
r[l[k+1]] = r[k+1];
l[r[k+1]] = l[k+1];
}
/*
L x,表示在链表的最左端插入数 x。
R x,表示在链表的最右端插入数 x。
D k,表示将第 k 个插入的数删除。
IL k x,表示在第 k 个插入的数左侧插入一个数。
IR k x,表示在第 k 个插入的数右侧插入一个数。
*/
链表的应用
用的比较多的是单链表,用来存储图。插入都是 O(1)的,而查找是O(n)的。
栈
Intro
栈是一种能有效帮助我们临时保存数据的数据结构,遵循 Last In First Out 的规则,支持 push(插入),pop(弹出),top(栈顶元素),isEmpty(是否为空)等操作。
用数组模拟栈是十分简单的,只需要开辟一个适当大小的数组,然后借助一个栈指针。

代码和解释
//top 是栈指针,指向栈顶元素,栈为空时置为0
int stk[N],top = 0;
void push(int x){
stk[++top] = x;
}
void pop(){
if(top)
top--;
}
bool isEmpty(){
return top == 0;
}
int Top(){
return stk[top];
}
应用
[https://www.acwing.com/problem/content/description/3305/](Acwing 3302.表达式求值)
[https://www.acwing.com/problem/content/832/](Acwing 830.单调栈)
队列
队列是一种特殊的线性表,遵循规则 First in First out, 正如生活中常见的那样。

模拟队列主要依靠两个模拟指针,分别指向队头和队尾。
代码和解释
// head 为队头指针,指向队头,tail为队尾指针,指向最后一个元素的后一个位置。
int q[N],head = 0,tail = 0;
void push(int x){
q[tail++] = x;
}
void pop(){
head++;
}
bool isempty(){
return head == tail;
}
int front(){
return q[head];
}

浙公网安备 33010602011771号