IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

标签:数据结构

共 69 篇相关文章

IT 累计浏览 55

一个简单的 A star 寻路算法实现

这篇讲的是一个极简A*寻路算法的实现,作者从实用角度出发,重新设计了一套C语言接口,核心特点是与地图数据结构完全解耦,方便移植到不同场景。 实现上最巧妙的是用单向链表替代了传统A*中复杂的优先队列,同时把所有寻路数据压进一块平坦内存,这样既避免了算法执行中的内存分配,又天然兼容多线程环境。底层数据结构是一个闭散列哈希表,作者用一个自增的version值巧妙实现了O(1)复杂度的表重置,大幅降低重复寻路时的初始化开销。 考虑到实际地图规模,算法内置了安全阀:当哈希表使用率超过一半时自动中止,但会返回已找到的离目标最近的中途点,用户可多次调用拼接完整路径。作者还贴心地提供了可视化函数,能将哈希表内部状态输出为灰度图,方便调试。 虽然代码刚写好还未充分测试,但作者追求的“接口简单、数据结构通用、内存开销固定”的设计目标清晰明确,适合那些需要轻量、易集成寻路功能的项目。

IT 累计浏览 40

CSPJ 教学总结:树状数组

树状数组(Binary Indexed Tree)是一种用于高效处理动态序列单点更新与区间求和问题的数据结构。其核心思想是利用二进制表示和 lowbit 操作,构建一个辅助数组,将前缀和查询与单点更新的时间复杂度均优化至 O(log N)。文章从暴力解法的瓶颈出发,逐步剖析 lowbit 函数的原理与实现、树状数组的结构定义、求和与更新操作的具体步骤,并说明了如何通过前缀和数组将初始化复杂度降至 O(N)。进一步,文章阐述了每个树状数组元素所管辖的区间范围及其在更新与查询过程中的变化规律。此外,还介绍了树状数组与差分数组结合以处理区间更新问题、二维树状数组的扩展,以及利用树状数组求解逆序对数量的应用场景与离散化处理技巧。

IT 累计浏览 45

算法模式:并查集

并查集是一种用于解决动态连通性问题的数据结构,能够高效管理节点间的连接关系并快速判断任意两点是否属于同一连通分量。其核心操作包括`union`(合并两个节点所属的集合)和`connected`(查询两个节点是否连通)。初始化时每个节点自成一组,通过`parent`数组记录节点的父节点,最终形成树状结构。 判断连通性时需向上查找各自根节点并比较是否相同。为提升查询效率,可应用路径压缩技术:在查找根节点过程中,将路径上所有节点直接指向根节点,从而大幅降低后续操作的时间复杂度。文章通过图示和Java代码示例展示了并查集的基本实现,包括查找、合并、连通分量计数等功能,体现了其在处理动态集合合并与连通性查询场景下的实用性。

IT 累计浏览 3,999

用邻接表实现无向图

这篇讲的是作者在游戏管道系统扩展中,如何用邻接表实现一个无向图数据结构。作者从原有的液体管道系统(采用类似树的固定数组存储)出发,面对电线网络等新需求——节点无方向且可多邻接,决定重新设计。核心思路是将节点id与边关系分离,便于模块化复用。具体实现上,每条边用32位紧凑表示(16位端点id对,小id在低位确保唯一性),并设计了一个巧妙的结构:在边数据中加入两个链表指针,分别指向两端点所属的边集合,从而支持高效遍历。 更精巧的是,作者进一步压缩了存储:通过将其中一端点的边集合连续排列,另一端以链表链接,并用“反转端点id”来标志链表结束(通常小id在前),最终每条边只需48位。文章以九宫格网格图为例,完整演示了如何从节点索引开始,逐步追踪并找出顶点5的全部四条邻接边。作者坦言这种无向图实现并非日常工作所需,但经过半天编码,能写出这样紧凑高效的结构让他颇为满意,其压缩方案甚至可能具有一定的原创性。

IT 累计浏览 2,131

阿里面试题:为什么Map桶中个数超过8才转为红黑树

