【AcWing算法基础课】第二章 数据结构(部分待更)(1)

简介: e数组存储每个结点的值,ne数组存储每个结点的指向的下一个结点。

课前温习

8dc679b764b3809c1e1561c9d57b212c_d303555596e145cdbfeba228e635c7e5.png


一、单链表

邻接表:存储图和树

36379aee4c74224f20e042465825bb6f_a95efdacd62a48f1a7b341e5f85f82c4.png


e数组存储每个结点的值,ne数组存储每个结点的指向的下一个结点。


数组模拟链表比较快,指针模拟会涉及到new操作,比较慢。

核心模板

//head存储链表头,e数组存储结点值,ne数组存储结点的next指针,idx表示当前用到了哪个结点

int head,e[N],ne[N],idx;
//初始化
void init(){
    head=-1;
    idx=0;
}
//在链表头插入一个数a
void insert(int a){
    e[idx]=a,ne[idx]=head,head=idx++;
}
//将头结点删除,需要保证头结点存在
void remove(){
    head=ne[head];
}


题目链接:826. 单链表


1.1题目描述

实现一个单链表,链表初始为空,支持三种操作:

向链表头插入一个数;

删除第 k 个插入的数后面的数;

在第 k 个插入的数后插入一个数。

现在要对该链表进行 M 次操作,进行完所有操作后,从头到尾输出整个链表。

注意:题目中第 k 个插入的数并不是指当前链表的第 k 个数。例如操作过程中一共插入了 n 个数,则按照插入的时间顺序,这 n 个数依次为:第 1 个插入的数,第 2 个插入的数,…第 n 个插入的数。


输入格式


第一行包含整数 M,表示操作次数。

接下来 M 行,每行包含一个操作命令,操作命令可能为以下几种:

H x,表示向链表头插入一个数 x。

D k,表示删除第 k 个插入的数后面的数(当 k 为 0 时,表示删除头结点)。

I k x,表示在第 k 个插入的数后面插入一个数 x(此操作中 k 均大于 0)。


输出格式


共一行,将整个链表从头到尾输出。


数据范围


1≤M≤100000

所有操作保证合法。


输入样例:

10
H 9
I 1 1
D 1
D 0
H 6
I 3 6
I 4 5
I 4 5
I 3 4
D 6


输出样例:


6 4 6 5


1.2思路分析

524575f1b9416ba4b490f56edda8b9ec_eba1581708e04f67bdb3aece502955ca.png


插入操作:

74a4a712e02c7b0c3a264798b37ad142_8b147c2a6e1c43df957a2529b07a883e.png


删除操作:

7d403a9bac73065b5294777a7f1c2b38_c7fa460752984f138416e81c946e4165.png


1.3代码实现

#include <iostream>
using namespace std;
const int N=100010;
//head表示头结点的下标
//e[i]表示结点i的值 
//ne[i]表示结点的next的指针(i的下一个点的下标)
//idx表示当前用到了哪个点(点的编号/下标) 
int head,e[N],ne[N],idx;
//初始化 
void init(){
  head=-1;
  idx=0;
}
//将x插到头结点
void add_to_head(int x){
  e[idx]=x;        //保存当前结点的值 
  ne[idx]=head;    //将新结点的next指针指向head 
  head=idx;        //将新结点更新为头结点 
  idx++;          
} 
//将x插到下标为k的点的后面 
void add(int k,int x){
  e[idx]=x;        //保存当前结点的值 
  ne[idx]=ne[k];   //将新结点的next指针指向下标为k的点的下一位结点 
  ne[k]=idx;       //将下标为k的结点的next指针指向新结点 
  idx++;
}
//将下标为k的点的后面的点删掉
void remove(int k){
     ne[k]=ne[ne[k]];   //将下标为k的结点的next指针指向下标为k的结点的下一位的下一位结点 
} 
int main(){
    int m;
    cin>>m;
    init();
    while(m--){
      int k,x;
      char op;
      cin>>op;
      if(op=='H'){
      cin>>x;
      add_to_head(x);
  }
  else if(op=='D'){
    cin>>k;
    if(!k) head=ne[head];   //如果删除的数是头结点,下标为0,需要先将头结点更新为头结点的下一位,否则将无法访问链表元素,造成内存泄漏
    remove(k-1);            //此处k代表第k个数,第k个数下标为k-1,下同 
  }
  else{
    cin>>k>>x;
    add(k-1,x);
  }
  }
  for(int i=head;i!=-1;i=ne[i]){
    cout<<e[i]<<" ";
  }
  return 0;
}


