堆排序:堆排序如何实现?时间复杂度详解

堆排序是利用“堆”(特殊完全二叉树)实现的排序算法,常用大顶堆(父节点≥子节点)。核心思想是“先建堆,再排序”:先将数组转为大顶堆(堆顶为最大值),再反复交换堆顶与末尾元素,调整剩余元素为堆,完成排序。 堆的基本概念:完全二叉树结构,数组中索引i的左子节点2i+1、右子节点2i+2、父节点(i-1)//2。大顶堆父≥子,小顶堆父≤子。 实现分两步:1.构建大顶堆:从最后非叶子节点开始,通过“堆化”(比较父与子节点,交换最大值并递归调整子树)确保大顶堆性质;2.排序:交换堆顶与未排序末尾元素,缩小堆规模后重复堆化,直至完成。 时间复杂度:构建堆O(n),排序过程O(n log n),总O(n log n),空间复杂度O(1)(原地排序)。特点是不稳定,适合大规模数据排序。

阅读全文
邻接表:图的高效存储方式,比邻接矩阵好在哪?

这篇文章介绍了图的基本概念及两种核心存储方式:邻接矩阵与邻接表。图由顶点(如社交网络用户)和边(如好友关系)构成。 邻接矩阵是二维数组,用0/1表示顶点间是否有边,空间需n²(n为顶点数),查找边时间O(1),但稀疏图(边少)时空间浪费大。邻接表则为每个顶点维护邻居列表(如用户好友列表),空间n+e(e为边数),仅存实际边,查找需遍历邻居表(时间O(degree(i)),i为顶点),遍历邻居更高效。 对比显示,邻接表在稀疏图(多数实际场景)中空间和时间效率均优于邻接矩阵,是处理图问题(如最短路径)的主流存储方式,更省空间且遍历更快。

阅读全文
动态规划的状态转移:从问题到状态转移方程的过程

动态规划通过拆分问题、存储中间结果避免重复计算,适用于有重叠子问题和最优子结构的场景。其核心是“状态转移”,即不同阶段状态间的推导关系。以爬楼梯为例:定义`dp[i]`为爬到第`i`级台阶的方法数,转移方程为`dp[i] = dp[i-1] + dp[i-2]`,初始条件`dp[0]=1`(0级台阶1种方法)、`dp[1]=1`(1级台阶1种方法)。另一拓展例子(零钱兑换)中,`dp[i]`表示凑`i`元的最少硬币数,转移方程为`dp[i] = min(dp[i-coin]+1)`(`coin`为可用面额),初始条件`dp[0]=0`,其余为无穷大。初学者需掌握“定义状态→找转移关系→写方程”,通过练习熟悉状态转移思维。动态规划本质是“空间换时间”,状态转移方程是连接中间结果的桥梁。

阅读全文
并查集的路径压缩:并查集优化,让查找更快

并查集用于解决集合合并与元素归属问题(如连通性判断)。核心操作是`find`(查找根节点)和`union`(合并集合),基础版通过`parent`数组记录父节点实现,但长链结构会导致`find`效率极低。为优化,引入**路径压缩**:在`find`过程中,将路径上所有节点直接指向根节点,使树结构扁平化,查找效率接近O(1)。路径压缩通过递归或迭代实现,将长链转化为“一步到位”的短路径。结合按秩合并等优化,可高效处理大规模集合问题,成为解决连通性、归属判断的核心工具。

阅读全文
红黑树:平衡二叉树的一种,简单理解它的规则

红黑树是自平衡二叉搜索树,通过颜色标记和5条规则保证平衡,使插入、删除、查找复杂度稳定在O(log n)。核心规则包括:节点非红即黑;根为黑色;空叶子(NIL)为黑色;红节点子节点必为黑色(避免连续红节点);任一节点到后代NIL路径的黑节点数(黑高)一致。规则4阻止连续红节点,规则5确保黑高相等,共同限制树高在O(log n)。插入新节点为红色,若父红需调整(变色或旋转)。广泛应用于Java TreeMap、Redis有序集合等,以平衡结构实现高效有序操作。

阅读全文
最小生成树:贪心算法的经典应用,Prim算法入门

本文介绍了生成树、最小生成树(MST)及Prim算法。生成树是连通无向图的无环子图,含所有顶点;MST是边权和最小的生成树,适合贪心算法(每步选局部最优得全局最优)。 Prim算法核心步骤:选起点,反复从已选和未选顶点间的边中选最小权边,将对应顶点加入已选集,直至所有顶点入集。关键是用邻接矩阵或邻接表记录图结构,算法伪代码中,`key`数组记录最小边权,`parent`记录父节点,时间复杂度邻接矩阵为O(n²),优化后O(m log n)。 Prim算法基于贪心选择,安全边性质保证总权最小,应用于网络布线、电路设计等需最小成本连接所有节点的场景。总结:MST是贪心算法经典应用,Prim通过逐步扩展选最小边高效构建最优生成树。

阅读全文
后缀数组:后缀数组是什么?解决字符串问题的利器