这篇讲的是一个经典的Java面试题:为什么HashMap的桶中链表长度达到8才转为红黑树?作者从一个好友的阿里面试经历切入,直接打开了源码中的注释,发现它只记录了阈值,却未解释原因。 文章的核心在于对源码“Implementation notes”的深入解读。作者指出,红黑树节点占用的空间是普通节点的两倍,因此转换是一种空间与时间的权衡。更关键的是,文章引用了源码中一段关于泊松分布的注释:在随机哈希算法下,桶中节点数量遵循特定的概率分布,链表长度达到8的概率极低(仅约千万分之六)。这从统计学角度证明了阈值8的选取并非随意,而是经过严谨计算的。 此外,文章也驳斥了一种常见但不够严谨的“性能对比”解释,强调了设计背后的科学性。通过剖析源码与概率模型,这篇文章将一个常见面试考点还原成了其严谨的设计思想,适合所有想理解Java集合框架底层优化的开发者。

IT 累计浏览 2,393

一些不常见但是很重要的数据结构

这篇源自Stack Overflow高赞讨论的整理,系统梳理了那些在日常编程中不常被提及、却在特定领域发挥关键作用的数据结构。文章并非泛泛而谈,而是紧扣具体应用:比如Bloom filter如何在BigTable、Cassandra中用于快速存在性检查,Skip list作为Redis有序集合的底层实现原理,以及Rope数据结构如何通过高效的字符串拼接操作,在Java等语言中胜任繁重的文本处理任务。 作者将这些结构与经典方案对比着介绍,突出了各自的核心价值:Splay tree的简洁与良好性能,Suffix tree用于字符串搜索的O(n)构建优势,以及Cuckoo Hashing利用多哈希函数提升空间利用率的巧妙思路。同时,文章也涵盖了并查集、Merkle tree、无锁数据结构等并发与特定场景下的利器,甚至提及了缓存参数无关、左偏红黑树等更前沿的方向。 整篇文章更像一份精心挑选的“数据结构工具箱”清单,它不仅扩充了开发者的知识库,更揭示了在解决特定性能或规模问题时,超越常规选择的可能性。对于想夯实基础、或寻找更优解方案的技术读者,这份清单提供了明确的索引和深入探索的起点。

IT 累计浏览 1,898

美团面试经历,贡献出来一起学习

这篇讲的是一位程序媛分享她应聘美团大数据研发实习生的四轮技术面试经历。文章按时间顺序,详细还原了从简历筛选到最终HR面的完整过程,像一份真实的面试笔记。 面试内容覆盖面非常广。一面由部门主管在会议间隙进行,侧重项目架构与设计模式;二面长达一小时,深入考察了Spring机制、多线程、JVM内存与GC、MySQL优化等核心知识;三面是交叉面试,增加了在线编码环节;最后的HR面则异常“硬核”,面试官对项目细节和科研经历进行了深度追问。 作者在应对面试时有不少值得借鉴的思路。例如,面对不熟悉的问题(如服务器配置)坦诚相告;在解释Spring IOC/AOP时,用项目实例来证明理解;遇到不确定的技术点(如Java异步IO)时,坦然说明并向面试官展示自己的推理过程。文章也记录了面试官“边面试边给反馈”这类有助于候选人调整状态的细节。 文末,作者总结了对此次面试的反思:技术基础(算法、框架原理)需要扎实,面试中要主动引导节奏展示自己的知识体系,而对于高并发、分布式等工程经验,在校生只能通过理论学习先行铺垫。这为准备技术面试的读者提供了切实的参考。

IT 累计浏览 4,435

研发面试最常用的10大算法

算法题是研发面试中躲不过的一道坎。这篇没有泛泛而谈,作者直接从实际面试需求出发,为你梳理了程序员在代码面试中最常遇到的10大算法类型。 文章重点以 **String/Array/Matrix**(字符串/数组/矩阵)这一类为例,点明了面试的“陷阱”——题目表面看很简单,但解决往往需要动态规划、递归等高级算法思维。文中还贴心地附上了Java中操作字符串和数组的常用方法代码片段,非常实用。 除了数组字符串,文章还涵盖了如排序、二叉树、图、动态规划等核心题型,并列举了大量经典例题,例如“Two Sum”、“单词分割”、“最长回文子串”等。对于每个类别,它都点出了核心考察点和需要深入理解的原理。 这更像一份高效的面试算法备战地图,帮你厘清重点,把有限的精力投入到真正需要花功夫去理解的算法原理上,而不是盲目刷题。

IT 累计浏览 2,674

Trie树(字典树) 最热门的前N个搜索关键词

