![](https://img-blog.csdnimg.cn/2021011519002771.jpg?x-oss-process=image/resize,m_fixed,h_224,w_224)
数据结构
文章平均质量分 77
数据结构冲啊
咕噜咕噜崩
理想还是要有的
展开
-
数据结构回顾
数据量小==>内排序数据量大==>外排序O(n)得到第(前)K大元素==>快排思想(适合小数据量)O(nlogn)得到前K大元素==>维护一个K个元素的小顶堆(适合大数据量)【一次堆化需要logn,堆化n个元素需要n个logn】有序链表的范围查找==>跳表【O(logn)】...原创 2021-05-24 22:24:09 · 101 阅读 · 0 评论 -
Trie树
基本概念Trie 树,也叫“字典树”。顾名思义,它是一个树形结构。它是一种专门处理字符串匹配的数据结构,用来解决在一组字符串集合中快速查找某个字符串的问题。Trie 树的本质,就是利用字符串之间的公共前缀,将重复的前缀合并在一起:Trie树的操作Trie树是为匹配字符串而准备的,所以我们需要预先建立一个Trie树:构造Trie树但实际上构造Trie树,是利用数组(每个节点是字符值+下一字符的索引):纯26个小写英文字母匹配,可以通过字符的 ASCII 码减去“a”的 ASCII 码,迅原创 2021-01-29 21:26:00 · 9078 阅读 · 1 评论 -
字符串匹配
BF 算法BF 算法中的 BF 是 Brute Force 的缩写,中文叫作暴力匹配算法,也叫朴素匹配算法。BF 算法的时间复杂度很高,是 O(n*m)(n为主串字符个数,m为模式串字符个数)第一,实际的软件开发中,大部分情况下,模式串和主串的长度都不会太长。统计意义上,大部分情况下,算法执行效率要比这个高很多。第二,朴素字符串匹配算法思想简单,代码实现也非常简单。简单意味着不容易出错,如果有 bug 也容易暴露和修复。在工程中,在满足性能要求的前提下,简单是首选。这也是我们常说的KISS(Ke原创 2021-01-29 21:25:40 · 904 阅读 · 0 评论 -
图
图(Graph)顶点(vertex)和 边(edge)组成 。无向图顶点相连接的边数:度有向图入度(In-degree)和出度(Out-degree)带权图(weighted graph)如QQ好友亲密关系:存储方法邻接矩阵无向图的话浪费了一半空间稀疏图(Sparse Matrix):顶点很多,但每个顶点的边并不多(比如微信有好几亿的用户,但是每个用户的好友也就三五百个。)所以,邻接矩阵很浪费空间,但是邻接矩阵在矩阵计算方面有优势。邻接表大致思路如此,按照需求可以改造:原创 2021-01-27 19:19:40 · 290 阅读 · 0 评论 -
红黑树
平衡二叉树严格定义是这样的:二叉树中任意一个节点的左右子树的高度相差不能大于 1。(像完全二叉树、满二叉树其实就是平衡二叉树)实际应用中平衡二叉查找树中“平衡”的意思,其实就是让整棵树左右看起来比较“对称”、比较“平衡”。并不会死抠定义,高度差大于一也是可以的。红黑树(Red-Black Tree,简称 R-B Tree)它就是一种不严格的平衡二叉查找树红黑树中的节点,一类被标记为黑色,一类被标记为红色。要求:根节点是黑色的;每个叶子节点都是黑色的空节点(NIL),也就是说,叶子节点不存储原创 2021-01-27 19:19:21 · 212 阅读 · 0 评论 -
堆
概念堆是一个完全二叉树;(所以用数组存储)堆中每一个节点的值都必须大于等于(或小于等于)其子树中每个节点的值。(根结点最大就是大顶堆,根节点最小就是小顶堆)堆的存储:子结点下标/2 = 父节点下标(无论左右子结点)注意:是从下标1开始存放元素 (不然上式永远也到不了下标为0 元素位置)堆的操作1. 往堆中插入一个元素 (堆化heapify)从下往上堆化: 将插入元素变为堆最后的叶子结点代码中也就是将插入元素放在数组最后,然后与其父节点比较、交换:子结点下标/2 = 父节点下标(无论左原创 2021-01-27 19:18:55 · 252 阅读 · 0 评论 -
二叉树
树(Tree)高度和深度都是边数:二叉树(Binary Tree)每个节点最多有两个“叉”,也就是两个子节点的树,分别是左子节点和右子节点。满二叉树: 叶子节点全都在最底层,除了叶子节点之外,每个节点都有左右两个子节点,这种二叉树就叫做满二叉树(编号2);完全二叉树: 叶子节点都在最底下两层,最后一层的叶子节点都靠左排列,并且除了最后一层,其他层的节点个数都要达到最大。(编号 3 )链式存储法大部分二叉树代码都是通过这种结构来实现的。完全二叉树不就是“芸芸众树”啊,为神马还要单独提出原创 2021-01-27 19:18:36 · 316 阅读 · 0 评论 -
数据结构☞散列表
散列表(Hash Table)散列表的英文叫“Hash Table”,我们平时也叫它“哈希表”或者“Hash 表”。散列表用的是数组支持按照下标随机访问数据的特性,所以散列表其实就是数组的一种扩展,由数组演化而来。可以说,如果没有数组,就没有散列表。key:键或者关键字。散列函数(或“Hash 函数”“哈希函数”):把key值转化为数组下标的映射方法。散列函数计算得到的值就叫作散列值(或“Hash 值”“哈希值”)。散列函数散列函数设计的基本要求:散列函数计算得到的散列值是一个非负整原创 2021-01-23 23:25:48 · 23461 阅读 · 6 评论 -
哈希算法
基本概念将任意长度的二进制值串映射为固定长度的二进制值串,这个映射的规则就是哈希算法,而通过原始数据映射之后得到的二进制值串就是哈希值。哈希算法需要满足的几点要求:从哈希值不能反向推导出原始数据(所以哈希算法也叫单向哈希算法);对输入数据非常敏感,哪怕原始数据只修改了一个 Bit,最后得到的哈希值也大不相同;散列冲突的概率要很小,对于不同的原始数据,哈希值相同的概率非常小;哈希算法的执行效率要尽量高效,针对较长的文本,也能快速地计算出哈希值。应用应用一:安全加密最常用于加密的哈希算法是原创 2021-01-24 18:46:54 · 1226 阅读 · 0 评论 -
最常用排序方法选取总结
不要求稳定:数据量n很大时间复杂度空间复杂度数据范围k很大快速排序O(nlogn)O(1)数据范围k很小桶排序(计数排序)O(n+k)O(n+k)要求稳定排序:数据量n很大时间复杂度空间复杂度数据范围k很大归并排序O(nlogn)O(n)数据范围k很小桶排序(计数排序)O(n+k)O(n+k)数据量小就用插入排序![稳定;时间复杂度:O(n2n^2n2);空间复杂度:O(1)]java.util.Array原创 2021-01-24 18:46:19 · 106 阅读 · 0 评论 -
二分查找
特点1. 底层必须依赖数组2. 要求数据是有序的3. 二分查找更适合处理静态数据,也就是没有频繁的数据插入、删除操作。4. 时间复杂度就是 O(logn)每次与mid值比较一次,一共需要比较k次,时间复杂度是 O(k),通过 n/2k=1,我们可以求得 k=log2n,所以时间复杂度就是 O(logn)。实现public int bsearch(int[] a, int n, int value) { int low = 0; int high = n - 1; while原创 2021-01-24 18:45:54 · 379 阅读 · 0 评论 -
跳表
跳表的理解特点跳表中查询、插入、删除操作的时间复杂度也是 O(logn)(第 k 级索引的结点个数是第 k-1 级索引的结点个数的 1/2,那第 k级索引结点的个数就是 n/(2k))跳表的空间复杂度是 O(n)(但是在实际的软件开发中,原始链表中存储的有可能是很大的对象,而索引结点只需要存储关键值和几个指针,并不需要存储对象,所以当对象比索引结点大很多时,那索引占用的额外空间就可以忽略了。)跳表索引动态更新通过一个随机函数,来决定将这个结点插入到哪几级索引中,比如随机函数生成了值 K,那原创 2021-01-23 12:46:53 · 153 阅读 · 0 评论 -
排序优化
Collection.sort()方法底层使用Arrays.sort()实现的!而Arrays.sort主要采用TimSort算法, 大致思路是这样的:元素个数 < 32, 采用二分查找插入排序(Binary Sort)元素个数 >= 32, 采用归并排序,归并的核心是分区(Run)找连续升或降的序列作为分区,分区最终被调整为升序后压入栈如果分区长度太小,通过二分插入排序扩充分区长度到分区最小阙值每次压入栈,都要检查栈内已存在的分区是否满足合并条件,满足则进行合并最终栈内的分区被原创 2021-01-21 18:28:29 · 145 阅读 · 0 评论 -
外排序
外部排序就是数据存储在外部磁盘中,数据量比较大,内存有限,无法将数据全部加载到内存中。排序动图演示桶排序有序的桶数据在各个桶之间的分布是比较均匀的(不然复杂度就退化为 O(nlogn))每个桶里的数据再单独进行排序(一般为快速排序)然后再将数据按照桶的顺序依次拼到一起,就是排序好的数据。时间复杂度是 O(n)(桶的个数 m 要接近数据个数 n,至少在同一个数量级上)适合外部排序,大数据量。计数排序(Counting sort)计数排序其实是桶排序的一种特殊情况:适合虽然数据量大,原创 2021-01-21 18:28:06 · 330 阅读 · 0 评论 -
递归
关键:(直接考虑n和n-1两层之间的关系)如果一个问题 A 可以分解为若干子问题 B、C、D(这些子问题的处理逻辑和问题A相同),你可以假设子问题 B、C、D 已经解决,在此基础上思考如何解决问题 A。而且,你只需要思考问题 A 与子问题 B、C、D 两层之间的关系即可,不需要一层一层往下思考子问题与子子问题!经典例题:data01\src\data\recursion\Test.java 汉诺塔基本概念去的过程叫“递”,回来的过程叫“归”。基本上,所有的递归问题都可以用递推公式来表示。满足三个原创 2021-01-20 21:15:06 · 270 阅读 · 0 评论 -
数据结构之内排序
排序动图演示分析排序算法排序算法的执行效率最好情况、最坏情况、平均情况时间复杂度时间复杂度的系数、常数 、低阶实际的软件开发中,我们排序的可能是 10 个、100 个、1000 个这样规模很小的数据,所以,在对同一阶时间复杂度的排序算法性能对比的时候,我们就要把系数、常数、低阶也考虑进来。比较次数和交换(或移动)次数排序算法的内存消耗就是空间复杂度原地排序(Sorted in place):原地排序算法,就是特指空间复杂度是 O(1) 的排序算法。排序算法的稳定性稳定性是说,如原创 2021-01-20 21:14:32 · 548 阅读 · 0 评论 -
队列
基本概念先进者先出入队 enqueue();出队 dequeue()。用数组实现的队列叫作顺序队列,用链表实现的队列叫作链式队列。顺序队列链式队列循环队列(循环队列一般都用数组)需要浪费一个存储空间当队满时,(tail+1)%n=head阻塞队列这个时候有多个线程要对队列进行操作,就会存在线程安全问题。实现线程安全的队列我们叫作并发队列。最简单直接的实现方式是直接在 enqueue()、dequeue() 方法上加锁(synchronized),但是锁粒度大并发度会比原创 2021-01-19 13:16:25 · 75 阅读 · 0 评论 -
栈
基本概念后进者先出,先进者后出,这就是典型的“栈”结构。从栈的操作特性来看,是一种“操作受限”的线性表,只允许在端插入和删除数据。自动扩容数组栈理解均摊分析法:入栈操作的均摊时间复杂度为 O(1)重要例题表达式求值左括号直接压栈只有运算符高于符号栈顶时才直接压栈括号匹配data01/src/data/stack/StringCheck.java浏览器前进后退data01/src/data/stack/Browser.java...原创 2021-01-19 13:15:59 · 150 阅读 · 0 评论 -
链表
单链表删除某个结点:单纯的删除操作时间复杂度是 O(1),但需要遍历查找(时间复杂度为 O(n))。根据时间复杂度分析中的加法法则,删除值等于给定值的结点对应的链表操作的总时间复杂度为 O(n)。同理,插入一个结点操作的总时间复杂度为 O(n)想根据下标访问某一元素时间复杂度为O(n) 。循环链表双向链表双向循环链表数组与链表区别单纯的插入删除:总结:对于执行较慢的程序,可以通过消耗更多的内存(空间换时间)来进行优化;而消耗过多内存的程序,可以通过消耗更多的时间(时间换原创 2021-01-17 18:17:58 · 95 阅读 · 0 评论 -
数组
数组(Array)是一种线性表数据结构。它用一组连续的内存空间,来存储一组具有相同类型的数据。线性表(Linear List)顾名思义,线性表就是数据排成像一条线一样的结构。非线性表比如二叉树、堆、图等。之所以叫非线性,是因为,在非线性表中,数据之间并不是简单的前后关系。连续的内存空间和相同类型的数据计算机会根据数据类型给每个数据分配相同内存单元。计算机通过寻址公式访问数组中元素【这就是为什么数组以0为初始下标的原因】寻址公式:a[i]_address = base_address +原创 2021-01-17 18:17:33 · 82 阅读 · 0 评论 -
数据结构与算法 准备
重点:10 个数据结构:数组、链表、栈、队列、散列表、二叉树、堆、跳表、图、Trie 树;10 个算法:递归、排序、二分查找、搜索、哈希算法、贪心算法、分治算法、回溯算法、动态规划、字符串匹配算法。基本概念从广义上讲,数据结构就是指一组数据的存储结构。算法就是操作数据的一组方法。从狭义上讲,指某些著名的数据结构和算法,比如队列、栈、堆、二分查找、动态规划等。数据结构与算法:数据结构是为算法服务的,算法要作用在特定的数据结构之上。时间复杂度eg: int cal(int n) { .原创 2021-01-16 13:13:14 · 131 阅读 · 0 评论