Fork me on GitHub

链表与邻接表

应用都可以用英文

为什么要用数组模拟

  1. 效率原因
  2. new Node(); // 非常慢,不会使用动态链表的形式
  3. 十万个节点会超时
  4. 如果直接初始化n个节点其实也是可以的

单链表

解题思路:

最主要还是理解三个操作:

  1. add
  2. remove
  3. add_to_head

数组实现的链表可以实现指针链表的所有事情.模拟的链表是静态的链表

用数组模拟邻接表

除非是找值,否则直接能找到位置

单链表只往后看,不能往前看。删了一个点就当它不存在就好了

idx只是一个地址。不用管删去的问题

TLE用删代码法

不会出现删除一个已经删除的点

可以先不管视频里怎么说的,一般来说,如果想删除链表第一个节点,会说“删除头结点”,如果想删除整个链表,会直接说“删除整个链表” head是指向头结点的指针,它本身是不存节点的,只是指向了整个链表的第一个节点。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1e5 +10;
int head, idx;
int ne[maxn], e[maxn];


void init()
{
    head = -1;
    idx = 0;
}

// 把某个值加入到头节点当中
void add_to_head(int x)
{
    e[idx] = x;
    ne[idx] = head;
    head = idx;
    idx ++;
}


void add(int k, int x)
{
    e[idx] = x;
    ne[idx] = ne[k];
    ne[k] = idx;
    idx++;
}

void remove(int k)
{
    ne[k] = ne[ne[k]];
    // 不需要free
}


int main()
{
    int m;
    cin >> m;
    while(m--)
    {
        char op;
        cin >> op;
        if(op == 'H')
        {
            int x;
            cin >> x;
            if(!x) head = ne[head];
            add_to_head(x);
        }
        else if(op == 'D')
        {
            int k;
            cin >> k;
            remove(k - 1);
        }
        else
        {
            int k, x;
            cin >> k >> x;
            add(k - 1, x);
        }
        
    }
    for(int i = head; i != -1; i = ne[i]) cout << e[i] << " ";
    cout << endl;
    return 0;
}

双链表

双链表的操作

  1. add

    注意我们是从idx = 2 开始运行的

  2. remove

写成数组比较简单,比写成结构体数组要简单很多

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1e5 + 10;
int k, x;
int head, tail, idx;
int l[maxn], r[maxn];
int e[maxn];


void init()
{
    head = 0, tail = 1;
    r[head] = 1;
    l[tail] = 0;
    idx = 2;
}

void add(int k, int x)
{
    e[idx] = x;
    l[idx] = k;
    r[idx] = r[k];
    l[r[k]] = idx;
    r[k] = idx++;
}

void remove(int k)
{
    l[r[k]] = l[k];
    r[l[k]] = r[k];
    //l[r[k]] = l[k];
    // 不用idx--,地址放在那里不管就好了
}

void read()
{
    string op;
    cin >> op;
    if(op == "L")
    {
        cin >> x;
        add(head, x);
    }
    else if(op == "R")
    {
        cin >> x;
        add(l[tail], x);
    }
    else if(op == "D")
    {
        cin >> k;
        remove(k + 1);
    }
    else if(op == "IL")
    {
        cin >> k >> x;
        add(l[k + 1], x);  // l已经表示在左边了,不需要再-1
    }
    else if(op == "IR")  // 两个字符的时候不能判断'r'
    {
        cin >> k >> x;
        add(k + 1, x);
    }
}
int main()
{
    int m;
    init();  // 不能每次都init
    cin >> m;
    while (m -- )
    {
        read();
    }
    for(int i = r[head]; i != tail; i = r[i]) printf("%d ", e[i]);
    cout << endl;
    return 0;
    
}

邻接表

邻接表就是n个单链表

链式前向星,就是数组模拟邻接表

模拟出来之后能更深刻的理解这个是在干嘛的

posted @ 2020-03-01 16:49  WalterJ726  阅读(368)  评论(0编辑  收藏  举报