
Java数据结构秘籍
文章平均质量分 92
程序之学,结构为纲。Java之为用,经纬百业,其理在条分缕析,其要在架构精严。
吾初学此道,常惑于数据流转、算法屈伸。今辟专栏,录所思所悟:或述链表之柔,数组之刚;或解栈堆之序,树图之章。非敢称达者,唯求以文会友,与同好共探堂奥。
愿积跬步,渐至千里。是为序。
手握风云-
[就读于河北科技大学]
[23级 软件工程专业]
[目标:拿到一个大厂offer]
展开
专栏收录文章
- 默认排序
- 最新发布
- 最早发布
- 最多阅读
- 最少阅读
-
Java数据结构第二十七期:布隆过滤器,用 “模糊” 换高效的查重黑科技
布隆过滤器是一种高效的概率型数据结构,用于判断元素是否存在集合中。它通过多个哈希函数将元素映射到位图中,具有空间效率高、查询速度快的特点,但存在一定误判率。文章详细介绍了布隆过滤器的原理、Java实现代码(包括添加和查询操作),以及其优缺点和应用场景(如URL去重、垃圾邮件过滤等)。需要注意的是,布隆过滤器不支持直接删除元素,且存在假阳性可能。该结构特别适合处理海量数据的快速查询需求。原创 2025-09-27 11:25:02 · 978 阅读 · 33 评论 -
Java数据结构第二十六期:解密位图,海量数据处理的 “空间魔法”
本文介绍了Java中的位图数据结构及其应用。位图是一种紧凑表示布尔值的数组,每个元素对应一个位,适合处理海量不重复整数数据。通过40亿整数查询案例,展示了位图如何用476MB空间解决内存不足问题。文章详细讲解了位图实现原理,包括set()、get()、reSet()方法的核心位运算逻辑,并提供了完整的Java实现代码。最后指出位图在高效存储、集合运算、去重计数及布隆过滤器等场景的重要应用价值,特别适合处理大规模数据的布尔状态判断需求。原创 2025-08-18 02:03:32 · 857 阅读 · 42 评论 -
Java数据结构第二十五期:红黑树传奇,当二叉树穿上 “红黑铠甲” 应对失衡挑战
本文详细介绍了红黑树的概念、性质及Java实现。红黑树是一种自平衡二叉查找树,通过颜色属性(红/黑)和特定规则确保近似平衡。文章重点讲解了红黑树的节点定义、插入操作(包括颜色调整和旋转处理)以及验证方法(检查颜色连续性和路径黑节点数量)。此外,还对比了AVL树与红黑树的特性差异,并列举了红黑树在编程语言库、数据库系统和文件系统等领域的应用场景。全文提供了完整的Java代码实现,包括节点结构、插入逻辑和旋转操作等关键算法。原创 2025-07-16 15:29:07 · 1277 阅读 · 42 评论 -
Java数据结构第二十四期:探秘 AVL 树,当二叉搜索树学会 “自我调节”
本文介绍了AVL树的基本概念和实现原理。首先回顾二叉搜索树的特点及其局限性,引出AVL树的必要性。AVL树通过平衡因子(左右子树高度差不超过1)实现自平衡,确保操作时间复杂度维持在O(logN)。文章详细阐述了AVL树的节点定义、插入操作、四种旋转调整方式(右单旋、左单旋、左右双旋、右左双旋)的实现逻辑,并提供了验证AVL树平衡性的方法。最后分析AVL树的性能特点:查找、插入、删除均为O(logN)时间复杂度,具有高效查找优势,但需付出额外存储和维护平衡的开销。原创 2025-06-23 11:32:40 · 906 阅读 · 25 评论 -
Java数据结构第二十三期:Map与Set的高效应用之道(二)
扩容的时候还需要注意,比如我们要插入的元素的key为14,扩容前需要插入下标为4的位置,扩容2倍后,就需要插入下标为14的位置。理想的搜索⽅法:可以不经过任何比较,⼀次直接从表中得到要搜索的元素。我们的基本思路是:利用HashSet,先遍历一遍数组,把集合中没有的数字放入,如果有,再移除,最后集合中剩下的元素就是只出现一次的数字,再遍历一遍数组,匹配HashSet中的数组。由于我们哈希表底层数组的容量往往是小于实际要存储的关键字的数量的,就会导致冲突的发⽣是必然的,但我们能做的应该是尽量的降低冲突率。原创 2025-03-15 21:26:26 · 1338 阅读 · 38 评论 -
Java数据结构第二十二期:Map与Set的高效应用之道(一)
上面的TreeMap传给了m,m是NavigableMap类型的,而NavigableMap又继承了Map,我们再来看add方法,里面的e接收了key,PRESENT接收了value,而这个PRESENT又是一个Object类。对有n个结点的⼆叉搜索树,若每个元素查找的概率相等,则⼆叉搜索树平均查找⻓度是结点在⼆叉搜 索树的深度的函数,即结点越深,则比较次数越多。如果相等,直接返回这个结点。Map是⼀个接⼝类,该类没有继承⾃Collection,该类中存储的是结构的键值对,并且K⼀定是唯一的,不能重复。原创 2025-03-11 21:53:12 · 1402 阅读 · 41 评论 -
Java数据结构第二十一期:解构排序算法的艺术与科学(三)
我们先定义三个指针,先让三个指针同时指向三个数组的第一个下标,比较nums[s1]与nums[s2]的值。我们对数组里的元素进行分组,每一个单独的元素都是有序的;由于合并需要3个参数,根据上一种做法的分析,left=i,mid=left+gap-1,right=mid+gap。类似于快速排序,利用数组下标的中间值mid进行分解,当left=right时,说明左树已经分解完毕,然后再去分解右树,然后再进行排序与合并。这样临时数组中储存的就是有序数据,但原数组还不是有序的,我们将临时数组拷贝到原始数组中。原创 2025-03-09 20:58:13 · 6108 阅读 · 27 评论 -
Java数据结构第二十期:解构排序算法的艺术与科学(二)
这种选择排序的思路是从首尾找,起始两个值接收下标都为0,利用i去遍历数组,找出最大值与最小值下标,再让left下标的值与MinIndex下标的值交换,right下标的值与MaxIndex下标的值交换。无论是递归左边还是右边,与上面的过程都是一样的。与上面的方法类似,我们依然是以6为基准值,把6存进tmp中,right向左移动,遇到比6小的数,把6之前的位置填上;但我们一运行,就会发现,排序出现了问题,这是因为,如果最大值或最小值本身就在首尾,那么一交换,最大值或最小值就会跑掉,,所以我们还需要判断一下。原创 2025-03-09 00:42:52 · 6444 阅读 · 35 评论 -
Java数据结构第十九期:解构排序算法的艺术与科学(一)
插入排序的过程:让i从第二个元素为起始位置,j=i-1,当arr[j]>arr[i],用tmp接收i下标的值,让j下标的元素向前移,然后让j--,如果tmp的值大于j下标的值,就把tmp的插入j的后面;假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的 相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之 前,则称这种排序算法是稳定的;如果gap非常大的时候,那么j回退的次数就越少,几乎可以认为是常数。原创 2025-03-07 23:21:13 · 1586 阅读 · 48 评论 -
Java数据结构第十八期:探索优先级队列的魅力(二)
我们来看一下Integer里面的源码,在Structure里面找到compare(int ,int),因为10>5,进不来上面的循环,就可以走下面的代码,再把0下标给到5元素,从而实现小根堆。除此之外,还有第三种解法,就是利用大根堆。先建立一个大小为k的大根堆,从数组的第k+1个元素开始遍历数组,如果数组元素比堆顶元素小,则交换,遍历结束之后,大根堆里的元素就是最小k个数。offer的源码如下,从下面的逻辑中可以看出,它的向上调整是一个一个实现的,而不是直接去调整一个数组,所以下面的时间复杂度是。原创 2025-03-07 10:56:06 · 1167 阅读 · 10 评论 -
Java数据结构第十七期:探索优先级队列的魅力(一)
队列是⼀种先进先出(FIFO)的数据结构,但有些情况下,操作的数据可能带有优先 级,⼀般出队列时,可能需要优先级⾼的元素先出队列,在某些场景下,比如在手机上玩游戏时,有人打电话,系统就会优先处理打过来的电话。对于元素的删除,我们先删优先级最高的“65”,这个方法非常巧妙:我们先把"65"与最后一个结点下标的元素进行交换,再利用向下调整再变成大根堆(在这个过程中65不参与调整)就是左结点,但有可能这个左结点是不存在的,所以我们需要判断这个下标是否是合法的,并且不能只判断一次,因为c会随着p的值发生变化。原创 2025-03-06 11:01:06 · 5770 阅读 · 35 评论 -
Java数据结构第十六期:走进二叉树的奇妙世界(五)
当遍历到4时,左子树为空,返回结点4并弹出,再去遍历4的右结点,然后返回结点2并弹出,让cur等于结点2的右子树并遍历。代码写到这里就会出现问题,原因是:当遍历到结点4的时候,4的左子树为空,就无法进入while循环。然后把4弹出去,让cur=top,问题又来了,如果结点4左边要是不为空,又得放入栈中,也需要走while循环。如下图,前序遍历肯定是先将根结点放进去,如果是队列,根结点先进先出,然后怎么去遍历右子树呢,就无法打印的顺序了。但这样写,会存在问题:当遍历到结点5的右结点7时,会陷入死循环。原创 2025-03-02 14:21:14 · 917 阅读 · 37 评论 -
Java数据结构第十五期:走进二叉树的奇妙世界(四)
我们以中序遍历的数组的第一个元素ibegin,最后一个元素iend之间找到二叉树的根,因为是前序遍历,先有的左树再有的右树,那么左边的区间就会是(9,x) = (ibegin,iend),iend = iroot-1;再继续往下走,如果root.right为空,正好符合上面2结点的情况:2的左边走完,右边为空,直接return加右括号。通过上图分析:当1的左子树不为空,就用一个(,2的左子树也不为空,也使用一个(,4再往下递归返回null,直接)闭合;当root的左树不为空,右树为空,也加右括号闭合。原创 2025-03-01 19:34:26 · 1321 阅读 · 35 评论 -
Java数据结构第十四期:走进二叉树的奇妙世界(三)
实现的逻辑也非常简单:求出每棵子树的高度,如果左子树的高度与右子树的高度之差小于等于1,则是平衡二叉树。看下面的三棵二叉树,上面的树存储的值相同,结构也相同;一棵树的本身就是它的子树,所以我们要首先判断两棵树是否相同,再去判断subRoot是不是等于root的左子树还是右子树,判断我们可以依照上面讲过的是否是相同的树来判断。要判断二叉树是否是对称的,也就是判断左右子树是否是对称的(如下图所示)。root.left与root.right是否是对称的,再判断下面的子结点是否对称,也就是递归的条件。原创 2025-02-26 00:15:56 · 6363 阅读 · 35 评论 -
Java数据结构第十三期:走进二叉树的奇妙世界(二)
同样的,我们上面已经实现了二叉树结点的遍历,我们也只需要再定义一个计数器,只要root不为空,countNode就递增。每一个节点的遍历顺序都是按照“根——>左子树——>右子树”的顺序来遍历,每遇到一个新的结点都看作是一棵新的树。求二叉树的高度,整棵树的高度等于左子树高度的最大值或者右子树高度的最大值加一,当root为空的时候,高度为0。中序遍历的顺序为“左子树——>根——>右子树”,遇到一个结点,先去遍历左子树,如果该节点的根为空,才能递归回来进行打印。上面的是遍历思路,还有一种子问题思路。原创 2025-02-24 22:15:55 · 6136 阅读 · 31 评论 -
Java数据结构第十二期:走进二叉树的奇妙世界(一)
树是⼀种⾮线性的数据结构,它是由n(n>=0)个有限结点组成⼀个具有层次关系的集合。把它叫做 树是因为它看起来像⼀棵倒挂的树,也就是说它是根朝上,⽽叶朝下的。有⼀个特殊的结点,称为根结点,根结点没有前驱结点除根结点外,其余结点被分成M(M > 0)个互不相交的集合T1、T2、......、Tm,其中每⼀个集合Ti (1 <= i <= m) ⼜是⼀棵与树类似的⼦树。每棵⼦树的根结点有且只有⼀个前驱,可以有0个或多个后继树是递归定义的注意,在树型结构中,子树与子树之间不能有交集,否则就不是树型结构。原创 2025-02-20 14:57:55 · 1912 阅读 · 0 评论 -
数据结构(Java版)第十一期:栈和队列(二)
第二种解决方案是牺牲一个空间,当存储元素的时候,判断下一个位置是否为front,如果是,就不再存储了;第三种解决方案是标记,定义一个isFull方法,初始,先假设isFull是false,每次元素入队时,检查rear和front是否重合,如果重合设置rear==front,isFull方法置为true。模拟出栈,先判断哪个队列为空,另一个队列中前n-1个进入的元素进入到空队列中,最后一个元素再出队列。如下图所示,左边是队列,只能出10,而右边的栈只能出20,所以一个队列无法实现栈。原创 2025-02-19 22:04:21 · 11674 阅读 · 32 评论 -
数据结构(Java版)第十期:栈和队列(一)
对于push方法,普通栈当中,所有数据都要放入,最小栈要对我们的普通栈第一次push进行维护。如果我们抛开这道题,获取栈中的最小元素,我们就可以去遍历这个栈来找出我们的最小元素。对于pop方法,如果弹出的数据不是最小栈的栈顶数据,则只需要弹出普通栈的栈顶数据就行,否则则要弹出最小栈的栈顶数据。Stack继承了Vector,Vector和ArrayList类似,都是动态的顺序表,不同的是 Vector是线程安全的,我们可以直接用数组来实现栈。入栈:栈的插⼊操作叫做进栈/压栈/⼊栈,⼊数据在栈顶。原创 2025-01-16 22:03:36 · 2758 阅读 · 66 评论 -
数据结构(Java版)第九期:LinkedList与链表(四)
从上面的图中可以看到LinkedList实现了众多的接口来帮助我们实现各种各样的功能,这里我们主要看List的接口。我们看一下LinkedList里面的源码。原创 2025-01-15 21:31:47 · 7524 阅读 · 48 评论 -
数据结构(Java版)第八期:LinkedList与链表(三)
题目中要求不能改变原来的数据顺序,也就是如上图所示。我们先定义一个cur引用去遍历这个链表,用每个结点的val值与x进行比较,然后利用尾插的方法把结点插入进两个链表中。我们先定义bs、be、as、ae四个引用来表示两个链表的头尾,在尾插的时候需要注意,利用ae.next = node;ae = node,记录下尾结点,保证ae永远指向最后一个结点,同时be.next=as,连接上两个链表。代码的大体框架已经写好,这时我们需要考虑一下当第一段插入第一个节点时,第一个节点既是头又是尾。原创 2025-01-13 15:45:08 · 9069 阅读 · 65 评论 -
数据结构(Java版)第七期:LinkedList与链表(二)
我们先定义一个傀儡结点newH,如上图所示,起初headA的val值比headB的val值小,那么headA就会指向下一个结点,再把0x23赋给我们的傀儡结点,再与headB的val值进行比较。加入我们输入了5个结点,要求我们返回第6个结点,那我们的fast就需要走5步,直接指向了空指针,我们可以再写一个if语句来返回-1。我们还需要再定义一个ListNode.tmp,当headA走到下一个结点时,tmp走到上一个结点,这样就能保证刚进行比较的两个结点中最小的结点值是新创建链表的最后一个结点。原创 2025-01-10 23:35:08 · 2307 阅读 · 35 评论 -
数据结构(Java版)第六期:LinkedList与链表(一)
与顺序表不同的是,链表的地址在物理上不连续,但在逻辑上是连续的。我们先来实现头插和尾插。但这种写法也有致命的缺点,如果说这个方法有返回值呢,head遍历完我们的链表之后,head引用变为了null,返回的值也会成一个null,如果我们再用ListCode创建一个cur变量,head引用保持不动,把head的引用赋值给cur,再让cur去遍历链表。接下来我们要通过代码来实现链表,我们就可以定义一个MySingleList类,链表当中有很多的节点,基于面向对象的思想,我们可以使用内部类来定义我们的节点。原创 2024-12-18 22:21:08 · 7889 阅读 · 103 评论 -
数据结构(Java版)第五期:ArrayList与顺序表(下)
但如果说,我们删除中间的某一个元素,当index==size时,尾插是可以的,但index>size的时候,就会出现异常。这个for循环结束的条件有两个,i==size或者是arr[i]==val时,但由于我们这个i是for循环里面的局部变量,我们可以把i改成index,并作用再for循环之外。下面我们进行对新增元素的实现,当我们插入一个新元素时,这个新元素之后的所有元素都要后移一个位置。其实呢,对于我们的顺序表和链表这样的结构来说,它们都是“有序的”,如果我们把原有的顺序改变了,就不是原来的结构了。原创 2024-11-24 23:21:13 · 7639 阅读 · 80 评论 -
数据结构(Java版)第四期:ArrayLIst和顺序表(上)
/第一种方式,创建ArrayList对象,构造空的顺序表//第二种方式其中ArrayList里面,也是实现了List的接口。也就是说,我们完全可以通过向上转型,把List引用指向ArrayList的实例。我们来看下面两段代码的,两个都是构造空的顺序表,二者有什么区别呢?第一个是创建了一个盒子,盒子里面为空,而第二个却连盒子都没有。//使用arrayList1复制一份,生成arrayList3//构造的同时,可以去指定初始容量。原创 2024-11-23 22:05:54 · 5896 阅读 · 60 评论 -
数据结构(Java版)第三期:线性表
多个元素,一个挨着一个。线性表的特点是每个元素都有一个前驱和一个后继。如果说一个表中出现分支,某个元素后面有两个后继,那么这个表就不是线性表了。线性表往下细分,分为两种实现方式:1.顺序表,也就是对经过封装的数组;2.链表。二者最本质的区别在于顺序表在内存空间上是连续的,而链表是不连续的,通过其它一些方式把前驱和后继联系起来。比如一本书中的一个故事,在第10页中没有讲完,在末尾就会印上“后续参见20页”。线性表是一个接口。定义一个线性表需要支持哪些功能,这些功能的具体实现,交给线性表的类来完成。原创 2024-11-23 14:35:37 · 792 阅读 · 33 评论 -
数据结构(Java版)第二期:包装类和泛型
描述的是使用泛型,创建泛型实例的时候,传入的参数(类型实参)需要满足什么条件。方法限定符 <类型形参列表> 返回值类型 方法名称{原创 2024-11-22 23:06:41 · 4468 阅读 · 60 评论 -
数据结构(Java版)第一期:时间复杂度和空间复杂度
什么是数据结构呢?相信很多老铁尤其是非计算机专业的老铁还是第一次听说这个词。通俗地说,数据结构就是在内存当中对我们的数据进行一个管理和建立数据见关系,我们熟知的内存条(如下图所示)就是存储数据的介质,我们对数据的管理就是存储在内存条上的。计算机这个学科最重要的是做软件开发,软件可以帮助我们实现各种功能,比如我们微信好友列表里面,表面上就是一堆姓名的数据,透过计算机我们看到的只是01010,而这些数据就存在内存条上。原创 2024-11-21 23:31:43 · 3050 阅读 · 46 评论