后缀数组是对字符串所有后缀按字典序排序后,存储排序后缀起始位置的数组。后缀指从字符串每个位置开始到末尾的子串(如“banana”的后缀有“banana”“anana”等)。字典序比较规则为:首字符不同则按字符大小比较,相同则依次比较后续字符,若一后缀是另一前缀则较短的更小。 以“abrac”为例,其后缀排序后起始位置数组为[0,3,4,1,2](如位置0的“abrac”<位置3的“ac”,再依次排列)。 后缀数组的核心价值在于高效解决字符串问题:通过排序后相邻后缀的紧密关系(公共前缀长),可快速处理最长重复子串、子串存在性等。例如,用LCP数组找最长重复子串,或通过二分查找验证子串是否存在。 总结:后缀数组通过排序后缀起始位置,为字符串问题提供高效解决方案,是字符串处理的实用工具。

阅读全文
前缀树:前缀树如何存储和查找单词?实例讲解

前缀树(字典树)是处理字符串前缀问题的数据结构,核心是利用公共前缀节省空间、提升查找效率。其节点含字符、最多26个子节点(假设小写字母)及isEnd标记(是否为单词结尾)。 插入时从根节点开始,逐个字符处理,无对应子节点则新建,处理完字符后标记结尾节点isEnd为true。查找时同样从根开始逐个字符匹配,最后检查isEnd确认是否存在。 实例中,“app”与“apple”共享前缀“app”,“banana”与“bat”共享“ba”,体现空间优势。其优势在于空间更省(共享前缀)、查找快(时间复杂度O(n),n为单词长度),且支持前缀查询。

阅读全文
栈与队列的应用:括号匹配问题,用栈解决超简单

### 括号匹配问题:栈的"超简单"应用 文章介绍了利用栈(后进先出特性)解决括号匹配问题的方法。括号匹配需判断由`()`、`[]`、`{}`组成的字符串是否合法,即左括号与右括号一一对应且顺序正确。 栈的"后进先出"特性适合此类问题:左括号入栈暂存,右括号需匹配最近入栈的左括号。具体步骤为:初始化栈,遍历字符串时,左括号直接压栈;右括号则检查栈顶元素是否匹配(通过字典映射右括号与对应左括号),匹配则弹出栈顶,否则非法;遍历结束后栈为空则合法,否则非法。 关键细节包括:区分括号类型(用字典映射)、右括号空栈时直接非法、最终栈为空是合法的必要条件。通过左压右查、匹配弹栈的逻辑,可高效判断任意括号串合法性。

阅读全文
快速排序:快速排序如何选择基准?分区过程图解

快速排序基于分治法,核心是选基准(pivot)并分区。基准选择影响效率:最左/右元素易导致有序数组退化(O(n²));中间元素平衡稍差;三数取中法(首、尾、中间中值)最推荐,可避免极端情况。分区通过左右指针移动实现,使基准归位,左子数组均小于基准,右子数组均大于基准,递归排序子数组。平均时间复杂度O(n log n),是工程常用高效排序算法。

阅读全文
归并排序:归并排序的原理,分治思想的经典应用

归并排序基于“分而治之”思想,核心是分解、递归、合并。先将数组递归拆分为长度为1的子数组,再通过双指针合并相邻有序子数组(比较元素大小,临时数组存储结果)。完整流程:分解至最小子数组,逐层合并成有序数组。 时间复杂度稳定为O(n log n)(递归深度log n,每层合并需遍历所有元素),空间复杂度O(n)(需临时数组存储合并结果)。作为稳定排序,相等元素相对顺序不变,适合大数据量或需稳定排序的场景。其“分解-合并”逻辑直观体现分治思想,是理解递归与复杂问题简化的经典案例。

阅读全文
二叉搜索树:如何用二叉搜索树实现高效查找?

二叉搜索树(BST)是一种高效的数据结构,用于解决日常数据查找中“快速定位目标”的问题。它是特殊二叉树,每个节点满足:左子树所有节点值小于当前节点值,右子树所有节点值大于当前节点值。 其高效性源于“左小右大”规则:查找时从根节点开始,每次比较目标值与当前节点值,若小于则递归左子树,大于则递归右子树,可排除一半节点,效率稳定在O(log n),优于无序数组(O(n))和有序数组二分查找(插入效率低)。 查找过程核心是“比较-缩小范围”:从根节点出发,等于则找到,小于去左子树,大于去右子树,递归执行。递归或迭代均可实现,如递归法从根开始逐层比较,迭代法则用循环缩小范围。 需注意,若BST不平衡(如退化为链表),效率会退化为O(n);平衡树(如红黑树、AVL树)可保持稳定O(log n)。BST通过“导航式”缩小范围,实现高效有序查找。

阅读全文
链表反转:单链表反转的方法,递归和迭代实现

单链表由含数据域和指针域(next)的节点组成,头节点起始,尾节点next为None。反转链表用于逆序输出、回文判断等场景。 迭代法:遍历链表,维护prev(初None)、current(头节点)、next指针。步骤:保存current.next→next,反转current.next→prev,移动prev和current,current为None时返回prev(新头)。时间O(n),空间O(1),直观。 递归法:递归反转子链表(终止于空或单节点),递归后设head.next.next=head,head.next=None,返回新头。时间O(n),空间O(n),代码简洁。 对比:迭代无栈风险,递归依赖栈。关键:迭代注意指针顺序,递归明确终止条件。

