单链表

算法题中最常考的单链表就是邻接表(用来存储图和数),比如最短路问题,最小生成树问题,最大流问题。双链表用于优化某些问题。
利用数组来表达单链表:存储值和指针的两个数组利用下标进行关联。

需要注意的是,head不是节点,只是指向某个节点的指针。head存的是链表第一个点的下标,形象地看就好像是指向了头结点。
这里贴一个非常有趣的题解

#include <iostream>using namespace std;const int N = 100010;int n;
int h[N], e[N], ne[N], head, idx;//对链表进行初始化
void init(){head = -1;//最开始的时候,链表的头节点要指向-1,//为的就是在后面进行不断操作后仍然可以知道链表是在什么时候结束/*插句题外话,我个人认为head其实就是一个指针,是一个特殊的指针罢了。刚开始的时候它负责指向空结点,在链表里有元素的时候,它变成了一个指向第一个元素的指针当它在初始化的时候指向-1,来表示链表离没有内容。*/idx = 0;//idx在我看来扮演两个角色,第一个是在一开始的时候,作为链表的下标,让我们好找//第二在链表进行各种插入,删除等操作的时候,作为一个临时的辅助性的所要操作的元素的下//标来帮助操作。并且是在每一次插入操作的时候,给插入元素一个下标,给他一个窝,感动!/*再次插句话,虽然我们在进行各种操作的时候,元素所在的下标看上去很乱,但是当我们访问的时候,是靠着指针,也就是靠ne[]来访问的,这样下标乱,也就我们要做的事不相关了。另外,我们遍历链表的时候也是这样,靠的是ne[]*/
}
//将x插入到头节点上
void int_to_head(int x){//和链表中间插入的区别就在于它有head头节点e[idx] = x;//第一步,先将值放进去ne[idx] = head;//head作为一个指针指向空节点,现在ne[idx] = head;做这把交椅的人换了//先在只是做到了第一步,将元素x的指针指向了head原本指向的head = idx;//head现在表示指向第一个元素了,它不在是空指针了。(不指向空气了)idx ++;//指针向下移一位,为下一次插入元素做准备。
}//将x插入到下标为k的点的后面
void add(int k, int x){e[idx] = x;//先将元素插进去ne[idx] = ne[k];//让元素x配套的指针,指向它要占位的元素的下一个位置ne[k] = idx;//让原来元素的指针指向自己idx ++;//将idx向后挪/*为了将这个过程更好的理解,现在将指针转变的这个过程用比喻描述一下,牛顿老师为了省事,想插个队,队里有两个熟人张三和李四,所以,他想插到两个人中间,但是三个人平时关系太好了,只要在一起,就要让后面的人的手插到前面的人的屁兜里。如果前面的人屁兜里没有基佬的手,将浑身不适。所以,必须保证前面的人屁兜里有一只手。(张三在前,李四在后)这个时候,牛顿大步向前,将自己的手轻轻的放入张三的屁兜里,(这是第一步)然后,将李四放在张三屁兜里的手抽出来放到自己屁兜里。(这是第二步)经过这一顿骚操作,三个人都同时感觉到了来自灵魂的战栗,打了个哆嗦。*/
}//将下标是k的点后面的点个删掉
void remove(int k){ne[k] = ne[ne[k]];//让k的指针指向,k下一个人的下一个人,那中间的那位就被挤掉了。
}
int main(){cin >> n;init();//初始化for (int i = 0; i < n; i ++ ) {char s;cin >> s;if (s == 'H') {int x;cin >> x;int_to_head(x);}if (s == 'D'){int k;cin >> k;if (k == 0) head = ne[head];//删除头节点else remove(k - 1);//注意删除第k个输入后面的数,那函数里放的是下标,k要减去1}if (s == 'I'){int k, x;cin >> k >> x;add(k - 1, x);//同样的,第k个数,和下标不同,所以要减1}}for (int i = head; i != -1; i = ne[i]) cout << e[i] << ' ' ;cout << endl;return 0;
}

我的代码:

#include <iostream>using namespace std;const int N = 100010;//head表示头节点的下标
//e[i]表示节点i的值
//ne[i]表示节点i的next指针是多少,节点i的下一个点的位置(下标/地址)
//idx存储当前已经用到了哪个点
int head, idx, e[N], ne[N];//初始化
void init()
{head = -1;idx = 0;
}//将x插到头节点
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的点后面的点删掉
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 ('H' == op){cin >> x;add_to_head(x);}else if ('D' == op){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;
}

双链表

#include <iostream>using namespace std;const int N = 100010;int e[N], l[N], r[N], idx;void init()
{r[0] = 1;l[1] = 0;idx = 2;
}
//在节点k的右边插入一个数
void add(int k, int x)
{e[idx] = x;r[idx] = r[k];l[idx] = k;l[r[k]] = idx;r[k] = idx;idx++;
}//删除节点k
void remove(int k)
{r[l[k]] = r[k];l[r[k]] = l[k];
}int main()
{int m;cin >> m;init();while (m--){string op;cin >> op;int k, x;if ("L" == op){cin >> x;add(0, x);}else if ("R" == op){cin >> x;add(l[1], x);}else if ("D" == op){cin >> k;remove(k + 1);}else if ("IL" == op){cin >> k >> x;add(l[k + 1], x);}else{cin >> k >> x;add(k + 1, x);}}for (int i = r[0]; i != 1; i = r[i])  cout << e[i] << ' ';cout << endl;return 0;
}

