主要关注单链表和双链表中都用到了哪些变量和数组,至于它们的实现方式和之前所学的无异
单链表
/**
* head: 第一个节点的下标
* idx: 当前节点可用的下标,第一个节点为0
* -1: 空节点下标
* e[i]: 下标为i的节点的value
* ne[i]: 下标为i的节点的下一个节点的数组下标,类似next指针
*/
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int m;
int head, idx, e[N], ne[N];
void init()
{
head = -1; // 此时链表为空,没有节点,所以代表第一个节点下标的head值应该为-1
idx = 0;
}
void add_to_head(int x)
{
e[idx] = x;
ne[idx] = head;
head = idx ++;
}
void add(int k, int x) // 在数组下标为k的节点之后插入值为x的节点
{
e[idx] = x;
ne[idx] = ne[k];
ne[k] = idx ++;
}
void remove(int k) // 删除数组下标为k的节点的后一个节点
{
ne[k] = ne[ne[k]];
}
双链表
/**
* 为了减少边界的判断条件,设立了两个存在但不存储值的边界节点,首尾节点下标分别用0和1表示
* e[i]: 下标为i的节点的value
* l[i]: 下标为i的节点的左侧节点的下标值
* r[i]: 下标为i的节点的右侧节点的下标值
* 0: 头节点,不代表真实节点,仅起标识作用
* 1: 尾节点,仅起标识作用,不用-1的原因在于我们应该可以通过尾节点索引到最后一个有意义的节点,1可以作为数组下标但-1不行
*
*/
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int idx, e[N], l[N], r[N];
void init()
{
r[0] = 1;
l[1] = 0;
idx = 2;
}
void add_to_left(int x)
{
e[idx] = x;
r[idx] = r[0];
l[idx] = 0;
l[r[0]] = idx;
r[0] = idx;
++ idx;
}
void add_to_right(int x)
{
e[idx] = x;
l[idx] = l[1];
r[idx] = 1;
r[l[1]] = idx;
l[1] = idx;
++ idx;
}
void add(int k, int x) // 在下标为k的节点的右侧插入一个节点
{
e[idx] = x;
r[idx] = r[k];
l[idx] = k;
l[r[k]] = idx;
r[k] = idx;
++ idx;
}
void remove(int k) // 删除下标为k的节点
{
l[r[k]] = l[k];
r[l[k]] = r[k];
}