阅读全文
哈希冲突:哈希表为什么会冲突?如何解决?

哈希表通过哈希函数将键映射到数组位置,但若不同键映射到同一位置则产生哈希冲突,核心原因是键数量远超数组容量或哈希函数不均。解决冲突的核心是让冲突键“各占位置”,常见方法有: 1. **链地址法(拉链法)**:最常用,每个数组位置为链表,冲突键依次挂在对应链表后,如键5、1、9冲突时,链表为5→1→9。查找时遍历链表,实现简单且空间利用率高。 2. **开放定址法**:冲突时从后续位置找空位,包括线性探测(步长1)、二次探测(步长平方)、双重哈希(多函数映射),但易聚集或实现复杂。 3. **公共溢出区**:主数组存无冲突键,冲突键放入溢出区,查找需主区+溢出区遍历,空间分配难。 解决冲突需依场景选择,链地址法因高效通用被广泛采用,理解冲突及解决方法可优化哈希表性能。

阅读全文
树的BFS:广度优先搜索,层次遍历的实现步骤

BFS是树的经典遍历方法,按“广度优先”(层次)访问节点,核心依赖队列(FIFO)实现。其步骤为:初始化队列(根节点入队),循环取出队首节点访问,将左、右子节点(或子节点自然顺序)入队,直至队空。 BFS适用于树的层次关系问题,如计算树高、判断完全二叉树、求根到叶最短路径等。以二叉树 `1(2(4,5),3)` 为例,层次遍历顺序为1→2→3→4→5。 关键点:队列确保层次顺序,子节点入队顺序(左→右),时间复杂度O(n)(n为节点数),空间复杂度O(n)(最坏队列存n/2节点)。掌握BFS可高效解决层次问题,为复杂算法奠基。

阅读全文
树的DFS:深度优先搜索,从根到叶的遍历方法

树由节点和边组成,每个节点(除根外)有一个父节点,可有多子节点。DFS(深度优先搜索)是“深入一条路到黑再回溯”的遍历方法。树的DFS遍历含前序(根→左→右)、中序、后序,前序最直接体现根到叶路径。 递归实现前序遍历:访问当前节点→递归左子树→递归右子树。以示例树(根1,左2、右3;2左4、右5)为例,顺序为1→2→4→5→3。非递归用栈:初始化栈入根,循环弹出栈顶访问,先右后左入栈子节点。 根到叶DFS遍历用于路径求和、输出路径等问题。递归实现直观,非递归用栈模拟适合大数据。掌握前序遍历是树结构核心技能。

阅读全文
哈希函数:哈希函数如何生成哈希值?初学者必知

哈希函数是将任意长度输入转为固定长度哈希值的“翻译器”,哈希值即数据的“身份证号”。其核心特点:固定长度(如MD5为32位十六进制字符)、单向不可逆(无法由哈希值反推原数据)、近似唯一(碰撞概率极低)、雪崩效应(输入微小变化致哈希值巨变)。生成过程分三步:输入预处理为二进制,分段数学运算,合并结果。与加密函数不同,哈希单向无需密钥,加密可逆需密钥。应用广泛:文件校验(比对哈希值防篡改)、密码存储(存哈希值保安全)、数据索引及分布式系统数据分布。哈希如数据指纹,关键特性使其在安全与校验中不可或缺。

阅读全文
插入排序:插入排序如何工作?与冒泡排序对比
2025-12-20 81 阅读 数据结构

文章介绍了排序的基础重要性,并聚焦两种简单排序算法:插入排序和冒泡排序。 插入排序核心思想是逐步构建有序序列,从第二个元素开始,将每个元素插入到已排序部分的正确位置(类似整理扑克牌)。其平均时间复杂度O(n²),最好情况(数组有序时)为O(n),空间复杂度O(1),稳定,适用于小规模或接近有序数据。 冒泡排序则通过相邻元素比较,将大元素逐步“冒”到末尾(如气泡上浮),每轮确定一个最大元素的位置。平均时间复杂度同样O(n²),空间复杂度O(1),稳定,但移动元素更多,实际应用较少。 两者均为O(n²)复杂度,插入排序更高效,尤其数据接近有序时表现更好。理解它们是学习复杂排序算法的基础。

阅读全文
二分查找:二分查找的适用场景,零基础也能学会

这篇文章介绍了二分查找算法,其核心是在有序数组中通过比较中间元素,逐步缩小查找范围,快速定位目标。它适用于有序、大数据量、静态(少修改)且需快速查找的场景,如字典或配置文件。 查找过程通过左右指针`left`和`right`确定中间值`mid`,根据目标与中间值的大小调整指针:若中间值等于目标则找到;若目标更大,右移`left`;若更小,左移`right`,直至找到或范围无效。 Python迭代实现的核心代码通过`left <= right`循环,计算`mid = (left + right)//2`,边界处理确保数组为空或目标不存在时返回-1。时间复杂度为O(log n)(每次范围减半),空间复杂度为O(1)(仅用常数变量)。 关键细节包括处理重复元素需扩展遍历,单元素数组直接判断,找不到目标返回-1。二分查找的“减治”思想高效解决有序大数据的快速查找问题,是算法基础中的重要工具。

阅读全文
邻接矩阵:图的另一种表示方法,优缺点对比