模拟栈

#include <iostream>using namespace std;const int N = 100010;int stk[N], tt;int main()
{int m;cin >> m;while (m--){string op;int x;cin >> op;if ("push" == op){cin >> x;stk[++tt] = x;}else if ("pop" == op)  tt--;else if ("empty" == op)    cout << (tt ? "NO" : "YES") << endl;else    cout << stk[tt] << endl;}return 0;
}

模拟队列

#include <iostream>using namespace std;const int N = 100010;int q[N], hh, tt = -1;int main()
{int m;cin >> m;while (m--){int x;string op;cin >> op;if ("push" == op){cin >> x;q[++tt] = x;}else if ("pop" == op)    hh++;else if ("empty" == op)  cout << (hh <= tt ? "NO" : "YES") << endl;else cout << q[hh] << endl;}return 0;
}

单调栈

单调栈和单调队列虽然很抽象难以理解,但是好消息在于能用的时机还是有限的。

#include <iostream>using namespace std;const int N = 100010;
int stk[N], tt;int main()
{int n;scanf("%d", &n);for (int i = 0; i < n; i++){int x;scanf("%d", &x);while (stk[tt] >= x && tt)   tt--;//当栈不为空且栈顶元素大于x,则舍去if (tt)  printf("%d ", stk[tt]);//如果栈内有元素,则输出结果else printf("-1 ");stk[++tt] = x;//将x压入栈}return 0;
}

单调队列

最经典的应用就是求滑动窗口的最大值最小值。
我们用q来表示单调队列,p来表示其所对应的在原列表里的序号。

由于此时队中没有一个元素,我们直接令1进队。此时,q={1},p={1}。

现在3面临着抉择。下面基于这样一个思想:假如把3放进去,如果后面2个数都比它大,那么3在其有生之年就有可能成为最小的。此时,q={1,3},p={1,2}

下面出现了-1。队尾元素3比-1大,那么意味着只要-1进队,那么3在其有生之年必定成为不了最小值,原因很明显:因为当下面3被框起来,那么-1也一定被框起来,所以3永远不能当最小值。所以,3从队尾出队。同理,1从队尾出队。最后-1进队,此时q={-1},p={3}

出现-3,同上面分析,-1>-3,-1从队尾出队,-3从队尾进队。q={-3},p={4}。

出现5,因为5>-3,同第二条分析,5在有生之年还是有希望的,所以5进队。此时,q={-3,5},p={4,5}

出现3。3先与队尾的5比较,3<5,按照第3条的分析,5从队尾出队。3再与-3比较,同第二条分析,3进队。此时,q={-3,3},p={4,6}

出现6。6与3比较,因为3<6,所以3不必出队。由于3以前元素都<3,所以不必再比较,6进队。因为-3此时已经在滑动窗口之外,所以-3从队首出队。此时,q={3,6},p={6,7}

出现7。队尾元素6小于7,7进队。此时,q={3,6,7},p={6,7,8}。

那么,我们对单调队列的基本操作已经分析完毕。因为单调队列中元素大小单调递*(增/减/自定义比较),
因此,队首元素必定是最值。按题意输出即可。

#include <iostream>using namespace std;const int N = 1000010;int a[N], q[N];int main()
{int n, k;scanf("%d%d", &n, &k);for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);int hh = 0, tt = -1;for (int i = 0; i < n; i ++ ){if (hh <= tt && i - k + 1 > q[hh]) hh ++ ;//判断对头是否划出窗口while (hh <= tt && a[q[tt]] >= a[i]) tt -- ;//如果队尾大于要加入的值,则出队q[ ++ tt] = i;if (i >= k - 1) printf("%d ", a[q[hh]]);//满足前k个数才输出}puts("");hh = 0, tt = -1;for (int i = 0; i < n; i ++ ){if (hh <= tt && i - k + 1 > q[hh]) hh ++ ;//判断对头是否划出窗口while (hh <= tt && a[q[tt]] <= a[i]) tt -- ;//如果队尾小于要加入的值,则出队q[ ++ tt] = i;if (i >= k - 1) printf("%d ", a[q[hh]]);//满足前k个数才输出}puts("");return 0;
}

KMP字符串

不错的题解
//KMP算法

#include <iostream>using namespace std;const int N = 100010, M = 1000010;//N为模板串长度,M为模式串长度
int n, m, ne[N];
char p[N], s[M];//s为模式串,p为模板串(匹配串)int main()
{cin >> n >> p + 1 >> m >> s + 1;//下标从1开始//求next数组for (int i = 2, j = 0; i <= n; i++){while (j && p[i] != p[j + 1]) j = ne[j];if (p[i] == p[j + 1]) j++;ne[i] = j;}//kmp匹配for (int i = 1, j = 0; i <= m; i++){while (j && s[i] != p[j + 1])    j = ne[j];if (s[i] == p[j + 1]) j++;//满足匹配条件,打印开头下标, 从0开始if (j == n){//匹配完成后的具体操作//如:输出以0开始的匹配子串的首字母下标printf("%d ", i - n);j = ne[j]; //再次继续匹配}}return 0;
}

Acwing算法基础课学习笔记(四)--数据结构之单链表双链表模拟栈模拟队列单调栈单调队列KMP相关推荐

  1. Acwing算法基础课学习笔记

    Acwing学习笔记 第一章 基础算法 快速排序 归并排序 二分查找 前缀和与差分 差分 位运算 离散化 第二章 数据结构 单链表 双链表 栈 队列 单调栈 单调队列 KMP算法 Trie 并查集 堆 ...

  2. ACwing算法基础课全程笔记(2021年8月12日开始重写+优化)

    更好的阅读体验 ※基础模板 2021年8月12日开始对基础课笔记进行重写+优化 请大家支持AcWing正版,购买网课能让自己获得更好的学习体验哦~ 链接:https://www.acwing.com/ ...

  3. AcWing算法基础课 Level-2 第二讲 数据结构

    单链表 826. 单链表 #include <bits/stdc++.h> using namespace std; const int N = 1e5 + 10;int idx, l[N ...

  4. 【学习笔记】数据结构之单链表(先进先出、先进后出)

    先看下数据结构中一种重要的数据存储形式,链表,下面两段是来自百度百科:        链表是一种物理存储单元上非连续.非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的.链表由一系列 ...

  5. 算法与数据结构模版(AcWing算法基础课笔记,持续更新中)

    AcWing算法基础课笔记 文章目录 AcWing算法基础课笔记 第一章 基础算法 1. 排序 快速排序: 归并排序: 2. 二分 整数二分 浮点数二分 3. 高精度 高精度加法 高精度减法 高精度乘 ...

  6. 背包四讲 (AcWing算法基础课笔记整理)

    背包四讲 背包问题(Knapsack problem)是一种组合优化的NP完全问题.问题可以描述为:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高 ...

  7. 吴恩达《机器学习》学习笔记四——单变量线性回归(梯度下降法)代码

    吴恩达<机器学习>学习笔记四--单变量线性回归(梯度下降法)代码 一.问题介绍 二.解决过程及代码讲解 三.函数解释 1. pandas.read_csv()函数 2. DataFrame ...

  8. 计算机视觉算法——Transformer学习笔记

    算机视觉算法--Transformer学习笔记 计算机视觉算法--Transformer学习笔记 1. Vision Transformer 1.1 网络结构 1.2 关键知识点 1.2.1 Self ...

  9. python的基本数据结构_Python学习笔记——基本数据结构

    列表list List是python的一个内置动态数组对象,它的基本使用方式如下: shoplist = ['apple', 'mango', 'carrot', 'banana'] print 'I ...

最新文章

  1. 云评测、云监测、云加速,性能魔方mmTrix全球速度最快
  2. .NET Core 构建配置文件从 project.json 到 .csproj
  3. arcgis已知两点投影坐标求距离
  4. 小球进盒子C语言,N个小球放进M个盒子算法-Go语言中文社区
  5. 业务自助分析怎么推?中梁集团办的这场BI建模大赛值得借鉴
  6. 数据结构之树的应用:并查集
  7. remix卡在android root,小米平板刷入remixeOS后怎么root?
  8. VS 的编译选项 build下的 platform target -- Any CPU和x86有什么影响?
  9. 【笔记】工具 - 输入法 - rime 小狼毫(weasel)
  10. Intel 80286工作模式
  11. 5.2.3 UE behaviour in state 5GMM-REGISTERED
  12. 解决在宝塔面板IIS服务器上部署svg/woff/woff2字体的问题
  13. 1-7-2 查询水果价格分数
  14. 隐藏专杀工具文件夹病毒专杀工具
  15. java 策略模式 促销_设计模式之策略模式
  16. 计算机照片打印设置方法,详解设置打印机纸张添加7寸照片尺寸在win7电脑中的操作的步骤...
  17. 程序员吃饭段子Java吃完就走_程序员专用段子笑话,笑话死循环
  18. 【b站求职笔记】行路院-王贺 2020年12月笔记
  19. Linux命令之中英文对照
  20. 计算机网络 英文笔记本,笔记本的英文是什么

热门文章

  1. 信息化时代的大数据攻略
  2. Nginx实现负载均衡Nginx缓存功能
  3. 动画详解Transformer模型注意力机制的概念与模型搭建
  4. java游戏开发入门(七) - 计时器
  5. 基于指标的约束多目标进化算法
  6. evaluate函数使用无效_VBA学习笔记5:函数与公式
  7. 周末老板请吃东西,刮到多少算多少?Python带你制作一款刮刮卡小程序。
  8. BCB6 中调用ADOCONNECTION的数据连接属性
  9. 【Linux】proc详解
  10. [转]Magento on Steroids – Best practice for highest performance