前言:书读百遍其义自见,代码也是一样,不断地写不断地背,才能熟练的掌握
y总:yxc
链接:https://www.acwing.com/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

一、链表与邻接表

说明:这种方式new Node()非常慢。当然,这是针对算法竞赛笔试,只考虑时间最优。考研还是用这种的。
y总讲的是用数组来模拟单链表和双链表。原因就是比new

(1)单链表

  • 构建链表
const int N = 100010;
int head, e[N], ne[N], idx;

如何理解idx呢?

idx相当于新开的元素的地址,或者理解成新开结点的个数
  • 初始化
void init()
{head = -1;idx = 0;
}
  • 将x插入到头结点(头指针指向的结点)
void add_to_head ()
{e[idx] = x, ne[idx] = head, head = idx, idx ++
}
  • 将x插入到下标是k的元素后面
void add(int k, int x)
{e[idx] = x;               //给当前结点赋值ne[idx] = ne[k];      //将下标为k的next指针给当前结点ne[k] = idx;            //将下标为k的元素指向当前结点idx ++;
}
  • 删掉下标为k的后面一个结点(k指针直接指向下下个)
void remove()
{ne[k] = ne[ne[k]];
}

(2)双链表

  • 构建双链表
const int N = 10010;
int e[N], l[N], r[N], idx;
  • 初始化
void init ()
{//偷个懒,假设0是左端点,1是右端点r[0] = 1;l[1] = 0;idx = 2;
}
  • 在下标为k的右边插入x
void add(int k, int x)
{e[idx] = x;r[idx] = r[k];l[idx] = k;l[r[k]] = idx;r[k] = idx;
}
  • 删除下标为k的元素
void remove(int k)
{r[l[k]] = r[k];l[r[k]] = l[k];
}

二、栈与队列

(1)基本定义
栈:先进后出
队列:先进先出

(2)用数组模拟栈
栈的操作很简单,所以不需要额外定义函数。

  • 构建
int stk[N], tt;      //stk是stack,栈的意思;tt是top,栈顶的意思
  • 输入栈顶元素(push)
stk[ ++ tt] = x;
  • 弹出栈顶元素(pop)
tt --;
  • 判断非空
if (tt)  not empty
else empty
  • 查询栈顶元素
cout << stk[tt] << endl;

(3)单调栈
1.题目描述:给定一个长度为 N 的整数数列,输出每个数左边第一个比它小的数,如果不存在则输出 −1。
2.思路: 找出左边第一个比它小,意味着最终这是一个向右单调递增的栈,故名单调栈。
在保持栈内元素单调的情况下,如果新元素x比栈顶元素小,说明后面入栈的数找到第一个比它小的数一定是这个x而不是x前面的大数,因此x会将前面所有比它大的元素全部弹出。
3.时间复杂度: O(n)
4.【算法模板】