邻接矩阵是图的一种基础表示方式,本质为n×n二维数组,行与列对应图的顶点,元素值表示顶点间边的存在性或权重。无向图中,元素1表示有边,0表示无边;有权图则直接存储权重值。 其优点:一是判断边存在仅需O(1)时间,计算顶点度高效(无向图行和,有向图行/列分别对应出/入度);二是适合稠密图(边数接近n²),空间利用率高,且实现简单,便于初学者理解。 缺点:空间复杂度为O(n²),稀疏图时浪费大量空间;遍历邻接顶点需O(n)时间,效率低于邻接表;动态调整边数灵活性不足。 总结:邻接矩阵以空间换时间,适合稠密图、需频繁查询边或计算度的场景,不适合稀疏图或需频繁遍历邻接顶点的场景,是理解图结构的基础工具。

阅读全文
并查集:并查集是什么?解决“朋友关系”问题的方法

并查集是管理元素分组的高效数据结构,核心解决“合并组”(Union)和“查询是否同组”(Find)问题,适用于快速判断元素是否属于同一集合的场景。其底层以parent数组维护父节点关系,每组视为一棵树,根节点为组代表,初始各元素自成一组。 关键优化是**路径压缩**(查询时压缩路径,使节点直接指向根)和**按秩合并**(小树依附大树,避免树退化为链表),确保操作接近常数时间复杂度。核心方法`find`(查找根节点并压缩路径)和`union`(合并两组,小树根指向大树根)实现高效分组。 应用广泛,如网络连接判断、家族关系查询、最小生成树(Kruskal算法)及等价类问题等,是处理分组场景的简洁强大工具。

阅读全文
前缀和:前缀和数组如何快速计算区间和?

前缀和数组是一种用于快速计算区间和的辅助数组。定义为:原数组A的前缀和数组S,其中S[0]=0,S[k](k≥1)是A[1]到A[k]的和,即S[k] = S[k-1] + A[k]。例如原数组A=[1,2,3,4,5],其前缀和数组S=[0,1,3,6,10,15]。 计算区间和的核心公式是:原数组从第i个到第j个元素的和 = S[j] - S[i-1]。例如计算A[2]到A[4]的和,用S[4]-S[1]=10-1=9,结果正确。 优势在于:预处理S数组需O(n)时间,每次区间和查询仅需O(1)时间,总复杂度O(n+q)(q为查询次数),远快于直接计算的O(qn)。需注意索引对齐(如原数组从0开始时公式调整)、区间合法性及空间换时间的特点。 前缀和数组通过“提前累积”实现

阅读全文
动态规划:动态规划入门,斐波那契数列的高效解法

斐波那契数列定义为f(0)=0,f(1)=1,n>1时f(n)=f(n-1)+f(n-2)。直接递归计算时,因重复计算过多,时间复杂度达O(2^n),效率极低。 动态规划通过空间换时间优化:一是记忆化递归,用备忘录数组存储已计算结果,每个子问题仅算一次,时间与空间复杂度均为O(n);二是递推法,仅用两个变量迭代计算,时间O(n)、空间O(1),为最优解。 动态规划核心特性是重叠子问题(子问题重复出现)与最优子结构(当前解依赖子问题解)。其本质是通过存储子问题结果避免重复计算,斐波那契是经典入门案例,掌握后可推广至爬楼梯等同类问题。

阅读全文
平衡二叉树:为什么需要平衡?旋转操作简单讲

二叉搜索树(BST)因极端插入可能退化为链表,操作复杂度升至O(n)。平衡二叉树通过**平衡因子**(节点左右子树高度差)控制平衡,要求平衡因子为-1、0或1。当不平衡时,通过**旋转操作**(LL右旋、RR左旋、LR先左旋后右旋、RL先右旋后左旋)调整结构,使树高保持log n级别,确保查找、插入、删除等操作复杂度稳定在O(log n)。旋转本质是调整支点,恢复树的平衡结构。

阅读全文
图:图的基本概念,邻接表表示法初学者指南

图由顶点(点)和边(连接关系)组成,顶点是基本单元,边可单向(有向图)或双向(无向图),有权图边带权重(如距离),无权图仅存连接关系。邻接表是高效表示法,解决邻接矩阵在稀疏图(边远少于顶点平方)中空间浪费问题,核心是每个顶点对应存储直接相连顶点的列表。无向图邻接表如顶点0连接1、2、3,邻接表为[1,2,3];有权图可存“邻接点+权重”元组。邻接表空间复杂度O(V+E)(V顶点数,E边数),适合稀疏图,遍历邻接点方便,但判断两点是否有边需遍历邻接表。掌握邻接表为图遍历、最短路径等算法奠定基础。

阅读全文
堆:堆的结构与应用,最小堆和最大堆入门

堆是一种特殊的完全二叉树,核心特点是父节点与子节点满足大小关系(最小堆父≤子,最大堆父≥子),能高效获取极值(堆顶为最小或最大元素),类似优先队列。其底层为完全二叉树,每一层尽量填满,最后一层从左到右排列。数组存储时,左子节点索引=2i+1,右子节点=2i+2,父节点=(i-1)//2。基本操作包括插入(末尾添加后上浮)和删除(堆顶删除后尾元素顶替,再下沉),时间复杂度均为O(log n)。堆广泛用于优先队列(任务调度)、找第k大元素、哈夫曼编码等场景,是高效处理极值问题的关键结构。