这篇讲的是Trie树,也叫字典树,一种专门用来高效处理字符串的树形数据结构。它的核心思想很巧妙,通过“空间换时间”,利用字符串的公共前缀来共享存储路径,从而最大化地减少不必要的比较,让查询和插入操作的时间复杂度直接与单词长度挂钩,而不是单词数量。 文章里用了一组清晰的图示和例子,一步步展示了Trie树是如何从零构建起来的。比如,当你有 `inn, int, at, age` 这些单词时,像 `inn` 和 `int` 就可以共享 “in” 这个前缀的分支。这种结构让查找操作变得非常直接:只需顺着字符路径走到底,再检查终点节点是否被标记为“存在”即可。 更实用的是,文章没有停留在原理,而是直接给出了两个经典的应用场景。一个是统计海量文本中出现频率最高的词,另一个是在千万级的搜索日志中,用有限内存找出最热门的查询串。在这两个问题里,Trie树都扮演了高效的计数和索引角色,再结合堆进行排序,就能得出最终结果。对于想理解如何将数据结构用于解决实际工程问题的人来说,这篇文章的路径很清晰。

IT 累计浏览 4,360

Cuckoo Filter:设计与实现

这篇讲的是如何设计和实现一种名为 Cuckoo Filter 的高效过滤器。作者从实际业务中海量数据快速查询的需求出发,指出经典的 Bloom Filter 虽然空间利用率高,但存在无法删除元素的硬伤,一旦删除就会导致漏报。 为了解决这个问题,文章引入了布谷鸟哈希(Cuckoo Hashing)的设计思想。每个元素有两个哈希位置,发生冲突时,新元素会“踢走”原有元素,并利用其备用位置重新安置,就像布谷鸟侵占别的鸟巢一样。通过使用包含多个槽位的桶结构,可以大幅缓冲碰撞几率,实现高达 80% 以上的空间占用率(论文数据超过 90%),同时支持可靠的插入、查询和删除操作。 作者随后展示了自己用不到 500 行 C 代码实现的完整案例。核心思路是在内存中维护一个轻量级的哈希表,仅存储元素的部分摘要(tag)来快速过滤,将完整数据存放在后端存储(如 Flash)。这样查询时能最大程度避免不必要的磁盘读取。代码清晰地定义了哈希表、槽位结构,并实现了查询、插入等关键操作,验证了该方案在正确性和效率上的可行性。

IT 累计浏览 2,780

[Java基础教程]第十章-Java容器

这篇讲的是如何用“小明打酱油”这个生活化例子,来拆解Java核心容器(List、Set、Map)的用法与区别。作者从重构打酱油流程出发,先让商店用`ArrayList`持有酱油列表,并详细演示了增、删、改、查的基本操作。 很快代码暴露了问题:商店用List卖酱油,居然反复给了小明同一瓶!这个错误生动地引出了`List`有重复、有序的特性。于是,文章引入了`Set`(以`HashSet`为例)来解决去重问题,重构代码后小明终于拿到了正确的5瓶酱油。这部分对比了List与Set在数据结构和适用场景上的关键差异。 文章并未止步于此,它进一步扩展场景:当商店要支持多品牌酱油时,简单的集合不够用了。这时,`Map`(以`HashMap`作为实现)登场,通过“品牌名(key)-酱油列表(value)”的映射关系,优雅地解决了分类存储和查找的需求。整个过程自然融入了泛型、接口与实现类、以及遍历方式(普通循环与foreach)等知识点。 作者通过一步步迭代代码、暴露问题并修复,让读者在贴近生活的业务逻辑中,直观掌握了Java常用容器的核心特性和典型应用场景。

IT 累计浏览 6,066

如何教会非计算机专业的女友写代码

这篇讲的是一个计算机专业男生如何系统指导金融专业女友转行前端开发并成功就业的完整经历。 作者从自身背景出发,为女友选择了适合入门且“可进可退”的前端方向,并制定了清晰的学习路径:从《Head First》系列和《JavaScript语言精粹》等书籍掌握基础语法,再通过言传身教渗透HTTP协议、网络通信等原理知识。他强调“工欲善其事”,专门为女友购置MacBook Pro以便熟悉Vim、Git等开发工具。 实践环节是关键。作者引导女友在GitHub写博客、开发小作品,并报名参加了筛选制的百度IFE前端技术学院。当基础扎实后,便鼓励她投递简历,通过面试发现不足,最终顺利获得实习Offer。过程中遇到的JS异步、闭包等难点,也被一一攻克。 文章还直面了两个常见偏见:技术是否适合女性,以及互联网行业是否过于繁忙。作者以实例论证,技术岗位对女生同样有吸引力且并不枯燥,互联网公司也存在灵活的工作选择。最后,他用自己的支持与担当,为这段转行之路画上了有温度的句号。

