链表
1. 链表的概念
1.1 普通版本
struct Node{
Node *next;
int data;
};
为什么不用这个方法在算法题里写链表? 因为这个创建结点 动态生成
new或者malloc时间太慢了
1.2 acwing 版本
int e[N], ne[N], idx = 0, H = -1;
相当于用长度固定的数组来直接模拟链表, 这种好处就是快(静态链表)
e[N]用于存储数据,下标就是结点的编号(就是一般由idx自增来给的编号)ne[N]则是存下个结点的下标- 某个数据和对应的地址就是由同一个下标来关联起来的
idx就是给结点分配的序号,默认从 0 开始。ps:idx+1好像就是第几个插入的数H表示头指针,指向 -1 就是指向空 NULL
2. 链表的操作
2.1 初始化
void init(){
idx = 0;
H = -1;
}
2.2 插入
void add_to_head(int x){
e[idx] = x;
ne[idx] = H;
H = idx;
idx++;
}
void add(int i, int x){ //add x behind i(th)
e[idx] = x;
ne[idx] = ne[i - 1];
ne[i - 1] = idx;
idx++;
}
2.3 删除
void remove(int i){
ne[i - 1] = ne[ne[i - 1]];
}
2.4 遍历
void display(){
int p = H;
while(p != -1){
cout << e[p] << “ ”;
p++;
}
}
3. 邻接表
3.1 作用
用于存图和树
- 树看作是特殊的图
- 图分为有向图和无向图
- 无向图可以看作是特殊的有向图
总结:有向图可以看作是图和树存储的灵魂
3.2 邻接表的操作
(一)邻接表的初始化
void init(){
int h[N], e[M], ne[M];
memset(h, -1, sizeof h);
}
(二)存有向关系(头插法)
eg:a->b
add(int a, int b){
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}