阅读全文
贪心算法:贪心算法是什么?找零钱问题实例讲解

贪心算法是每步选择当前最优(局部最优)以期望全局最优的算法,核心是满足“贪心选择性质”——每步局部最优能导致全局最优。经典应用如找零钱:以25、10、5、1分硬币为例,找67分时,按从大到小逐步取25×2(50分)、10×1(10分)、5×1(5分)、1×2(2分),共6枚,验证为最优。其局限性在于,若问题不满足贪心选择性质(如硬币面额[1,3,4]找6分),贪心可能失效(贪心取4+1+1=3枚,最优为3+3=2枚)。适用场景包括硬币面额合理(如25、10、5、1)、活动安排(选最早结束活动)等。总之,贪心算法简单直观高效,但仅适用于满足贪心选择性质的问题,不保证所有问题全局最优。

阅读全文
分治算法:分治思想如何解决问题?归并排序原理

分治算法核心是“分而治之”,通过分解(拆分为小问题)、解决(递归求解子问题)、合并(整合结果)三步处理复杂问题,适合递归结构场景。以数组总和计算为例,分解数组,递归求子数组和,合并得总和。 归并排序是典型应用:先分解数组至单个元素(本身有序),再用双指针法合并有序子数组。其时间复杂度O(n log n),空间复杂度O(n)(需临时数组)。 分治通过递归简化问题,归并排序高效体现其优势,是理解递归、排序等算法的基础。

阅读全文
递归:递归是什么?用斐波那契数列举例,初学者也能懂

这篇文章用生活化的例子和经典案例讲解了递归的概念。递归是将大问题分解为更小的同类问题,直到问题小到可直接解决(终止条件),再通过小问题结果反推大问题结果的方法,核心是“分解”与“终止”。 以斐波那契数列为例,其递归定义为:F(0)=0,F(1)=1,n>1时F(n)=F(n-1)+F(n-2)。计算F(5)时,需先算F(4)和F(3),依此类推,直到分解到F(0)或F(1)(终止条件),再逐层返回结果。递归的关键是必须有明确终止条件(如n=0、1),且每次调用规模递减,否则会无限循环。 Python代码实现简洁:`def fibonacci(n): if n==0: return 0; elif n==1: return 1; else: return fibonacci(n-1)+fibonacci(n-2)`。递归代码优雅但计算大数字(如F(100))时效率低于迭代法,体现了“以退为

阅读全文
查找算法:顺序查找和二分查找的区别,哪个更快?

文章介绍了两种基础查找算法:顺序查找和二分查找,用于解决从数据中定位特定元素的问题。 顺序查找(线性查找)原理是逐个比较元素,无需数据有序,时间复杂度O(n)(n为数据量),优点是简单,缺点是效率低,适合小数据量或无序数据。 二分查找(折半查找)要求数据有序,通过分半比较缩小范围,时间复杂度O(log n),效率高(如n=1000时仅需约10次),但需处理边界条件,适合大数据量有序数据。 两者对比:顺序查找无需有序、实现简单但效率低;二分查找需有序且复杂度高但速度快。选择依据为数据规模和有序性:有序大数据用二分,无序小数据用顺序。

阅读全文
排序算法:冒泡排序入门,步骤详解+代码示例

冒泡排序是计算机科学中最简单的排序算法之一,核心思想是通过重复比较相邻元素并交换位置,使大元素逐步“冒泡”到数组末尾。其基本步骤为:外层循环控制n-1轮比较(每轮确定一个大元素位置),内层循环从第一个元素开始,依次比较相邻元素,若前大后小则交换;优化项为若某轮无交换,说明数组已有序,可提前终止。 时间复杂度上,最坏情况(完全逆序)为O(n²),最好情况(已排序)为O(n),空间复杂度为O(1)(仅需常数额外空间)。该算法实现简单、易于理解,适合小规模数据排序,是排序算法的入门基础。

阅读全文
哈希表:哈希表如何存储数据?冲突解决方法图解

哈希表是通过哈希函数将键映射到数组桶位置的键值对存储结构,实现O(1)级别的高效查找、插入与删除。其底层为数组,键经哈希函数(如“键%数组长度”)转换为数组索引(桶位置),直接存储对应的值。 当不同键哈希值相同时会发生冲突(如学号12和22在数组长度10时均%10得2)。经典解决方法有二:链地址法(每个桶存链表,冲突元素挂在链表尾部),实现简单但需额外空间;开放定址法(线性探测下一个空桶,如冲突位置h→h+1→h+2...),纯数组操作但可能形成聚集。 哈希表核心在于哈希函数、冲突处理逻辑,是数据结构学习的基础。

阅读全文
二叉树:二叉树的三种遍历方式,递归实现超简单