#include <iostream>
using namespace std;
const int N = 100010;
int stk[N], tt;int main()
{int n;cin >> n;while (n -- ){int x;scanf("%d", &x);while (tt && stk[tt] >= x) tt -- ;  //tt非空且栈顶大于x,则弹出栈顶元素if (!tt) printf("-1 ");                //若栈为空,则输出 - 1else printf("%d ", stk[tt]); //若栈非空,则输出上一个值(第一个比它小的)stk[ ++ tt] = x;             //将输入的值放进栈里,注意tt从0开始计数}return 0;
}

(4)KMP算法

①子串的定位运算通常称为串的模式匹配串匹配。广泛用于拼写检查、数据压缩等应用中。
②串的模式匹配设有主串S(也称正文串)和子串T(模式),在主串S中查找与模式T相匹配的子串,若匹配成功,则返回子串第一个字符在主串S中的下标

1.BF算法介绍

这是最朴素的算法:依次比较主串 i 和子串 j 所指的字符,若不匹配,则i指针回溯到 i - j + 2处重新进行匹配。在最坏情况下平均时间复杂度为O(n x m),因此改进为kmp算法

2.kmp算法介绍

KMP可以在O(n + m)的时间数量级完成匹配操作。其改进在于:不需回溯 i 指针,利用“已匹配”的结果将子串向右滑动尽可能远的一段距离。



注意点:一般next[ j ]开头都是 0 1,注意 J从1开始取,比较的是k - 1个元素。

(1)KMP算法
【算法步骤】

(2)求next值
【算法步骤】

(3)求next的修正值nextval
【算法步骤】

三、Trie树

一种可以快速存储和查找字符串、二进制数集合的数据结构

此图用来表示存储方式,五角星表示以该字符为结尾的“单词”存在。

(1)用数组模拟指针
下标:idx——>第x个数
儿子:son[x][0] ——>x代表结点x,0代表这是x的第0个儿子,即 ‘a’
计数:cnt[x] ——>以x结尾的单词有多少个
维护:idx ——>用来记录每个结点的编号

(2)基本操作

  • 初始化
const int N  = 100010;
int son[N][M], idx;
//N表示trie树结点个数,M表示每个结点的儿子个数,idx是第idx个结点
  • 插入
void insert(char *str)
{int p = 0;                                //令p等于根节点for (int i = 0; str[i]; i ++ )          //从根节点开始向下遍历{int u = str[i] - 'a';               //输入结点儿子的值if (!son[p][u]) son[p][u] = ++ idx; //若不存在儿子,则创建一个儿子p = son[p][u];                     //指针指向新儿子}cnt[p] ++ ;
}
  • 查询
int query(char *str)
{int p = 0;for (int i = 0; str[i]; i ++ ){int u = str[i] - 'a';if (!son[p][u]) return 0;p = son[p][u];}return cnt[p];
}

四、并查集

(1)基本使用场景
①将两个集合合并
②询问两个元素是否在一个集合当中

(2)基本原理
每个集合用一棵树来表示。树根的编号就是整个集合的编号。每个结点用p[x]结点用来表示存储他的父节点

(3)问题处理
①如何判断树根: if(p[x] == x)
②如何求x的集合编号: while(p[x] !=x) x = p[x];
③如何合并两个集合: px是x的集合编号,py是y的集合编号。p[x] = y

这里注意:在处理第二步的时候有一个优化:路径压缩。这节内容记住这个优化模板就行。

【算法描述】

#include <iostream>
using namespace std;
const int N = 100010;int n, m;
int p[N];   //一定要定义一个father数组,用来存储每个数的父亲结点int find (int x)    //核心步骤:返回x的祖宗结点 + 路径压缩
{if (p[x] != x) p[x] = find(p[x]);return p[x];
}int main()
{cin >> n >> m;for (int i = 1; i <= n; i ++) p[i] = i;     //初始状态每个数都在自己的集合当中,所以父结点就是自己while (m --){char op[2];int a, b;scanf("%s%d%d", op, &a, &b);if (*op == 'M') p[find(a)] = find(b);   //让a的祖宗结点连接在b的祖宗结点下面else{if (find(a) == find(b)) puts("Yes");else puts("No");}}return 0;
}

五、堆(Heap)

定义:堆又可称之为完全二叉堆。这是一个逻辑上基于完全二叉树、物理上一般基于线性数据结构(如数组、向量、链表等)的一种数据结构。

(一)堆的存储

  • 小根堆
    ①根节点的值最小 ②堆可以用一维数组保存。假设根的坐标为x,则左儿子为2x,右儿子为2x + 1 ③下标从1开始比较方便,因为如果是0的话2x还是0。

(二)堆的基本操作
1.插入一个数

heap[ ++ size] = x; up(size);

2.集合当中的最小值

heap[1];

3.删除最小值

heap [1] = heap[size]; size --; down(1);    //替代,干掉,下沉

4.删除任意一个元素

heap[k] = heap[size]; size--; down(k);up(k);    //不知道上升还是下沉干脆都做一遍好了

5.修改任意一个元素

heap[k] = x; down(k); up(k);

6.down操作:使权数大的值下沉(对大根堆就是使权数小的值下沉)

void down(int u)
{int t = u;        //假设t是三者中最小的if (u * 2 <= cnt && h[u * 2] < h[t]) t = u * 2;             //判断左儿子if (u * 2 + 1 <= cnt && h[u * 2 + 1] < h[t]) t = u * 2 + 1    //判断右儿子if (u != t)     //若最小的不是u,则u下沉{swap(h[u], h[t]);down (t);}
}

7.up操作

--------未更完--------

六、哈希表

散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做哈希函数,存放记录的数组叫做哈希表。

(一)基本概念

  • 使用场景:将一个较大的值域里的数映射到较小范围数中。
  • 对不同关键字很有可能映射到同一哈希地址,这种现象称为“冲突”,根据解决冲突的方式可以分为“拉链法”和“开放寻址法”。
  • (思维导图)

    (二)存储结构
    (1)拉链法-----一个单数组拉了很多链
  • 图示

1、定义哈希数组,将原数组映射到哈希数组中。
2、哈希数组的范围N最好取质数
3、scanf输入字符串可以自动过滤空格或空字符

  • 代码
int h[N], e[N], ne[N], idx;// 向哈希表中插入一个数void insert(int x){int k = (x % N + N) % N;e[idx] = x;ne[idx] = h[k];h[k] = idx ++ ;}// 在哈希表中查询某个数是否存在bool find(int x){int k = (x % N + N) % N;for (int i = h[k]; i != -1; i = ne[i])if (e[i] == x)return true;return false;}

(2)开放寻址法(坑位??)

  • 图示
  • 思路
    1.开一个2~3倍的哈希数组,保证映射后的数一定有位置存放
    2.循环整个数组,find函数返回可存放的位置。令h[find(x)] = x即可。
  • 代码
#include <iostream>
#include <cstring>
using namespace std;
const int N = 200003, null = 0x3f3f3f3f;
int h[N];int find(int x)
{int t = (x % N + N) % N;    //映射while (h[t] != null && h[t] != x){t ++;if (t == N) t = 0;}return t;
}int main()
{int n;scanf("%d", &n);memset(h, 0x3f, sizeof h);    while (n --){char op[2];int x;scanf("%s%d", op, &x);if (*op == 'I') h[find(x)] = x;else{if (h[find(x)] == null) puts("No");else puts("Yes");}}return 0;
}

(三)字符串的哈希方式

1预处理全部前缀的哈希(吧字符串看成p进制数-> 转化为10进制数-> 模上较小的数Q)

acwing数据结构笔记(一)相关推荐

  1. 归并排序算法 C++实现与时间复杂度(考过)恋上数据结构笔记

    复习梗概 画图,自己整个数组,看代码写步骤,这个对理解归并排序还是很有必要的 合并两个有序数组的merge函数写法 时间复杂度的分析方法!!! 其实我觉得去b站找个动态的步骤分解视频也是不错的复习方法 ...

  2. 数据结构笔记--线性表定义与实现(Swift)

    数据结构笔记系列 数据结构笔记-两个有序链表合并成一个有序链表 线性表   线性表是最常用且最简单的一种数据结构,简言之,一个线性表是 n 个数据元素的有序序列. 特点 只有一个首结点和尾结点: 除首 ...

  3. 数据结构笔记(王道考研) 第八章:排序

    大部分内容基于中国大学MOOC的2021考研数据结构课程所做的笔记,该课属于付费课程(不过盗版网盘资源也不难找...).后续又根据23年考研的大纲对内容做了一些调整,将二叉排序树和平衡二叉树的内容挪到 ...

  4. 数据结构笔记(王道考研) 第五章:树和二叉树

    大部分内容基于中国大学MOOC的2021考研数据结构课程所做的笔记,该课属于付费课程(不过盗版网盘资源也不难找...).后续又根据23年考研的大纲对内容做了一些调整,将二叉排序树和平衡二叉树的内容挪到 ...

  5. 数据结构笔记:选择排序

    原文地址添加链接描述 分类目录--数据结构笔记 每一步在未排序部分去比较当前标记的最小值(初始化为第1个)与当前值的大小,更新(或不跟新)最小值的索引,维护的是一个最小值的索引 每一轮找一个最小值,替 ...

  6. 二、考研数据结构笔记——绪论(理解数据结构,算法,时间复杂度计算做题技巧)

    一.数据结构基本概念 1.数据:数据是信息的载体.客观事物的一种表现形式.万事万物都能用数据表示出来. 2.数据元素:数据元素是数据的基本单位,一个数据元素有若干个数据项组成 3.数据项:构成数据元素 ...

  7. 考研数据结构笔记--数据结构和算法的基本概念

    考研数据结构笔记--数据结构和算法的基本概念 数据结构的基本概念 算法的基本概念 数据结构的基本概念 数据 数据是对客观事物的符合表示,在计算机科学中是指所有能输入到计算机中并且被计算机程序处理的符合 ...

  8. 大话数据结构笔记-图

    大话数据结构笔记-图 定义 图(Graph)是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为 G(V,E), 其中 G表示一个图, V是图G中的顶点的集合, E是图G中边的集合. 顶点就是图中 ...

  9. 一、考研数据结构笔记——引言及目录

    一.关于我理解的数据结构 1. 引言 本人自2021年3月准备考研,考研主要是为了提升学历,本科院校不是理想.迫切需要提高学历. 写这刊博客,主要是总结我考研路上对数据结构的一些理解,以及为了方便我后 ...

最新文章

  1. 45 MySQL自增id
  2. (转)android 在电脑上显示真机屏幕
  3. spm oracle cloud,oracle11g新特点——SQLPlanManagement(SPM)-Oracle
  4. PHPRPC for PHP
  5. 数据结构选择题(c语言)
  6. 视频光端机常见故障问题及处理方法大全
  7. Redis面试常问3 如何实现分布式锁 记住Redis的原子性
  8. js this指向分析
  9. word保存为高分辨率图片(word2016)
  10. mysql schemata_SCHEMATA · xiaoboluo768/mysql-system-schema Wiki · GitHub
  11. Django教程 —— 站点后台管理
  12. 唯物辩证法-矛盾论(普遍性+特殊性+斗争性+同一性)
  13. 模拟爬虫下载QQ空间相册高清图片
  14. 主成分回归之后预测_回归分析之主成分回归
  15. 初识 Arm 处理器
  16. Ubuntu中恢复rm命令误删文件(转)
  17. python变量命名规则
  18. pixhawk飞控板的硬件构成
  19. 1-fastfds 环境搭建
  20. Java学习----前端3

热门文章

  1. okd下gitlab首次启动没有重置密码如何登陆
  2. 【数据挖掘】2022年2023届秋招知能科技公司机器学习算法工程师 笔试题
  3. 全国青少年软件编程(Scratch)等级考试一级真题——2022.3
  4. 单片机c语言怎么实现按键松开,灯还保持松开前的状态,单片机C语言程序设计:K1-K4按键状态显示...
  5. 多传感器融合定位 第一章 概述
  6. 分子对接教程 | (8) PyMOL可视化对接结果
  7. 什么是模块化,为什么要模块化?
  8. 男人二十岁后应该学会的习惯 - 褪墨
  9. css+分散,【原】css实现两端对齐的3种方法
  10. Python库下载安装教程