写在前面:由于new
操作比如new Node()
是相当耗时的,并且笔试的时候数据量是比较大的,如果链表需要把节点都new出来可能会超时,这时候就需要使用数组来模拟。
数组模拟链表
(1)单链表常常使用邻接表来模拟,邻接表常常用来存储树和图。
(2)双链表通常是用来优化某些题。
e[N]: 某点的值是多少
ne[N]: 某个点的next指针是多少
e和ne使用下标来关联,0号点的值为e[0], next指针是ne[0], 显然ne[0] = 1,注意空节点的下标用-1来表示。
acwing数组模拟单链表
之前思考为什么这个只能支持插入的第k个链表删除、取出,也就是说,这个节点产生之后,无论前面的结点怎么样,这个k就是出生时的索引+1,初始的第一个结点从下标为0开始,只增不减。
import java.io.*;
import java.util.Scanner;
public class Main {
private static int N = 100010; // 数据规模为 10w
private static int head; // 表示头结点的下标
private static int[] e = new int[N]; // 表示结点 i的值
private static int[] ne = new int[N]; // 表示结点 i的 next指针是多少
private static int idx; // 表示存储当前结点已经使用结点的下一个结点
// 初始化数据
private static void init() {
head = -1; // 没有头结点
idx = 0; // 没有存入数据
}
// 将 val插到头结点
private static void addToHead(int val) {
e[idx] = val; // 赋值
ne[idx] = head; // 插入之前头结点的前面
head = idx; // 更新头结点信息
idx++; // idx向右移动
}
// 将下标是 k的点后面的点删掉
private static void remove(int k) {
ne[k] = ne[ne[k]]; // 让下标为 k的结点指向 下个结点的下个结点
}
// 将 val插入下标为 k的点的后面
private static void add(int k, int val) {
e[idx] = val;
ne[idx] = ne[k];
ne[k] = idx;
idx++;
}
// 程序入口
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
int m = Integer.parseInt(reader.readLine());
init(); // 初始化操作
// 进行 m次操作
while (m-- > 0) {
String[] s = reader.readLine().split(" ");
if (s[0].equals("H")) { // 插入头结点操作, 不能使用 ==, 要使用 equals()
int val = Integer.parseInt(s[1]);
addToHead(val);
} else if (s[0].equals("I")) { // 普通插入操作
int k = Integer.parseInt(s[1]);
int val = Integer.parseInt(s[2]);
add(k - 1, val); // 第 k个结点的下标为 k-1, 所以插入到下标为 k-1结点的后面
} else { // s[0] == "D", 删除操作
int k = Integer.parseInt(s[1]);
if (k == 0) { // 题意: k = 0, 删除头结点
head = ne[head];
} else
remove(k - 1); // 第 k个结点的下标为 k-1, 所以是删除到下标为 k-1后面的后面
}
}
// 打印输出
for (int i = head; i != -1; i = ne[i]) {
System.out.print(e[i] + " ");
}
}
}
数组模拟双向链表
e[N], l[N], r[N],
0号表示左端点,1号表示右端点
acwing数组模拟双向链表
import java.util.*;
import java.io.*;
class Main{
static BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
static int N = 100010;
static int[] e = new int[N]; //表示节点i的值
static int[] l = new int[N];
static int[] r = new int[N];
static int idx; //表示当前节点已经使用节点的下一个节点,或者说新函数用到的节点。
public static void init(){
r[0] = 1; // 0---头结点-x-x-x-尾部结点----1,
l[1] = 0; //
idx = 2;
}
//在节点k的右边插入一个数, k是下标, 比如说第一个插入的数下标是2
public static void add(int k, int x){
e[idx] = x;
r[idx] = r[k];
l[idx] = k;
l[r[idx]] = idx;
r[k] = idx++;
}
public static void delete(int k){
r[l[k]] = r[k];
l[r[k]] = l[k];
}
public static void main(String[] args) throws IOException{
int m = Integer.parseInt(cin.readLine());
init();
while(m-- > 0){
String[] s = cin.readLine().split(" ");
if(s[0].equals("L")){
int x = Integer.parseInt(s[1]);
int k = 0;
add(k, x);
}else if(s[0].equals("R")){
int x = Integer.parseInt(s[1]);
int k = l[1];
add(k, x);
}else if(s[0].equals("D")){
int k = Integer.parseInt(s[1]);
delete(k + 1);
}else if(s[0].equals("IL")){
int k = Integer.parseInt(s[1]);
int x = Integer.parseInt(s[2]);
add(l[k + 1], x);
}else{
int k = Integer.parseInt(s[1]);
int x = Integer.parseInt(s[2]);
add(k + 1, x);
}
}
for(int i = r[0]; i != 1; i = r[i]){
System.out.print(e[i] + " ");
}
}
}
数组模拟栈
import java.util.*;
class Main{
static int N = 100010;
static int[] stk = new int[N];
static int tt = 0;
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int m = in.nextInt();
in.nextLine(); //这里加一行in.nextLine()是因为nextLine和nextInt不互通,nextline函数并不知道之前已经读过一行了。
while(m-- > 0){
String[] ops = in.nextLine().split(" ");
if(ops[0].equals("push")){
int x = Integer.parseInt(ops[1]);
stk[++tt] = x;
}else if(ops[0].equals("pop")){
tt--;
}else if(ops[0].equals("empty")){
boolean empty = tt == 0;
if(empty){
System.out.println("YES");
}else{
System.out.println("NO");
}
}else{ //query
System.out.println(stk[tt]);
}
}
}
}
数组模拟队列
单调栈 & 单调队列
模版:
常见模型:找出每个数左边离它最近的比它大/小的数
int tt = 0;
for (int i = 1; i <= n; i ++ )
{
while (tt && check(stk[tt], i)) tt -- ;
stk[ ++ tt] = i;
}
acwing单调栈
给定一个长度为 N 的整数数列,输出每个数左边第一个比它小的数,如果不存在则输出 −1。
import java.util.*;
class Main{
static int N = 100010;
static int[] arr = new int[N];
static int[] stack = new int[N];
static int tt = 0;
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int n = in.nextInt();
for(int i = 0; i < n; i++) arr[i] = in.nextInt();
for(int i = 0; i < n; i++){
while(tt != 0 && stack[tt] >= arr[i]) tt--;
if(tt == 0) System.out.print("-1 ");
else System.out.print(stack[tt]+" ");
stack[++tt] = arr[i];
}
}
}