这篇文章介绍了二叉树的三种经典遍历方式(前序、中序、后序),基于递归实现,核心是明确根节点的访问位置。 二叉树每个节点最多有左右子树,遍历即按特定顺序访问节点。递归是关键,类似“套娃”,函数自调用且范围缩小,直到遇到空节点终止。 三种遍历顺序区别:前序(根→左→右)、中序(左→根→右)、后序(左→右→根)。以示例树(根1,左2,右3;2的左4,右5)为例: - 前序遍历结果:1 2 4 5 3; - 中序遍历结果:4 2 5 1 3; - 后序遍历结果:4 5 2 3 1。 递归实现核心:终止条件(空节点返回)+ 按遍历顺序递归左右子树。通过明确根位置和递归逻辑,可清晰理解遍历过程。

阅读全文
树:树结构是什么?用生活例子轻松理解

这篇文章用生活类比讲解数据结构中的“树”。核心是树与生活中的树类似:有根节点(起点)、子节点/父节点(分支与源头)、叶子节点(无后代)及子树(节点与后代),具有非线性、分支型、层级分明的特点。 与线性链表(单一路径)不同,树可多分支(如根节点分多个子节点)。生活中树结构无处不在:家庭关系以长辈为根,公司架构以CEO为根,电脑文件系统以磁盘为根,均体现层级分支。 树的核心优势是高效处理层级化分支问题,如数据库索引、导航路径规划、游戏场景构建等。理解树结构能掌握分支型问题的处理思维,生活中家庭、公司、文件系统都是树的典型应用。

阅读全文
队列:队列的“先进先出”如何实现?简单例子说明

队列是遵循“先进先出”(FIFO)原则的数据结构,仅能在队尾入队、队头出队,核心概念包括队头(最早元素)、队尾(最晚元素),基本操作为入队(Enqueue)和出队(Dequeue)。 以数组实现为例,需front(队头指针)、rear(队尾指针)及固定容量数组。队空条件为front == rear,队满为rear == max_size;入队时rear后移存储元素,出队时front后移取出元素。 实例演示:容量5的队列,初始front=0、rear=0;入队1、2、3后rear=3,队列[1,2,3];出队1(front=1),再入队4(rear=4);入队5后队列满,出队2(front=2),最终队列[3,4,5]。 应用场景包括任务调度、广度优先搜索(BFS)、打印机队列、网络请求等,在数据处理和任务排队中作用关键。

阅读全文
栈:栈的“后进先出”是什么意思?原理图解

这篇文章以“叠盘子”为例,解释了数据结构“栈”的核心概念。栈是只能从一端(栈顶)进行插入和删除操作的线性表,另一端为栈底,其核心特性是“后进先出”(LIFO)——最后放入的元素最先被取出。 栈的基本操作包括:入栈(push,添加元素到栈顶)、出栈(pop,移除并返回栈顶元素)、查看栈顶(top)和判空(empty)。例如,叠盘子时,新盘子放在最上面(入栈),拿取时必须先取最上面的(出栈),符合LIFO。 栈在生活与编程中广泛应用:括号匹配(用栈记录左括号,遇右括号弹出匹配)、函数调用栈(后调用的函数先返回)、浏览器后退功能(依次弹出最近访问的网页)等。理解栈的“LIFO”特性,能帮助解决递归、动态规划等问题,是数据结构的基础工具。

阅读全文
链表:单链表与双链表的区别,初学者一看就会

文章以游戏玩家列表存储为例,说明链表解决数组删除中间元素需移动节点的问题。链表是由节点组成的线性结构,节点含数据域和指针域,非连续内存存储,插入删除仅需修改指针。 单链表最简单,节点仅含next指针,单向遍历(从头至尾),插入删除需先找前驱节点改指针,省内存,适合单向场景(如队列)。 双链表节点多一个prev指针,支持双向遍历,插入删除直接通过prev/next指针操作,无需找前驱,内存稍高,适合双向操作(如浏览器历史、通讯录)。 单双链表对比:单链表结构简单省内存,双链表功能全但稍占内存。根据需求选择:单向用单链表,双向或频繁操作用双链表。

阅读全文
数组:为什么数组是数据结构的基石?零基础必学

这篇文章介绍了数组作为数据结构基础的核心地位。数组是相同类型元素的序列,通过索引(从0开始)实现随机访问,具有简单直观、连续存储和高效索引访问的特点。它是栈、队列、哈希表等复杂结构的基础(如栈用数组实现后进先出,队列用循环数组实现先进先出),也是二维数组(矩阵)的基础。数组支持遍历、查找、排序等基础操作,且随机访问时间复杂度为O(1),远超链表的O(n)。但它存在固定大小(静态数组)和插入删除效率低(需移动元素)的局限。总之,数组是数据结构的“入门钥匙”,掌握它能为后续学习复杂结构和算法奠定基础。

阅读全文
时间复杂度O(n)是什么?数据结构入门必学的效率概念

文章解释了时间复杂度的必要性:因硬件和编译器差异,直接计时不现实,需抽象描述算法效率趋势。核心是线性时间复杂度O(n),表示操作次数与输入规模n(如数组长度)成正比,如遍历数组找目标、打印所有元素等场景,均需n次操作。 大O表示法忽略常数和低阶项,仅关注增长趋势(如O(2n+5)仍为O(n))。对比常见复杂度(O(1)常数、O(n)线性、O(n²)平方、O(log n)对数),O(n)比O(n²)高效但不如O(1)或O(log n)。 理解O(n)是算法基础,可帮助优化代码,避免“暴力解法”导致的超时问题。

