算法个人记录持续更新~~~

100 阅读1分钟

链表

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 邻接表的操作

33C184541F491D97374DFED45B84E50D.png

(一)邻接表的初始化

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++;
}

最短路

1. 朴素 Dijkstra

2. 堆优化的 Dijkstra

3. 贝尔曼 算法

4. spfa 算法

5. Floyd 算法