链表与邻接表

1、链表与邻接表

这里用数组模拟,也可以用结构体和指针实现,不过每次都动态new比较慢,直接new一定数量和数据就比较相似了。

单链表:主要用途

  • 邻接表:存储树和图

双链表:优化某些问题

1.1、单链表

e[N]表示某个点的值,ne[N]表示某个点的next指针是多少

所谓的头节点head初始值一般为-1,表示链表里没有任何节点。但实际上,head这个节点是不存在的,实际的头节点应该是第一个节点,如下图插入操作里面,真正的头节点是值为3这个节点,head实际是不存在的,他只是用来存储第一个节点的地址。

其基本构成如下:

17

插入操作:

17

像这里,我向头节点前插入一个节点,此时这个头节点的地址是被head节点指向的。我想让新插入的节点的ne指向第一个节点,那么就让ne = head就可以了。

1.1.1 练手题目

https://www.acwing.com/problem/content/828/

17
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 邻接表

实际就是一堆单链表

posted @ 2021-03-25 15:06  晓尘  阅读(224)  评论(0)    收藏  举报