阅读全文
哈希表冲突怎么办?简单看懂数据结构的哈希解决方法

哈希表通过哈希函数映射键到数组槽位,不同键映射同一槽位即哈希冲突。解决核心是为冲突元素找新位置,主要方法如下: 1. **链地址法(拉链法)**:每个槽位存链表,冲突元素挂在链表上。例如键1、6、11哈希到同一槽位,其链表为[1,6,11]。优点:实现简单,适合动态数据;缺点:需额外空间存链表,查找最坏O(n)。 2. **开放寻址法**:冲突时找空槽位,分线性探测(i+1循环)和二次探测(i+1²等)。如键6哈希到槽位1冲突,线性探测到2;键11到3。优点:空间利用率高;缺点:线性探测易聚集,二次探测需更大数组。 其他方法:再哈希法(多哈希函数)、公共溢出区(基本表+溢出表),适合冲突少场景。选择依场景:链地址法(如Java HashMap)适合动态大量数据;开放寻址法适合固定数组、冲突少场景。

阅读全文
树的遍历怎么学?前序、中序、后序遍历轻松理解

树是基础数据结构,遍历是访问所有节点的过程。文章重点讲解二叉树的前序、中序、后序遍历,核心区别在于访问根节点的时机。 前序遍历(根→左→右):先访问根,再递归左子树,最后右子树。例:1→2→4→5→3→6→7。 中序遍历(左→根→右):先递归左子树,再访问根,最后右子树。例:4→2→5→1→6→3→7。 后序遍历(左→右→根):先递归左子树,再右子树,最后访问根。例:4→5→2→6→7→3→1。 记忆口诀:前序根在前,中序根在中,后序根在后。应用上,前序用于复制树,中序对二叉搜索树排序,后序用于删除节点。遍历本质是递归思想,掌握顺序和场景即可熟练。

阅读全文
递归怎么理解?用斐波那契数列轻松学递归

递归是“自己调用自己”的解决问题方法,将大问题分解为更小的同类子问题,直至子问题可直接解决,再逐层返回结果(如俄罗斯套娃拆解)。其核心要素是**终止条件**(避免无限循环,如n=0、n=1时返回固定值)和**递归关系**(分解为子问题,如F(n)=F(n-1)+F(n-2))。 以斐波那契数列为例,递归函数`fib(n)`通过终止条件和递归关系实现:`fib(0)=0`、`fib(1)=1`,`fib(n)=fib(n-1)+fib(n-2)`。以`fib(5)`为例,需递归计算`fib(4)`与`fib(3)`,逐层分解至`fib(1)`和`fib(0)`,再反向组合结果,最终得到答案。 递归过程如“剥洋葱”,触底后反弹。优点是逻辑清晰、易实现,但存在重复计算(如`fib(3)`被多次调用),效率较低,可通过记忆化或迭代优化。 递归本质是“大问题化小,小问题

阅读全文
堆是什么?数据结构中堆的基本操作详解

堆是基于完全二叉树的特殊结构,用数组存储,满足大顶堆(父节点值≥子节点)或小顶堆(父节点值≤子节点)性质,能高效获取最值,广泛应用于算法。数组索引映射父子关系:左子节点2i+1,右子节点2i+2,父节点(i-1)//2。大顶堆根节点最大(如[9,5,7,3,6,2,4]),小顶堆根节点最小(如[3,6,5,9,7,2,4])。核心操作:插入(新元素放末尾,上浮调整至父节点满足堆性质)、删除(交换堆顶与末尾元素,下沉调整至堆顶满足性质)、构建堆(从最后非叶子节点开始依次下沉调整)、获取堆顶(直接取根节点)。应用于优先队列、堆排序、Top K问题。堆结构与操作高效,对理解算法至关重要,初学者可从数组模拟入手掌握。

阅读全文
二分查找:比线性查找快多少?数据结构中的查找技巧

文章介绍了计算机中的查找算法,从线性查找和二分查找两方面展开。线性查找(顺序查找)是基础方法,通过从头到尾逐个检查数据,时间复杂度为O(n),适用于数据量小或无序的场景,最坏情况需遍历全部数据。二分查找则需在有序数组中使用,核心是每次排除一半数据,时间复杂度O(log n),数据量大时效率远超线性查找(如n=100万,二分仅需20次,线性需100万次)。两者适用场景不同:二分适用于有序、大数据量且频繁查找的场景;线性适用于无序、小数据量或动态变化的数据。总结:二分查找通过“对半排除”大幅提升效率,是大数据量有序数据的高效选择,而线性查找在小数据量或无序场景更灵活。

阅读全文
冒泡排序:最简单的排序算法,3分钟轻松入门
2025-12-08 133 阅读 数据结构 排序算法

冒泡排序是一种基础排序算法,通过模拟“气泡上浮”过程,将最大元素逐步“冒”到数组末尾实现排序。核心思想是重复比较相邻元素,若前大后小则交换,每轮遍历后最大元素到位,且若某轮无交换则提前结束。 以数组[5,3,8,4,2]为例:第1轮比较相邻元素,最大数8“冒”到末尾,数组变为[3,5,4,2,8];第2轮比较前4个元素,第二大的5到倒数第二位置,数组变为[3,4,2,5,8];第3轮比较前3个元素,第三大的4到倒数第三位置,数组变为[3,2,4,5,8];第4轮比较前2个元素,第四大的3到倒数第四位置,数组变为[2,3,4,5,8];最后一轮无交换,排序完成。 关键优化是提前结束,避免无效遍历。时间复杂度最坏和平均为O(n²),空间复杂度O(1)。其简单易懂,是排序算法入门的基础,虽效率较低

