
数据结构和算法
文章平均质量分 86
学习算法至少具备任一语言的编程基础,且能够阅读和编写简单代码。
超级小狗
这个作者很懒,什么都没留下…
展开
-
二分查找
如上图所示,我们先初始化指针 i=0 和 j=n−1 ,分别指向数组首元素和尾元素,代表搜索区间 [0,n−1]。请注意,中括号表示闭区间,其包含边界值本身。它利用数据的有序性,每轮缩小一半搜索范围,直至找到目标元素或搜索区间为空为止。为了避免大数越界,我们通常采用公式 m=⌊i+(j−i)/2⌋ 来计算中点。若数组不包含该元素,则返回 −1。若数组不包含目标元素,搜索区间最终会缩小为空。,元素按从小到大的顺序排列且不重复。:在二分循环中,区间每轮缩小一半,循环次数为。接下来,循环执行以下两步。原创 2024-01-09 12:55:53 · 537 阅读 · 0 评论 -
13. 二叉树
二叉树(binary tree)是一种非线性数据结构,代表“祖先”与“后代”之间的派生关系,体现了“一分为二”的分治逻辑。与链表类似,二叉树的基本单元是节点,每个节点包含值、左子节点引用和右子节点引用。每个节点都有两个引用(指针),分别指向「左子节点 left-child node」和「右子节点 right-child node」,该节点被称为这两个子节点的「父节点 parent node」。原创 2023-12-05 10:52:33 · 184 阅读 · 0 评论 -
12. 哈希算法
前两节介绍了哈希表的工作原理和哈希冲突的处理方法。然而无论是开放寻址还是链式地址,。如果哈希冲突过于频繁,哈希表的性能则会急剧劣化。如下图所示,对于链式地址哈希表,理想情况下键值对均匀分布在各个桶中,达到最佳查询效率;最差情况下所有键值对都存储到同一个桶中,时间复杂度退化至O(n)。。观察以上公式,当哈希表容量capacity固定时,hash(),进而决定了键值对在哈希表中的分布情况。这意味着,为了降低哈希冲突的发生概率,我们应当将注意力集中在哈希算法hash()的设计上。原创 2023-12-05 10:39:34 · 182 阅读 · 0 评论 -
11. 哈希冲突
上一节提到,,因此理论上哈希冲突是不可避免的。比如,输入空间为全体整数,输出空间为数组容量大小,则必然有多个整数映射至同一桶索引。哈希冲突会导致查询结果错误,严重影响哈希表的可用性。为解决该问题,我们可以每当遇到哈希冲突就进行哈希表扩容,直至冲突消失为止。此方法简单粗暴且有效,但效率太低,因为哈希表扩容需要进行大量的数据搬运与哈希值计算。为了提升效率,我们可以采用以下策略。哈希表的结构改良方法主要包括“链式地址”和“开放寻址”。原创 2023-12-04 19:10:34 · 412 阅读 · 0 评论 -
10. 哈希表
哈希表(hash table),又称散列表,其通过建立键key与值value之间的映射,实现高效的元素查询。具体而言,我们向哈希表输入一个键key,则可以在 \(O(1)\) 时间内获取对应的值value。给定 n 个学生,每个学生都有“姓名”和“学号”两项数据。假如我们希望实现“输入一个学号,返回对应的姓名”的查询功能,则可以采用下图所示的哈希表来实现。除哈希表外,数组和链表也可以实现查询功能,它们的效率对比如下表所示。观察发现,,非常高效。原创 2023-12-03 20:32:36 · 182 阅读 · 0 评论 -
9. 双向队列
在队列中,我们仅能删除头部元素或在尾部添加元素。如下图所示,双向队列(double-ended queue)提供了更高的灵活性,允许在头部和尾部执行元素的添加或删除操作。原创 2023-12-03 11:01:59 · 468 阅读 · 0 评论 -
7. 栈
栈(stack)是一种遵循先入后出的逻辑的线性数据结构。我们可以将栈类比为桌面上的一摞盘子,如果需要拿出底部的盘子,则需要先将上面的盘子依次取出。我们将盘子替换为各种类型的元素(如整数、字符、对象等),就得到了栈数据结构。如下图所示,我们把堆叠元素的顶部称为“栈顶”,底部称为“栈底”。将把元素添加到栈顶的操作叫做“入栈”,删除栈顶元素的操作叫做“出栈”。原创 2023-11-29 18:39:06 · 154 阅读 · 0 评论 -
6. 列表
列表(list)是一个抽象的数据结构概念,它表示元素的有序集合,支持元素访问、修改、添加、删除和遍历等操作,无需使用者考虑容量限制的问题。列表可以基于链表或数组实现。当使用数组实现列表时,。这是因为我们通常无法事先确定需要存储多少数据,从而难以选择合适的列表长度。若长度过小,则很可能无法满足使用需求;若长度过大,则会造成内存空间的浪费。为解决此问题,我们可以使用「动态数组 dynamic array」来实现列表。它继承了数组的各项优点,并且可以在程序运行过程中进行动态扩容。实际上,原创 2023-11-28 20:25:14 · 143 阅读 · 0 评论 -
5. 链表
内存空间是所有程序的公共资源,在一个复杂的系统运行环境下,空闲的内存空间可能散落在内存各处。我们知道,存储数组的内存空间必须是连续的,而当数组非常大时,内存可能无法提供如此大的连续空间。此时链表的灵活性优势就体现出来了。链表(linked list)是一种线性数据结构,其中的每个元素都是一个节点对象,各个节点通过“引用”相连接。引用记录了下一个节点的内存地址,通过它可以从当前节点访问到下一个节点。链表的设计使得各个节点可以被分散存储在内存各处,它们的内存地址是无须连续的。原创 2023-11-27 19:00:51 · 459 阅读 · 0 评论 -
4.数组
数组(array)是一种线性数据结构,其将相同类型元素存储在连续的内存空间中。我们将元素在数组中的位置称为该元素的索引(index)。下图展示了数组的主要术语和概念。原创 2023-11-26 13:28:44 · 349 阅读 · 0 评论 -
3.数据结构
常见的数据结构包括数组、链表、栈、队列、哈希表、树、堆、图,它们可以从“逻辑结构”和“物理结构”两个维度进行分类。原创 2023-11-26 11:18:33 · 348 阅读 · 0 评论 -
2.复杂度分析
对于一个给定的算法,最差时间复杂度通常是在最坏情况下的时间复杂度上界,它提供了算法在最坏情况下的性能保证。对于一个给定的算法,最佳时间复杂度通常是在最佳情况下的时间复杂度下界,它提供了算法在最佳情况下的性能上限。需要注意的是,在计算空间复杂度时,我们通常不考虑输入参数的空间占用,因为输入参数是在调用函数时传入的,不是在算法内部分配的。如图下图所示,计算渐近上界就是寻找一个函数f(n),使得当 n 趋向于无穷大时,T(n)和f(n)处于相同的增长级别,仅相差一个常数项 c 的倍数。而与时间复杂度不同的是,原创 2023-11-25 16:38:45 · 169 阅读 · 0 评论 -
1.算法是什么
算法(algorithm)是一系列解决问题或执行任务的指令或规则的有序集合。它是为了解决特定问题而设计的一种计算方法或步骤。算法可以用来处理数据、执行计算、自动化任务以及实现各种功能。问题是明确的,包含清晰的输入和输出定义。具有可行性,能够在有限步骤、时间和内存空间下完成。各步骤都有确定的含义,相同的输入和运行条件下,输出始终相同。数据结构(data structure)是一种组织和存储数据的方式,它定义了数据之间的关系、操作和访问方式。原创 2023-11-25 15:22:37 · 301 阅读 · 0 评论