链表与邻接表
1、链表与邻接表
这里用数组模拟,也可以用结构体和指针实现,不过每次都动态new比较慢,直接new一定数量和数据就比较相似了。
单链表:主要用途
- 邻接表:存储树和图
双链表:优化某些问题
1.1、单链表
e[N]表示某个点的值,ne[N]表示某个点的next指针是多少
所谓的头节点head初始值一般为-1,表示链表里没有任何节点。但实际上,head这个节点是不存在的,实际的头节点应该是第一个节点,如下图插入操作里面,真正的头节点是值为3这个节点,head实际是不存在的,他只是用来存储第一个节点的地址。
其基本构成如下:

插入操作:

像这里,我向头节点前插入一个节点,此时这个头节点的地址是被head节点指向的。我想让新插入的节点的ne指向第一个节点,那么就让ne = head就可以了。
1.1.1 练手题目
https://www.acwing.com/problem/content/828/

1.1.2 练手答案
#include<iostream>
using namespace std;
const int N = 100010;
// head表示头节点
// e[i]表示节点i的值
// ne[i]表示节点i的next指针是多少
// inx存储当前已经用到了哪个点,就是数组下标
int head,e[N],ne[N],idx;
// 初始化
void init()
{
head = -1;
idx = 0;
}
// 将x插入到头节点,实际就是head后面的位置
// 个人理解:head就像一个占位符,可以方便的去操作首个元素
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++;
}
// 将下标是k的点后面的点删除,如1,2,3输入2删除3,起始下标从1开始
void remove(int k)
{
ne[k] = ne[ne[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];
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;
}
1.2 双链表
一个节点同时指向左右两边l[N]和r[N],这里偷个懒,直接在初始时让最左边下标0为head,最右边下标1为tail
head和tail是边界,就像占位符一样,不算实质内容
初始状态为:
插入操作:
删除操作为:
1.2.1 练手题目
https://www.acwing.com/problem/content/description/829/
1.2.2 练手答案
#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; // 因为0和1已经被占用过了
}
// 在节点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];
}
int main()
{
cin >> m;
// 0是左端点,1是右端点
r[0] = 1, l[1] = 0;
idx = 2;
while (m -- )
{
string op;
cin >> op;
int k, x;
if (op == "L")
{
cin >> x;
insert(0, x);
}
else if (op == "R")
{
cin >> x;
insert(l[1], x);
}
else if (op == "D")
{
cin >> k;
remove(k + 1);
}
else if (op == "IL")
{
cin >> k >> x;
insert(l[k + 1], x);
}
else
{
cin >> k >> x;
insert(k + 1, x);
}
}
for (int i = r[0]; i != 1; i = r[i]) cout << e[i] << ' ';
cout << endl;
return 0;
}
1.3 邻接表
实际就是一堆单链表