阅读全文
哈希表怎么存数据?哈希函数让查找变简单

文章用找书类比引出问题:顺序查找数据(如数组)效率低,哈希表是高效存储工具。哈希表核心是哈希函数,将数据映射到“桶”(数组位置),实现快速存取。哈希函数把数据转为哈希值(桶编号),如学号取后两位得哈希值。存储时,先算哈希值定位桶,若多数据哈希值相同(冲突),用链表法(桶内挂链表)或开放寻址法(找下一个空桶)解决。查找时,直接算哈希值定位桶,再在桶内查找,无需遍历全部数据,速度极快。哈希表应用广泛(如通讯录、缓存),核心是用哈希函数将查找从“翻遍”转为“直达”。

阅读全文
手把手教你画二叉树:数据结构入门第一课

二叉树是数据结构基础,每个节点最多有左、右两个子节点,无后代的节点为叶子。核心术语包括:根节点(顶层起点)、叶子节点(无子节点)、子节点(父节点的下一层节点)、左右子树(节点的左/右子树及后代)。 构建时从根节点开始,逐步添加子节点,最多两层分支,不可超过两个子节点,子节点位置需有序(左/右有别)。判断二叉树需满足:每个节点≤2个子节点,且子节点位置明确。 遍历方式有前序(根→左→右)、中序(左→根→右)、后序(左→右→根)。画树是理解核心,直观展现节点关系,为堆、红黑树等复杂结构及算法(排序、查找)奠基。

阅读全文
排队的学问:队列在数据结构中的应用

文章介绍了队列数据结构。生活中排队(如食堂打饭)体现“先来先服务”,是队列雏形。队列是“先进先出”(FIFO)的数据结构,核心操作包括入队(队尾添加元素)和出队(队首移除最早加入的元素),还可查看队首、判断空队列。 队列与栈(后进先出,LIFO)不同,前者“先来后到”,后者“后来居上”。 队列应用广泛:电脑任务调度中,系统按队列处理多任务(如先打开的程序优先获CPU时间);BFS算法用队列逐层扩展节点,实现迷宫最短路径搜索;电商促销时,队列缓冲用户请求,避免系统过载;多线程中,生产者向队列添加数据,消费者按序处理,实现异步协作。 学习队列能解决按顺序处理数据、避免资源冲突等问题,是编程和算法的基础工具。理解“先进先出”原则,有助于高效解决实际问题。

阅读全文
生活中的栈:为什么栈是数据结构的入门首选?

文章以叠盘子、浏览器后退等生活场景引出“栈”,其核心特性是“后进先出”(LIFO)。栈是只能从顶部操作的容器,核心操作为“进栈(Push)”和“出栈(Pop)”。作为数据结构入门首选,栈逻辑简单(仅LIFO规则)、操作明确(仅两个基础操作)、应用广泛(括号匹配、浏览器后退、递归等场景),且用数组或链表即可简单实现。它是后续学习队列、树等结构的基础,帮助建立清晰的编程思维,是理解数据结构的“敲门砖”。

阅读全文
链表vs数组:数据结构入门必知的区别

数组和链表是编程中最基础的数据结构,理解其区别与适用场景对高效编码至关重要。 数组特点:连续内存存储,通过索引随机访问(时间复杂度O(1)),但初始需固定大小,中间插入/删除需移动元素(O(n)),适合已知固定大小、高频随机访问场景(如成绩表、地图坐标)。 链表特点:分散内存存储,节点含数据和指针,无法随机访问(需从头遍历,O(n)),但动态扩展灵活,中间插入/删除仅需修改指针(O(1)),适合动态数据、高频增删场景(如队列、链表哈希表)。 核心区别:数组连续内存但操作受限,链表分散存储但访问慢。关键差异体现在存储方式、访问速度、插入删除效率,需根据需求选择。理解其底层逻辑,可写出更高效的代码。

阅读全文
从0开始学数据结构:数组到底是什么?

数组是一组相同类型数据的有序集合,通过索引(从0开始)访问,元素连续存储,用于高效管理大量同类数据。例如班级成绩,用数组`scores = [90,85,95,78,92]`可替代多个变量,便于整体操作。 声明初始化(如Python):`scores = [90,85,95,78,92]`或`[0]*5`(声明长度为5的数组)。访问元素用`scores[索引]`,需注意索引范围(0到长度-1),越界会报错。 基本操作:遍历可用循环(`for score in scores: print(score)`);插入删除需移动后续元素(时间复杂度O(n))。 核心特点:类型相同、索引从0开始、元素连续存储。优点是访问速度快(O(1)),缺点是插入删除效率低、静态大小。 数组是数据结构基础,理解其“索引访问、连续存储”的核心思想,对学习链表、哈希表等复杂结构至关重要,是数据管理的核心工具。

阅读全文