IT 累计浏览 3,593

缓存算法–LRU

这篇讲的是两种经典的缓存淘汰算法:LRU和它的改进版LRU-K。文章开门见山,先解析了LRU(最近最少使用)的核心思想——它用一个巧妙的链表来实现,新数据插入头部,每次访问都把数据提到最前,满了就淘汰尾部那个“最久没碰”的。这种策略在热点数据集中时效率很高,实现也简单。 但文章也指出了LRU的软肋:一旦出现偶发的批量扫描,会挤掉很多热门数据,造成严重的“缓存污染”。为了解决这个问题,文章引入了LRU-K。这里的“K”代表一个访问次数阈值,比如我们常说的LRU-2。它不再因为一次访问就把数据加入缓存,而是让数据在历史队列中先“排队”,只有被访问了K次,证明它确实是热点,才获准进入缓存队列。 这样一来,LRU-K的命中率通常比LRU更高,能有效抵抗缓存污染。但天下没有免费的午餐,它的实现需要维护额外的访问历史队列并进行排序,算法复杂度、内存消耗和CPU开销都比LRU要高。文章最后也点明了选择的关键:LRU胜在简单高效,适合大多数常规场景;而当你面对严重的访问模式波动时,LRU-K(尤其是LRU-2)提供了一个更稳健的选择。

IT 累计浏览 4,635

校园招聘的简单总结

这篇文章是一位技术面试官首次参与校园招聘后的心得分享。作者从一线视角出发,详细描述了从线上笔试到三轮面试的完整流程,并分享了在筛选测试开发与Ruby开发工程师候选人时的观察。 作者发现,比较聪明且做了充分准备的同学更受欢迎。这些准备不仅体现在扎实的技术知识上,还包括对公司的了解、清晰的职业规划以及强烈的入职意愿。文章中特别提到一个细节:一位同学在二面时带来了针对公司产品的测试报告,这给面试官留下了深刻印象。 文中也流露出一些个人感慨。作者对比自己多年前的求职经历,感叹如今对技术能力的要求确实更高了。同时,他也认为在实力相当时,校招能否成功有时也看缘分。最后,文章附带了两道面试题(计算阶乘末尾零的个数、啤酒瓶换购问题)的Python实现代码,为文章增添了一些技术趣味。

IT 累计浏览 3,093

我为什么要使用哈希

这篇讲的是如何用哈希技巧解决一个经典的算法问题:在二叉树中找出所有结构完全相同的子树。 文章从一道大厂面试题切入。问题要求给定一棵二叉树,找出所有彼此完全相等的子树对。作者分享了自己的通过面试的解法,核心思路正是借助哈希。通过后序遍历整棵树,为每个节点计算一个哈希值——叶子节点用一个固定值(比如 md5("")),非叶子节点则将其左右子树的哈希值拼接后再次哈希。这样,任何子树都能被映射为一个唯一的哈希指纹。 计算出所有子树的哈希后,将它们放入哈希表。哈希值相同的子树,其结构“有可能”完全相同,但需要二次验证以排除哈希冲突。验证过程是递归地同时遍历两棵树,检查所有节点的左右子树存在状态是否一致。文章还提到了一个关键的优化:通过记录子树深度,在验证前就能排除掉大量哈希值相同但深度不同的“伪匹配”,极大地减少了不必要的递归检查。 整个过程清晰地展示了哈希作为一种“指纹”技术,在加速查找与比对操作中的强大作用,将复杂问题的复杂度显著降低。

IT 累计浏览 5,739

Java程序员必知的8大排序算法

这篇讲的是Java程序员几乎绕不开的排序算法集合。排序是编程基础,但很多人可能只记得零散的冒泡和快排,对其他几种知其然不知其所以然。这篇文章就系统性地梳理了直接插入、希尔、简单选择、堆排序等经典算法。 它不像教科书那样堆砌公式,而是像一张清晰的导航图,先用一张图展示8种排序之间的演进与关系,帮助读者建立整体认知。对于每一种算法,都拆解成三部分:先讲清楚核心思想和解决问题的逻辑,比如堆排序如何借助“堆”这种数据结构进行树形选择;然后给出一个直观的排序实例图,让抽象过程可视化;最后附上可直接运行的Java代码,将思想落地。 尤其值得一提的是,文章在讲解复杂算法(如堆排序)时,通过分解“建堆”和“交换”两个关键步骤的可视化过程,让算法的巧妙之处一目了然。这种从原理、图示到实现的递进式讲解,能帮助开发者不仅学会怎么用,更理解算法背后的设计考量,从而在面对不同数据规模或特征时,能更从容地做出选择。