二、双链表

用于优化某些问题


核心模板

//e数组存储结点的值,l数组存储结点的左指针,r数组存储结点右指针,idx表示当前用到了哪个结点

int e[N],l[N],r[N],idx;
//初始化
void init(){
    //0是左端点,1是右端点
    r[0]=1,l[1]=0;    //0号点的右边是1号点,1号点的左边是0号点
    idx=2;
}
//在结点a的右边插入一个数x
void insert(int a,int x){
    e[idx]=x;
    l[idx]=a,r[idx]=r[a];
    l[r[a]]=idx,r[a]=idx++;
}
//删除结点a
void remove(int a){
    l[r[a]]=l[a];
    r[l[a]]=r[a];
}


//e[i]表示结点i的值 
//l[i]表示结点的左指针(i的上一个点的下标)
//r[i]表示结点的右指针(i的下一个点的下标)
//idx表示当前用到了哪个点(点的编号/下标) 
int e[N],l[N],r[N],idx;
//初始化 
void init(){
  //0表示左端点,1表示右端点
  r[0]=1,l[1]=0;  //0号点的右边是1号点,1号点的左边是0号点 
  idx=2;
}
//在下标为k的点的右边插入x 
void add(int k,int x){
  e[idx]=x;        //保存当前结点的值 
  r[idx]=r[k];   //将新结点的右指针指向原序列k的下一位结点 
  l[idx]=k;      //将新结点的左指针指向k 
  l[r[k]]=idx;   //将原序列k的下一位结点的左指针指向新结点 
  r[k]=idx;      //将k的右指针指向新结点 
}
//删除第k个点 
void remove(int k){
    r[l[k]]=r[k];   //将原序列k的前一个点的右指针指向k的右指针指向的值 
    l[r[k]]=l[k];   //将原序列k的下一个点的左指针指向k的左指针指向的值 
}


题目链接:827. 双链表


2.1题目描述

实现一个双链表,双链表初始为空,支持 5 种操作:


在最左侧插入一个数;

在最右侧插入一个数;

将第 k 个插入的数删除;

在第 k 个插入的数左侧插入一个数;

在第 k 个插入的数右侧插入一个数

现在要对该链表进行 M 次操作,进行完所有操作后,从左到右输出整个链表。

注意:题目中第 k 个插入的数并不是指当前链表的第 k 个数。例如操作过程中一共插入了 n 个数,则按照插入的时间顺序,这 n 个数依次为:第 1 个插入的数,第 2 个插入的数,…第 n 个插入的数。


输入格式


第一行包含整数 M,表示操作次数。

接下来 M 行,每行包含一个操作命令,操作命令可能为以下几种:


L x,表示在链表的最左端插入数 x。

R x,表示在链表的最右端插入数 x。

D k,表示将第 k 个插入的数删除。

IL k x,表示在第 k 个插入的数左侧插入一个数。

IR k x,表示在第 k 个插入的数右侧插入一个数。

输出格式


共一行,将整个链表从左到右输出。


数据范围


1≤M≤100000

所有操作保证合法。


输入样例:


10
R 7
D 1
L 3
IL 2 10
D 3
IL 2 7
L 8
R 9
IL 4 7
IR 2 2


输出样例:


8 7 7 3 2 9


2.2思路分析

初始化:

7b68e2e852c232aaf94f56673f3e903a_194a8e7c547e4400a1b3c55165467a22.png


插入操作:

40e5c944c24f2a1406a826c6f968f635_45d377e5003242109df5fda194833aa8.png


先更新原序列k的下一个结点左指针,再修改k的右指针。否则,若颠倒,因原本k的右指针指向的便是k的下一个结点,先修改k的右指针会导致k的右结点“丢失”,再进行下续操作将无意义。

24e4e12e1091341c187b2c5e0685e2c8_92728d01199647668ee744f917e7f864.png


若在k的左边插入结点,相当于在k的前一个结点的右边插入结点,所以只需实现右插入即可。

85b86a46f24f787a7a7d9478b706d16a_d930cf5f0b754546bb166c1824131537.png


删除操作:

587c828f1124668d3e5fe818e007e3c4_9a1484eadab2493a81c86499ccbd941b.png


2.3代码实现

待更~


三、栈

先进后出


核心模板

