链表(数组模拟)
为什么要模拟?
效率问题,第一种实现方式是指针+结构体的方式,面试题多,笔试题不多,因为每一次创建一个新的链表就要调用一下new函数来new一个新的节点,new一个新节点这个操作是非常慢的,一般在笔试题中,链表大小在10w~100w级别,但是new出这些节点基本就超时了,因此在平时笔试时基本不会采用动态链表方式,当然如果改进一下是可以用的,比如可以先初始化n各节点,不过本质跟我们模拟链表差不多了。
模拟两种链表:
- 单链表:单链表在算法或笔试题中用的最多的是邻接表(邻接表其实是n个链表,最主要应用是存储图和树)
- 双链表:用的比较多的情况是优化某些问题
单链表
每个节点有两个值,value和指向下一个节点的指针next,模拟时用e[N]和ne[N]表示,用下标进行关联
#include <iostream>
using namespace std;
const int N = 100010;
//head表示头结点下标
//idx存储当前用到了哪个地址
int head, e[N], ne[N], idx;
void init()
{
head = -1;
idx = 0;
}
void add_to_head(int x)
{
e[idx] = x;
ne[idx] = head;
head = idx;
idx++;
}
//将x插入到下标k节点后面
void add(int k, int x)
{
e[idx] = x;
ne[idx] = ne[k];
ne[k] = idx;
idx++;
}
//可以在任意位置插入,但是如果要在O(1)时间复杂度内插入,只能在某个点后面插入
//将下标是k的点后面的点删掉
void remove(int k)
{
ne[k] = ne[ne[k]];
}
//删一个点这个题idx不用变,一般来说算法题是不用管的
int main()
{
int m;
cin >> m;
init();
while(m--)
{
char op;
int k, x;
cin >> op;
if(op == 'H')
{
cin >> x;
add_to_head(x);
}
else if(op == 'D')
{
cin >> k;
if(!k)
head = ne[head];
else
remove(k - 1);
}
else
{
cin >> k >> x;
add(k - 1, x);
}
}
for(int i = head; i != -1; i = ne[i]) cout << e[i] << ' ';
cout << endl;
return 0;
}
双链表
之所以单链表要用head指向第一个点,是因为后面用的时候总会用一个变量存第一个点,双链表往往不需要,只需要用两个数来表示左右端点。
这题是循环双链表,五个操作只需要实现两个就可以,一个是在k节点右边插入一个点,一个是删除。left和right不是链表中的点,表示的是端点。
#include<iostream>
using namespace std;
const int N = 100010;
int m;
int e[N], l[N], r[N], idx;
void init()
{
//0表示左端点,1表示右端点
r[0] = 1, l[1] = 0;
//开始为空,左端点指向右端点,右端点指向左端点
idx = 2;
}
//在下标是k的节点右边插入一个节点,值为x
void add(int k, int x)
{
e[idx] = x;
r[idx] = r[k];
l[idx] = k;
l[r[k]] = idx;
r[k] = idx;
idx++;
}
//在k节点左边插入
//直接调用add(l[k], x);
//在k节点左边节点的右边插入即可
//删除第k个节点
void remove(int k)
{
r[l[k]] = r[k];
l[r[k]] = l[k];
}
int main()
{
init();
int m;
cin >> m;
while(m--)
{
int k, x;
string op;
cin >> op;
if(op == "L")
{
cin >> x;
add(0, x);
}
else if(op == "R")
{
cin >> x;
add(l[1], x);
}
else if(op == "D")
{
cin >> k;
remove(k + 1);
//第k个插入点的下标是k+1,因为idx是从下标2开始的
}
else if(op == "IL")
{
cin >> k >> x;
add(l[k + 1], x);
}
else
{
cin >> k >> x;
add(k + 1, x);
}
}
for(int i = r[0]; i != 1; i = r[i]) cout << e[i] << ' ';
cout << endl;
return 0;
}