![](https://img-blog.csdnimg.cn/20190918140129601.png?x-oss-process=image/resize,m_fixed,h_224,w_224)
数据结构与算法
本专栏大部分为我在极客时间学习王争老师所讲数据结构与算法之美的总结与笔记。王争老师将复杂的数据结构与算法讲的通俗透彻,我也推荐大家订阅王争老师的专栏:
-红桃K
刨根问底 往祖坟上刨
你知道的越多 你不知道的也越多
展开
-
浅谈字符串匹配算法 —— BM算法
概述BF算法在某些极端情况下,性能会退化的比较严重。RK 算法需要用到哈希算法,设计一个可以应对各种类型字符的哈希算法则并不简单。BM算法BM(Boyer-Moore)算法是一种非常高效的字符串匹配算法,性能约是著名的KMP 算法的 3 到 4 倍。但是BM算法的实现原理也很复杂。BM算法的思想我们把模式串和主串的匹配过程,可以看作模式串在主串中不停地往后滑...原创 2020-03-27 14:29:04 · 1303 阅读 · 0 评论 -
浅谈字符串匹配算法 —— BF算法、RK算法
概述BF算法和RK算法都是单模式串匹配的算法。所谓单模式串匹配算法通俗来说就是一个串和一个串进行匹配常见的单模式串匹配算法还有BM算法和KMP算法。与之相对的就是多模式串匹配算法,就是在一个串中同时查找多个串,常见的有Trie 树和 AC 自动机。两个概念模式串和主串我们在字符串 A 中查找字符串 B,那字符串 A 就是主串,字符串 B 就是模式串。...原创 2020-03-24 15:28:52 · 641 阅读 · 0 评论 -
图 —— 深度优先搜索算法(DFS)
广度优先优先搜索算法是一种 “地毯式”层层推进的搜索算法,先查找离起始顶点最近的,然后是次近的,依次往外搜索。而深度优先搜索算法就像 “走迷宫” ,是一种 “不撞南墙不回头”的搜索算法假设站在迷宫的某个岔路口,然后想找到出口。随意选择一个岔路口来走,走着走着发现走不通的时候,你就回退到上一个岔路口,重新选择一条路继续走,直到最终找到出口。这种回退到上个岔路口,其实就是回溯...原创 2020-03-24 19:36:22 · 275 阅读 · 0 评论 -
图 —— 广度优先搜索算法(BFS)
算法是作用于具体数据结构之上的,深度优先搜索算法和广度优先搜索算法都是基于“图”这种数据结构的。图上的搜索算法,最直接的理解就是,在图中找出从一个顶点出发,到另一个顶点的路径。而深度和广度优先搜索就是图的众多搜索算法中最简单的,也是最“暴力”的搜索算法代码实现前提代码中的图结构是利用邻链表实现的无权无向图。import java.util.LinkedL...原创 2020-03-24 13:48:41 · 385 阅读 · 0 评论 -
数据结构 —— 图
图树是一种非线性表的数据结构,图也是,图和树比起来,是一种更加复杂的非线性表数据结构。涉及图的算法有很多,也非常复杂,比如图的搜索、最短路径、最小生成树、二分图等等。树中的元素称为节点,而图中的元素称为顶点。图中的一个顶点可以与任意其他顶点建立连接关系。这种建立的关系叫作边(edge)。微博、微信等这些社交网络的好友关系就是一个非常典型的图结构。...原创 2020-03-08 17:30:50 · 268 阅读 · 0 评论 -
堆的应用
优先级队列优先级队列首先是一个队列,他符合队列的基本特性,先进先出。不过,在优先级队列中,数据的出队顺序不是先进先出,而是按照优先级来,优先级最高的,最先出队。实现优先级队列的方法有很多,用堆来实现是最直接、最高效的。堆和优先级队列十分相似,有时候一个堆就可以看作一个优先级队列。往优先级队列中插入一个元素,就相当于往堆中插入一个元素;从优先级队列中取出优先级最高的元素,就相...原创 2020-03-07 21:54:40 · 204 阅读 · 0 评论 -
阶段总结(四)——为什么同为O(n log n),快速排序的性能比堆排序要好?
在平均情况下,快速排序和堆排序的时间复杂度都是O(n log n),堆排序的时间复杂度甚至比快速排序的时间复杂度稳定。因为快速排序最坏情况下时间复杂度是O(n²)。但是,在实际的软件开发中,快速排序的性能要比堆排序好。为什么?主要有两方面原因堆排序数据访问的方式没有快速排序友好对于快速排序来说,数据是顺序访问的。对于堆排序来说,数据是跳着访问的。比如堆...原创 2020-03-06 15:55:33 · 819 阅读 · 0 评论 -
排序算法之堆排序分析
堆排序堆排序就是利用堆的特点所设计的一种排序算法。(完全二叉树,每个节点的值都大于其左右子节点(或者小于))堆排序的过程大致可以分解成两个步骤:建堆 和 排序。建堆我们可以将数组原地建成一个堆。原地就是不借助与别的数组,在原数组上操作建堆有两种方法:若原数组有n个数据,可以假设数组起初只包含一个数据,就是下标为1的数据。然后将下标从 2 到 n 的数据依次插入到...原创 2020-03-06 15:31:48 · 428 阅读 · 0 评论 -
数据结构 —— 堆
堆“堆”(Heap),实际上就是一种特殊的树。什么样的树才是堆?需要满足两个条件一、 堆是一个完全二叉树;二、 堆中每一个节点的值都必须大于等于(或小于等于)其子树中每个节点的值(也可以说是其左右节点的值)。大顶堆对于每个节点的值都大于等于子树中每个节点值的堆,我们叫作“大顶堆”。小顶堆对于每个节点的值都小于等于子树中每个节点值的堆,我们叫作“小顶堆”。...原创 2020-03-06 13:53:23 · 5257 阅读 · 0 评论 -
递归树——分析递归算法的时间复杂度
递归的思想就是,将大问题分解为小问题来求解,然后再将小问题分解为小小问题。这样一层一层地分解,直到问题的数据规模被分解得足够小,不用继续递归分解为止。如果我们把这个一层一层的分解过程画成图,它其实就是一棵树。我们给这棵树起一个名字,叫作递归树。如何用递归树求解时间复杂度递归树分析归并排序时间复杂度归并排序每次会将数据一分为二,因为每次分解都是一分为二,所以代价...原创 2020-03-04 20:18:52 · 6583 阅读 · 0 评论 -
清晰理解红黑树的演变---红黑的含义
本文转自:甜菜波波的cnblog前言 红黑树,对不少人来说是个比较头疼的名字,在网上搜资料也很少有讲清楚其演变来源的,多数一上来就给你来五条定义,红啊黑啊与根节点距离相等之类的,然后就开始进行旋转、插入、删除这些操作。一通操作下来,连红色和黑色怎么来的,是什么含义,有什么作用都云里雾里的,能搞清楚就怪了。 本文介绍红黑树,暂时不涉及任何代码,只是帮助你理解红黑...原创 2020-03-04 14:49:40 · 300 阅读 · 0 评论 -
数据结构 —— 红黑树
红黑树红黑树本质上是二叉平衡查找树,二叉平衡查找树有很多种,包括AVL树,Splay Tree(伸展树)、Treap(树堆)等红黑树是平衡二叉查找树中的一种,也是最常用的一种。二叉查找树在频繁的动态更新过程中,可能会出现树的高度远大于 log2n 的情况,从而导致各个操作的效率下降。极端情况下,二叉树会退化为链表,时间复杂度会退化到 O(n)。要解决频繁动态更新后复杂度退...原创 2020-03-04 17:32:34 · 590 阅读 · 0 评论 -
阶段总结(三)——为什么有了散列表我们还需要二叉树
二叉查找树最大的特点就是,支持动态数据集合的快速插入、删除、查找操作。散列表也是支持这些操作的,而且散列表的这些操作比二叉查找树更高效,时间复杂度是 O(1)。既然散列表如此高效,那么散列表是不是可以完全替代二叉树呢。或者说有没有什么地方用散列表是做不了的,必须用二叉树呢?散列表的插入、删除、查找操作的时间复杂度可以做到常量级的 O(1),非常高效。而二叉查找树在比较平衡...原创 2020-03-03 21:02:43 · 297 阅读 · 0 评论 -
数据结构——二叉查找树(Binary Search Tree)
二叉查找树二叉查找树是二叉树中最常用的一种类型,也叫二叉搜索树。顾名思义,二叉查找树是为了实现快速查找而生的。实际上它除了支持快速查找一个数据,还支持快速插入、删除一个数据。之所以能支持这些,依赖于二叉查找树的特殊结构。二叉查找树要求,在树中的任意一个节点,左子树的每个节点的值都要小于该节点的值,右子树的节点值都大于这个节点的值。二叉树查找树的查找操作先...原创 2020-03-03 20:18:46 · 661 阅读 · 0 评论 -
二叉树的遍历以及递归、非递归实现 / 层次遍历
二叉树的遍历二叉树遍历的经典方法有四种,前序遍历、中序遍历、后序遍历和层次遍历。其中,前、中、后序,表示的是节点与它的左右子树节点遍历打印的先后顺序。前序遍历是指,对于树中的任意节点来说,先打印这个节点,然后再打印它的左子树,最后打印它的右子树。中序遍历是指,对于树中的任意节点来说,先打印它的左子树,然后再打印它本身,最后打印它的右子树。后序遍历是指,对于树中的任意节点来...原创 2020-03-01 19:14:03 · 1005 阅读 · 0 评论 -
二叉树的存储方式 以及 为什么会有完全二叉树这一概念和定义???
二叉树的存储方式存储一棵二叉树有两种方法,一种是基于指针或者引用的二叉链式存储法,一种是基于数组的顺序存储法。链式存储法用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。二叉链每个节点有三个字段,其中一个存储数据,另外两个是指向左右子节点的指针。顺序储存法顺序结构存储就是使用数组来存储。我们把根节点存储在下标 i = 1 的位置,那左子节点存储在下标 ...原创 2020-03-01 11:56:46 · 1422 阅读 · 0 评论 -
教你一秒钟得出 N个节点的完全二叉树有多少个叶子节点 / 度为1或2的节点个数
没耐心的同学们可以直接拉到最底下看结论,有兴趣的话可以浏览全篇文章完全二叉树的节点计算基本是几类,要么是求完全二叉树中的叶子节点个数或者度为1或者2的节点的个数。其实这些问题根本上一一类问题,求解方法也是基本相同的。先把题列出来:一棵完全二叉树具有1000个结点,则此完全二叉树有多少个度为2的结点?完全二叉树699个节点,则叶子节点有多少个?已知完全二叉树...原创 2020-02-29 19:46:00 · 29005 阅读 · 4 评论 -
数据结构——二叉树基础
树树的特征树是由n(n>=1)个有限结点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。树?非树?树的概念树中的每个元素都叫做节点,用来连线相邻节点之间的关系,叫作“父子关系”A 节点就是 B 节点的父节点,B 节点是 A 节点的子节点。B、C、D 这三个节点的父节...原创 2020-02-29 19:46:39 · 574 阅读 · 0 评论 -
散列函数的设计方法
本文转自:https://www.cnblogs.com/zhuyf87/archive/2012/12/17/2821785.html好的散列函数要求:(1)计算简单,至少散列函数的计算时间不应该超过其他查找技术与关键字比较的时间;(2)计算出的散列地址分布均匀,这样可以保证存储空间的有效利用,并减少为处理冲突而耗费的时间。1.直接定址法取关键字或关键字的某个线性函数值为散列...原创 2020-02-28 15:03:56 · 2525 阅读 · 0 评论 -
数据结构——散列表(Hash Table)(哈希表)
散列表散列表英文是hashtable,经常被叫做Hash表,或者哈希表。哈希表其实就是由数组演化而来的,利用的就是数组支持按照下标随机访问数据的特性,可以说散列表就是数组的一种扩展。百度文库对散列表的解释:根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的...原创 2020-02-28 18:15:07 · 1819 阅读 · 0 评论 -
数据结构——跳表(skip list)
跳表跳表是一种各方面性能都比较优秀的动态数据结构,可以支持快速的插入、删除、查找操作。跳表的实质就是一种可以进行“二分查找”的有序链表,跳表在原有的有序链表上面增加了多级索引,通过索引来实现快速查找。理解跳表对于一个单链表来讲,即便链表中存储的数据是有序的,如果我们要想在其中查找某个数据,也只能从头到尾遍历链表。这样查找效率就会很低,时间复杂度会很高,时间复杂度是 O(n...原创 2020-02-27 13:48:22 · 1207 阅读 · 0 评论 -
二分查找问题以及常见的二分查找变种问题
二分查找二分查找又叫做折半查找,二分查找针对的是一个有序的数据集合,查找思想有点类似分治思想。每次都通过跟区间的中间元素对比,将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间被缩小为 0。查找效率假设数据大小是 n,每次查找后数据都会缩小为原来的一半,也就是会除以 2。最坏情况下,直到查找区间被缩小为空,才停止。那么被查找的区间变化就是:n,n/2,n/4,...原创 2020-02-26 16:11:24 · 1629 阅读 · 0 评论 -
排序算法阶段总结(二)——如何选择合适的算法
当数据符合线性排序对数据的要求当数据符合线性排序的要求时,优先使用线性排序。时间复杂度为O(n)。但是对于大多数情况下,数据并不一定符合线性排序的数据要求。小规模数据如果对于小规模的数据排序,我们可以选择时间复杂度是 O(n²) 的算法。因为在小规模数据面前,O(n²) 时间复杂度的算法并不一定比 O(nlogn) 的算法执行时间长。我们通常进行的复杂度分析是偏理...原创 2020-02-24 17:16:28 · 603 阅读 · 0 评论 -
排序算法之线性排序分析——桶排序、计数排序、基数排序
线性排序桶排序、计数排序、基数排序是时间复杂度是 O(n) 的序算法。因为这些排序算法的时间复杂度是线性的,所以我们把这类排序算法叫作线性排序(Linear sort)。之所以能做到线性的时间复杂度,主要原因是,这三个算法是非基于比较的排序算法,都不涉及元素之间的比较操作。此外,线性排序对排序数据的要求很苛刻,要注意线性排序算法的适用场景。桶排序算法思想是将要排序的...原创 2020-02-24 14:05:50 · 444 阅读 · 0 评论 -
排序算法之快速排序分析
快速排序快速排序的执行效率快速排序的内存消耗快速排序的稳定性快速排序的代码实现原创 2020-02-23 14:08:05 · 575 阅读 · 0 评论 -
排序算法之归并排序分析
归并排序排序思想:归并排序使用的就是分治思想,将一个大问题分解成小的子问题来解决。小的子问题解决了,大问题也就解决了。这种将大问题分解成小问题的思想与递归很像,分治和递归的区别就是:分治是一种解决问题的处理思想,递归是一种编程技巧如果要排序一个数组,我们先把数组从中间分成前后两部分,然后对前后两部分分别排序,再将排好序的两部分合并在一起,这样整个数组就都有序了。归并排序...原创 2020-02-20 21:50:56 · 1675 阅读 · 1 评论 -
排序算法阶段总结(一)冒泡、插入、选择
可以看出来,同样是O(n²)的时间复杂度,冒泡和插入排序是优于选择排序的选择排序是不稳定的排序算法,而且无论数据的有序度如何,他的时间复杂度都是O(n²)。而冒泡排序和插入排序相比又如何呢?实际开发中,插入排序的受欢迎程度远高于冒泡排序,他们最大的区别就是冒泡排序是数据的交换,而插入排序是数据的移动。冒泡排序不管怎么优化,元素交换的次数是一个固定值,是原始数据的逆序度。插...原创 2020-02-20 16:04:07 · 281 阅读 · 0 评论 -
排序算法之选择排序分析
选择排序选择排序算法和插入排序算法类似,也分已排序区间和未排序区间。但是不同的是选择排序每次会从未排序区间中找到最小的元素,并将其放置到已排序区间的末尾。选择排序的执行效率选择排序的最好、最坏、平均情况下时间复杂度都为O(n²)因为无论数据有序度如何,都是每次遍历一次数组,排好一个数据。所以选择排序的时间复杂度为O(n²)。选择排序的内存消耗选择...原创 2020-02-19 20:07:52 · 726 阅读 · 0 评论 -
留个纪念:第一次写直接插入排序的“正确”代码
public void insertionSort(int[] a, int n) { if (n <= 1) return; for (int i = 0; i < n - 1; i++) { //i代表有序区间的最后一个数据下标 for (int j = i + 1; j > 0; j--) { ...原创 2020-02-19 14:16:23 · 297 阅读 · 0 评论 -
排序算法之插入排序分析
插入排序要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序。只要遍历数组,找到数据应该插入的位置将其插入即可,而插入排序算法正是建立在此方法之上的排序算法插入排序的执行效率最好情况下时间复杂度如果要排序的数据已经是有序的,我们并不需要搬移任何数据。如果我们从尾到头在有序数据组里面查找插入位置,每次只需要比较一个数据就能确定插入的位置。...原创 2020-02-19 14:17:31 · 905 阅读 · 0 评论 -
排序算法之冒泡排序分析
冒泡排序冒泡排序是重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(你所定义的逻辑顺序)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。冒泡排序的执行效率最好情况下时间复杂度最好情况为当要排序的数据已经是有序的,只需要进行一次冒泡排序,时间复杂度为O(n)。最坏情况下时间复杂度最坏...原创 2020-02-18 20:43:48 · 1813 阅读 · 0 评论 -
如何分析一个“排序算法”
一、排序算法的执行效率最好、最坏、平均情况时间复杂度对于要排序的数据,有的接近有序,有的完全无序。有序度不同的数据,对于排序的执行时间肯定是有影响。我们需要了解排序算法在不同数据下的性能表现。同一阶时间复杂度的排序算法性能对比,不要忽略系数,常数,低阶时间复杂度反应的是数据规模 n 很大的时候的一个增长趋势,所以它表示的时候会忽略系数、常数、低阶。但是在实际我们使...原创 2020-02-18 18:53:51 · 268 阅读 · 0 评论 -
递归的技巧以及注意事项
什么是递归递归是一种非常高效、简洁的编码技巧,一种应用非常广泛的算法。比如DFS深度优先搜索、前中后序二叉树遍历等都是使用递归。方法或函数调用自身的方式称为递归调用,调用称为递,返回称为归。什么问题可以用递归解决?1.一个问题的解可以分解为几个子问题的解2.这个问题与子问题除了数据规模不同之外,求解思路要相同3.存在递归终止条件写递归代码的技巧1.写...原创 2020-02-18 18:50:34 · 2320 阅读 · 0 评论 -
用数组实现一个循环队列
public class RoundQueue { private String[] items; private int n; private int front; private int rear; public RoundQueue(int capacity) { this.items = new String[n]; ...原创 2020-02-17 17:27:49 · 988 阅读 · 0 评论 -
如何判断循环队列为队空or队满?
什么是循环队列循环队列就是将队列存储空间的最后一个位置绕到第一个位置,首尾相连形成逻辑上的环状空间,供队列循环使用。循环队列可以更简单防止假溢出的发生,但队列大小是固定的。假溢出作为队列用的存储区还没有满,但队列却发生了溢出,我们把这种现象称为"假溢出"解决假溢出有两种方案:一、将队列元素向前搬移。二、将队列看成首尾相连,即循环队列。如何判断循环队列为队空or...原创 2020-02-16 13:18:35 · 14314 阅读 · 0 评论 -
利用数组和链表实现一个队列
什么是队列可以把它想象成排队买票,先来的先买,后来的人只能站末尾,不允许插队。队列的最大特点就是“先进先出”。栈有两个基本操作:入栈 push()和出栈 pop()。入栈和出栈都是在栈顶。队列最基本的操作也是两个:入队 enqueue(),放一个数据到队列尾部;出队 dequeue(),从队列头部取一个元素。队列跟栈一样,也是一种操作受限的线性表数据结构。顺序队列和链...原创 2020-02-15 15:20:55 · 993 阅读 · 1 评论 -
栈的应用
当某个数据集合只涉及在一端插入和删除数据,并且满足后进先出、先进后出的特性,我们就应该首选“栈”这种数据结构。在函数调用中的应用操作系统给每个线程分配了一块独立的内存空间,这块内存被组织成“栈”这种结构, 用来存储函数调用时的临时变量。每进入一个函数,就会将临时变量作为一个栈帧入栈,当被调用函数执行完成,返回之后,将这个函数对应的栈帧出栈。------------------...原创 2020-02-14 23:44:04 · 280 阅读 · 0 评论 -
利用数组或链表实现一个栈
什么是栈栈是一种“操作受限”的线性表,只允许在一端插入和删除数据。栈最大的特点就是“后进先出”栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。栈的删除操作叫做出栈。出数据也在栈顶。顺序栈和链式栈栈既可以用数组来实现,也可以用链表来实现。用数组实现的栈,我们叫作顺序栈,用链表实现的栈,我们叫作链式栈。数组实现一个顺序栈public class Arra...原创 2020-02-14 18:12:39 · 819 阅读 · 0 评论 -
如何写好链表代码
正确理解引用的含义将某个变量赋值给引用,实际上就是将这个变量的地址赋值给引用,或者反过来说引用中存储了这个变量的内存地址,指向了这个变量,通过引用就能找到这个变量。p.next=q这行代码是说,p 结点中的 next 存储了 q 结点的内存地址p->next=p->next->next这行代码表示,p 结点的 next 指针存储了 p 结点的下下一个结点的内存...原创 2020-02-14 11:41:18 · 250 阅读 · 0 评论 -
Java实现单链表的头插尾插、头删尾删
构造一个简单的单链表类public class MyLinkedList { /** * 链表中的一个结点 */ public class Node { public int value; // 保存的是有效数据 public Node next; // 下一个结点的线索(引用) Node(int ...原创 2020-02-12 20:15:12 · 434 阅读 · 0 评论