//tt表示栈顶
int s[N],tt=0;
//向栈顶插入一个数
s[++tt]=x;
//从栈顶弹出一个元素
tt--;
//栈顶的值
s[tt];
//判断栈是否为空
if(tt>0){
}


题目链接:828. 模拟栈


3.1题目描述

实现一个栈,栈初始为空,支持四种操作:


push x – 向栈顶插入一个数 x;

pop – 从栈顶弹出一个数;

empty – 判断栈是否为空;

query – 查询栈顶元素。

现在要对栈进行 M 个操作,其中的每个操作 3 和操作 4 都要输出相应的结果。

输入格式


第一行包含整数 M,表示操作次数。

接下来 M 行,每行包含一个操作命令,操作命令为 push x,pop,empty,query中的一种。


输出格式


对于每个 empty 和 query操作都要输出一个查询结果,每个结果占一行。

其中,empty 操作的查询结果为 YES 或 NO,query 操作的查询结果为一个整数,表示栈顶元素的值。


数据范围


1≤M≤100000,1≤x≤109


所有操作保证合法。


输入样例:


10
push 5
query
push 6
pop
query
pop
empty
push 4
query
empty
1


输出样例:


5
5
YES
4
NO


3.2思路分析

利用数组进行模拟栈。


3.3代码实现

待更~


四、队列

先进先出


核心模板

普通队列


//在队尾插入元素,在队头弹出元素
//hh表示队头,tt表示队尾
int q[N],hh=0,tt=-1;
//向队尾插入一个数
q[++tt]=x;
//从队头弹出一个数
hh++;
//队头的值
q[hh];
//判断队列是否为空
if(hh<=tt){
}


循环队列

//hh表示队头,tt表示队尾的后一个位置
int q[N],hh=0,tt=0;
//向队尾插入一个数
q[tt++]=x;
if(tt==N) tt=0;
//从队头弹出一个数
hh++;
if(hh==N)  hh=0;
//队头的值
q[hh];
//判断队列是否为空
if(hh!=tt){


题目链接:829. 模拟队列


4.1题目描述

实现一个队列,队列初始为空,支持四种操作:


push x – 向队尾插入一个数 x;

pop – 从队头弹出一个数;

empty – 判断队列是否为空;

query – 查询队头元素。

现在要对队列进行 M 个操作,其中的每个操作 3 和操作 4 都要输出相应的结果。

输入格式


第一行包含整数 M,表示操作次数。

接下来 M 行,每行包含一个操作命令,操作命令为 push x,pop,empty,query 中的一种。


输出格式


对于每个 empty 和 query操作都要输出一个查询结果,每个结果占一行。

其中,empty 操作的查询结果为 YES 或 NO,query 操作的查询结果为一个整数,表示队头元素的值。


数据范围


1≤M≤100000,1≤x≤109,所有操作保证合法。


输入样例:


10
push 6
empty
query
pop
empty
push 3
push 4
pop
query
push 6


输出样例:


NO
6
YES
4


4.2思路分析

待更~


4.3代码实现

待更~


目录
相关文章
|
4天前
|
搜索推荐 算法 Java
Java数据结构与算法:排序算法之冒泡排序
Java数据结构与算法:排序算法之冒泡排序
|
4天前
|
搜索推荐 算法 Java
Java数据结构与算法:排序算法之归并排序
Java数据结构与算法:排序算法之归并排序
|
4天前
|
搜索推荐 算法 Java
Java数据结构与算法:排序算法之选择排序
Java数据结构与算法:排序算法之选择排序
|
3天前
|
存储 设计模式 算法
数据结构,算法宏观印象构建
数据结构,算法宏观印象构建
|
3天前
|
存储 算法 调度
算法与数据结构-栈篇
算法与数据结构-栈篇
11 0
|
4天前
|
存储 人工智能 算法
程序与技术分享:Acwing算法笔记
程序与技术分享:Acwing算法笔记
|
4天前
|
人工智能 算法
程序技术好文:算法与数据结构
程序技术好文:算法与数据结构
|
6天前
|
算法 C语言
【数据结构与算法 经典例题】使用栈实现队列(图文详解)
【数据结构与算法 经典例题】使用栈实现队列(图文详解)
|
6天前
|
存储 测试技术
【数据结构】操作受限的线性表,栈的具体实现
【数据结构】操作受限的线性表,栈的具体实现
17 5
|
6天前
|
算法 C语言
【数据结构与算法 经典例题】使用队列实现栈(图文详解)
【数据结构与算法 经典例题】使用队列实现栈(图文详解)