IT 累计浏览 1,751

在白板上写代码是有难度的

这篇讲的是技术面试中那个让不少人头疼的环节:白板编程。作者从自己作为微软团队面试官的经验出发,给出了一个核心观点——面试官真正在考察的,并不是你能否当场写出语法完美无误的代码。 他理解白板没有智能感知和语法高亮,因此不介意你出现参数顺序错误这类“小瑕疵”。真正看重的是你的问题解决过程:是急于动手,还是先理清思路?是否主动识别并澄清了需求中的模糊点?会优先攻克难点还是先处理简单的部分? 文章以几个经典面试题(如实现栈、打乱数组)为例,点明了关键:很多问题本身就暗藏陷阱,比如字符串处理需要考虑不同编码,数组随机化要区分安全场景与测试场景。忽略这些“真实世界”的考量,代码设计就无从谈起。 作者鼓励应聘者,在编写代码时就要像开发者一样思考:如何测试?如何处理异常输入?代码是否健壮、可维护?他认为,展现出这种工程思维,远比纠结于一时的语法记忆更能证明你的潜力。最后他也坦言,技术面试本就艰难,聪明如他也曾被拒,这本身就是一个值得准备的过程。

IT 累计浏览 2,229

流式布局的原理和代码实现

这篇文章深入解析了流式布局的核心原理与代码实现,适合GUI开发者和前端工程师阅读。作者从最简单的布局模型出发,即控件靠左、靠右或堆叠排列,提出使用两个栈(Stack)数据结构——一个管理靠左控件的位置,另一个管理靠右控件——来高效实现流式布局。伪代码清晰展示了布局管理器的工作流程:当放置新控件时,先检查当前空间是否足够;若不够,则根据浮动方向从对应栈中弹出更高位置的控件来释放空间,确保布局不重叠。 文章重点讨论了两个实现关键:一是控件变化时的级联重布局,从子节点一直传递到根节点,这虽然简单但性能开销

IT 累计浏览 3,804

Redis编程小技巧拾遗

这篇讲的是作者在阅读Redis源码时,特意“拾遗”的几个精妙的C语言编程技巧。作者从Redis简洁的1.0版本入手,并未重复大众熟知的源码剖析,而是聚焦于那些能让代码更健壮、更高效的小细节。 最典型的是“空数组”技巧:在`sdshdr`和`zskiplistNode`结构体的末尾定义一个空数组成员(如`char buf[]`和`level[]`)。这允许在动态内存分配时,根据实际需要的数据长度(如字符串长度、跳表层数)一次性申请合适大小的内存,实现了结构体内可变长数据的紧凑存储。 另一个常见但重要的技巧是使用 `do { } while(0)` 来包裹宏定义中的多条语句。这不仅能确保宏在if等控制流中像单条语句一样安全执行,文章还展示了将其用于简化流程控制的用法,使代码逻辑更清晰。 此外,文章还介绍了Redis中定制化的断言宏`redisAssert`和分级日志系统`redisLog`,前者在条件失败时能输出详尽的上下文信息,后者则允许根据日志级别进行过滤。这些实现虽小,却体现了生产级项目对可调试性和可观测性的重视。 这些从顶级项目中提炼出的技巧,对任何C/C++开发者都有直接的借鉴意义。

IT 累计浏览 21,493

红黑树并没有我们想象的那么难(上)

这篇讲的是红黑树,作者从一个初学者的常见困惑出发:红黑树情况太多,似乎很难。文章给出的核心解法是“合并”——通过归结和简化情况来降低理解门槛。 作者首先回顾了红黑树必须满足的五个性质,然后直接切入数据结构定义和基础的二叉搜索树操作。全文的重点放在对插入与删除算法的拆解上。对于插入,文章将其归结为三种核心情况,通过逐步调整颜色和旋转来维持性质。对于删除,分析则更为细致,分多种情况(例如“兄弟节点颜色”或“侄节点颜色”不同)讨论了重新着色和旋转的策略,并配以直观的印象图和伪代码。 整篇文章像一份详尽的算法推演笔记,通过枚举具体场景并展示调整步骤,试图将复杂的平衡操作变得有迹可循。对于想从原理层面弄懂红黑树实现细节的读者,这种直面各种案例的讲解方式可能比单纯记忆规则更有帮助。