目录
- 0 引言
- 1 数据结构和算法
-
- 1.1 数据结构的分类
-
- 1.1.1 逻辑结构
- 1.1.2 物理结构(存储结构)
- 1.1.3 两种结构的关系
- 1.2 算法分类
-
- 1.2.1 按照设计策略分类
- 1.2.2 按照问题类型分类
- 1.2.3 按照实现方法分类
- 1.2.4 按照用途分类
- 1.2.5 特殊类别
- 2 算法好坏的评判标准
-
- 2.1 时间复杂度
-
- 2.1.1 基本概念
- 2.1.2 常见时间复杂度
- 2.1.3 如何计算时间复杂度
- 2.1.4 时间复杂度和实际性能
- 2.2 空间复杂度
-
- 2.2.1 基本概念
- 2.2.2 空间复杂度的组成
- 2.2.3 常见的空间复杂度
- 2.2.4 空间复杂度的计算
- 2.2.5 空间复杂度与时间复杂度的关系
- 2.2.6 实际应用中的考虑
- ♂️ 作者:海码007
- 专栏:计算机四大基础专栏
- 其他章节:网络快速入门系列、计网概述、计网应用层详解、计网Web和HTTP、计网FTP、计网EMail、计网DNS、计网P2P
- 标题:【数据结构和算法 第一章 】算法 时间复杂度 空间复杂度
- ❣️ 寄语:不怕苦,吃苦半辈子。怕吃苦,吃苦一辈子!
- 最后:文章作者技术和水平有限,如果文中出现错误,希望大家能指正
0 引言
最近开始 大话数据结构和算法
的学习,决定恶补计算机基础知识。
1 数据结构和算法
数据结构和算法是计算机科学的两个核心概念,它们对于开发高效和优化的软件至关重要。
-
数据结构:这是组织和存储数据的方式,使其可以有效地访问和修改。数据结构关注的是数据的组织和管理方式。不同的数据结构适用于不同类型的应用,主要的数据结构包括数组、链表、栈、队列、树、图等。选择合适的数据结构可以提高程序的效率和性能。
-
算法:算法是一系列定义清晰的指令,用于执行特定的任务或解决问题。它是解决特定问题的方法和步骤。算法的效率通常通过时间复杂度
和空间复杂度
来衡量,这影响了程序运行的快速和资源使用的高效。
数据结构和算法紧密相连:优秀的算法往往依赖于合适的数据结构来实现。掌握这两个概念对于编程和软件开发至关重要,因为它们直接影响到代码的性能和效率。
1.1 数据结构的分类
确实,数据结构通常可以根据其在计算机中的组织方式分为逻辑结构和物理结构两大类:
1.1.1 逻辑结构
逻辑结构描述的是数据对象之间的逻辑关系,即数据元素之间的相互关系,而不涉及这些关系在计算机内存中的存储方式。逻辑结构主要分为以下几类:
- 线性结构:数据元素之间是一对一的关系。例如,数组、链表、栈和队列。
- 树形结构:数据元素之间存在一对多的层次关系。例如,二叉树、红黑树、B树等。
- 图形结构:数据元素是多对多关系。例如,图可以包含多个节点,这些节点之间通过边相连,可以是有向的也可以是无向的。
- 集合结构:数据元素之间除了“属于同一集合”这一关系外,没有其他关系。
1.1.2 物理结构(存储结构)
物理结构是指数据的实际存储方式(在内存或磁盘上的排列方式)。物理结构主要关注数据的存储和访问方式。它通常有以下几种形式:
- 顺序存储结构:数据元素存放在地址连续的存储单元里,如
数组
。
- 链式存储结构:数据元素存放在任意的存储单元里,这些存储单元可以位于内存的任何位置,通过指针或引用相连,如
链表
。
- 索引存储结构:数据和索引分开存储,通过索引快速查找数据,这种方式常见于
数据库系统
。
- 散列存储结构:通过散列函数直接计算数据元素的存储地址,如
哈希表
。
在选择数据结构时,逻辑结构
决定了数据的组织方式
,而物理结构
决定了数据的存储方式
。根据不同的应用场景和需求,选择合适的数据结构对于提高程序性能和效率至关重要。
1.1.3 两种结构的关系
逻辑结构最终都需要通过相应的物理结构来实现。逻辑结构
定义了数据元素之间的关系,但它不涉及具体的实现细节。为了在计算机系统中存储和操作这些数据,必须选择合适的物理结构
来实际实现这些逻辑结构。
- 顺序存储结构和链式存储结构是最常见的两种
物理结构
。例如,数组是线性结构的顺序存储实现,而链表是线性结构的链式存储实现。
- 树形结构和图形结构的逻辑结构通常也需要通过链式存储或者结合顺序存储和链式存储的方式来实现。例如,二叉树可以通过数组(顺序存储)或指针(链式存储)来实现。
- 物理结构的选择影响了数据结构的性能,包括存取效率、内存使用、数据元素的插入和删除效率等。例如,数组提供快速的随机访问,但在插入和删除操作方面不如链表高效。
因此,在设计和实现数据结构时,开发者需要综合考虑逻辑结构和物理结构,以实现特定应用的需求和性能目标。
1.2 算法分类
算法可以根据其设计策略、解决的问题类型或实现方法等方面进行分类。以下是一些主要的算法分类:
1.2.1 按照设计策略分类
- 分治算法:将复杂问题分解成更小的子问题,递归解决这些子问题,然后合并结果。例如,快速排序和归并排序。
- 动态规划:将问题分解成重叠的子问题,并存储这些子问题的解,避免重复计算。例如,斐波那契数列的优化实现。
- 贪心算法:在每个步骤中选择当前看起来最优的选择,希望导致全局最优解。例如,最小生成树的Prim算法和Kruskal算法。
- 回溯算法:通过试错来找到问题的解,如果发现当前选择不是最优解,则回溯并尝试其他选项。例如,解决八皇后问题。
1.2.2 按照问题类型分类
- 排序算法:如快速排序、归并排序、冒泡排序等。
- 搜索算法:如二分查找、深度优先搜索(DFS)、广度优先搜索(BFS)。
- 图算法:如Dijkstra算法(最短路径)、Floyd-Warshall算法。
- 字符串处理算法:如KMP算法、Rabin-Karp字符串搜索算法。
1.2.3 按照实现方法分类
- 递归算法:通过调用自身来解决问题的子部分。
- 迭代算法:通过重复执行一系列操作直到达到特定条件来解决问题。
1.2.4 按照用途分类
- 算法数学问题:例如,素数生成(埃拉托斯特尼筛法)、大数运算。
- 机器学习算法:如决策树、支持向量机、神经网络。
- 密码学算法:如RSA、AES加密算法。
1.2.5 特殊类别
- 随机算法和启发式算法:例如,蒙特卡洛方法和遗传算法。
- 并行算法:专为并行处理设计的算法,能同时运行多个计算过程。
选择合适的算法取决于具体问题的需求、数据的特性、时间复杂度和空间复杂度的限制等因素。理解不同类型的算法以及它们的适用场景对于开发高效和可靠的软件系统至关重要。
2 算法好坏的评判标准
2.1 时间复杂度
算法的时间复杂度是衡量算法运行时间长短的一个重要指标。它表示了算法执行所需要的时间随着输入数据量的增长而增加的趋势。时间复杂度的概念有助于程序员在不同算法之间做出选择,特别是在处理大规模数据时。
2.1.1 基本概念
- 大O表示法:时间复杂度通常使用大O符号(O)表示。例如,O(n)表示算法运行时间与输入数据量n成正比。
- 最坏情况复杂度:通常我们关注算法在最坏情况下的时间复杂度,因为这提供了算法性能的一个保证。
- 平均时间复杂度:有时也会考虑算法在平均情况下的表现。
- 最佳情况复杂度:某些情况下,了解算法在最佳情况下的表现也是有用的。
2.1.2 常见时间复杂度
- O(1):常数时间复杂度,算法执行时间不随输入数据量的增加而增加。
- O(log n):对数时间复杂度,例如二分查找。
- O(n):线性时间复杂度,算法执行时间与输入数据量成正比。
- O(n log n):对数线性时间复杂度,很多高效的排序算法(如快速排序、归并排序)属于这一类。
- O(n^2):二次时间复杂度,例如冒泡排序、插入排序等简单排序算法。
- O(n^3):立方时间复杂度,某些较为复杂的算法可能会达到这个级别。
- O(2^n) 和 O(n!):指数时间复杂度和阶乘时间复杂度,这些算法的效率非常低,通常在输入规模稍大时就变得不实用。
2.1.3 如何计算时间复杂度
- 确定算法的基本操作:通常是算法中最内层循环的操作。
- 计算基本操作的执行次数:这通常取决于输入数据的规模。
- 忽略低阶项和常数因子:在大O表示法中,我们通常关注主导项(最高阶项)。
2.1.4 时间复杂度和实际性能
虽然时间复杂度是衡量算法效率的关键因素,但它并不是唯一因素。有时,具有较高时间复杂度的算法可能在实际应用中比具有较低时间复杂度的算法表现得更好,这可能由于各种实际因素,如常数因子、内存访问模式、硬件优化等。
因此,在评估和选择算法时,除了考虑理论上的时间复杂度之外,实际的应用场景和性能测试结果也非常重要。
2.2 空间复杂度
算法的空间复杂度是指执行算法所需的存储空间与输入数据量之间的关系。空间复杂度提供了一个衡量标准,用于评估算法对计算机内存资源的使用情况。理解空间复杂度对于开发内存效率高的程序尤为重要,特别是在资源有限的环境中。
2.2.1 基本概念
- 空间复杂度:通常表示为大O符号(O),用于描述算法内存需求的增长率。例如,O(n)表示随着输入数据量n的增加,算法所需空间呈线性增长。
- 总空间需求:算法的总空间需求包括固定部分(如变量、常数和程序代码占用的空间)和变量部分(由输入数据的规模决定
的空间)。
2.2.2 空间复杂度的组成
- 固定部分:这部分空间与算法执行的数据规模无关。它包括代码存储空间、简单变量和固定大小的结构变量等。
- 变量部分:这部分空间随着输入数据的规模变化而变化。它包括动态分配的空间、递归栈空间等。
2.2.3 常见的空间复杂度
- O(1):常数空间复杂度,即算法所需的空间不随输入数据的大小而变化。
- O(n):线性空间复杂度,算法所需的空间与输入数据的大小成线性关系。
- O(n^2):二次空间复杂度,常见于需要存储输入数据间所有两两组合的情况。
2.2.4 空间复杂度的计算
- 确定算法的变量空间:包括局部变量、参数、动态分配的空间等。
- 考虑递归算法的栈空间:对于递归算法,栈的深度与输入数据的大小有关。
- 总结固定空间和变量空间:算法的总空间复杂度是固定空间和变量空间之和。
2.2.5 空间复杂度与时间复杂度的关系
- 在一些情况下,为了降低时间复杂度,算法可能会增加空间复杂度,这种情况称为空间换时间。
- 反之,为了减少空间的使用,某些算法可能会增加时间复杂度,称为时间换空间。
2.2.6 实际应用中的考虑
在实际应用中,算法的空间复杂度同样重要。特别是在内存受限的环境(如嵌入式系统、移动设备)中,高空间复杂度的算法可能会导致性能问题甚至运行失败。因此,在设计算法时,需要根据应用场景和资源限制,平衡时间和空间的需求。