acwing算法笔记-数据结构:链表

链表

链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,它的特点是插入与删除数据十分方便,但寻找与读取数据的表现欠佳。其中链表又分为单链表和双链表。

链表的常见应用是构造邻接表,是之后处理树和图的相关问题的基础。 邻接表就是多个单链表!

单链表的构造:有n个节点,每个节点有val域和next域.
双链表的构造:在单链表的基础上多加一个pre域

  1. 结构体模拟链表

    这样的方式也叫动态链表,是一般情况下我们会选择的构造方式,思路和代码更直接。

    1
    2
    3
    4
    5
    struct ListNode {
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(nullptr) {}
    };

    缺点:因为new的底层涉及内存分配,调用构造函数,指针转换等多种复杂且费时的操作。一秒大概能new1w次左右。
    但是在算法比赛中,经常碰到操作在10w级别的链表操作,如果使用结构体这种操作,是无法在算法规定时间完成的。
    所以,在算法比赛这种有严格的时间要求的环境中,不能频繁使用new操作。也就不能使用结构体来实现数组。

    优点:思路直接,代码可读性比较高

  2. 数组模拟链表

    这样的构造方式也叫静态链表,比较常用于构造邻接表来解决图相关的问题。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    //这里我们为了更好的理解静态链表的构造方式,就把动态链表的代码对比分析

    //动态
    ListNode* i: 指针i,指向一个节点,简称 i的节点(不固定,因为指针会移动)
    i->val: i的节点的val
    i->next: i的节点的next指针
    i = p: 指针i移动到指针p的位置
    i->next = p: i的节点指向p的节点

    //静态
    int i: 节点下标i,指向一个节点,简称 i的节点(不固定,因为下标会变)
    e[i]: i的节点的val
    ne[i]: i的节点的next下标
    i = p: 下标i变成下标p
    ne[i] = p: i的节点指向p的节点

    //所以其实这两种的操作基本都是一一对应的,动态链表的操作从代码上可能会更直观一点

826. 单链表


基本思路

设计链表,这里采用静态链表的方式。

debug经验:

  1. 如果输出为空,检查是否读入和输出语句
  2. 如果是TLE, MLE, SF之类的错误,可以通过注释定位错误的位置

参考代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <iostream>

using namespace std;

const int N = 100010;


// head 表示头结点的下标
// e[i] 表示节点i的值
// ne[i] 表示节点i的next指针是多少
// idx 存储当前已经用到了哪个点
int head, e[N], ne[N], idx;

// 初始化
void init()
{
head = -1;
idx = 0;
}

// 将x插到头结点
void add_to_head(int x)
{
e[idx] = x, ne[idx] = head, head = idx ++ ;
}

// 将x插到下标是k的点后面
void add(int k, int x)
{
e[idx] = x, ne[idx] = ne[k], ne[k] = idx ++ ;
}

// 将下标是k的点后面的点删掉
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];
else 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;
}

Reference

[1]. yxc
[2]. 详细注释
[3]. 图解
[4]. 构造方式讨论
[5]. 精简笔记
[6]. dummy优化


827. 双链表


基本思路

双链表的构造,加上左右的哨兵节点会更方便

哨兵节点就相当于虚拟头尾节点,就可以不需要特判头尾节点了。
对于数组模拟链表,哨兵节点可以通过直接占用非零下标来实现

参考代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <iostream>

using namespace std;

const int N = 100010;

int m;
int e[N], l[N], r[N], idx;

// 在节点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;
}

Reference

[1]. yxc
[2]. Bug-Free
[3]. Hasity


链表专题题目

LeetCode

题单

剑指Offer

题单

Wiki

题单

AcWing

题单1
题单2

已打卡题目

LeetCode 2. 两数相加
LeetCode 19. 删除链表的倒数第N个节点
LeetCode 21. 合并两个有序链表
LeetCode 23. 合并K个排序链表
LeetCode 24. 两两交换链表中的节点
LeetCode 25. K 个一组翻转链表
LeetCode 61. 旋转链表
LeetCode 82. 删除排序链表中的重复元素 II
LeetCode 83. 删除排序链表中的重复元素
LeetCode 86. 分隔链表
LeetCode 92. 反转链表 II
LeetCode 141. 环形链表
LeetCode 142. 环形链表 II
LeetCode 143. 重排链表
LeetCode 203. 移除链表元素
LeetCode 206. 反转链表
LeetCode 237. 删除链表中的节点
LeetCode 445. 两数相加 II
LeetCode 876. 链表的中间结点

剑指 Offer 06. 从尾到头打印链表
剑指 Offer 18. 删除链表的节点
剑指 Offer 22. 链表中倒数第k个节点
剑指 Offer 24. 反转链表
剑指 Offer 25. 合并两个排序的链表
剑指 Offer 35. 复杂链表的复制
剑指 Offer 36. 二叉搜索树与双向链表
剑指 Offer 52. 两个链表的第一个公共节点


acwing算法笔记-数据结构:链表
https://vendestine.com/list
Author
Wenzhe Li
Posted on
April 2, 2022
Licensed under