《Hello 算法》第一章 · 初识算法

算法

算法定义

算法(algorithm)是指在有限时间内通过一组明确的步骤或指令来解决特定问题的过程。它具有以下基本特性:

  • 明确性:问题及其输入输出是清晰定义的,确保在不同的执行环境下可以得到一致的结果。
  • 可行性:算法能够在有限的步骤、时间和内存空间内完成,保证其可以在实际系统中执行。
  • 确定性:每个步骤有清晰的定义,并且在相同的输入和运行条件下,算法的输出始终一致,避免了不确定性和随机性。
  • 最优性:在满足问题要求的前提下,算法能够实现最高效的执行,例如最短的时间复杂度和最少的空间消耗。

实例

  • 排序算法,如冒泡排序(Bubble Sort)和快速排序(Quick Sort),用于将一组无序数据排列为有序数据。快速排序通常被认为是最优的,因为它的平均时间复杂度是 O(n log n),而冒泡排序的时间复杂度是 O(n²)。

算法复杂度

算法复杂度(algorithm complexity)是用来衡量算法执行效率的指标,主要包括时间复杂度空间复杂度。它反映了算法执行时所需资源的消耗,通常用于评估算法的优劣。

  • 时间复杂度:描述算法执行所需时间的增长情况,通常使用大 O 表示法(Big-O notation)。例如,O(n)、O(log n)、O(n²) 等表示算法随着输入规模的增加,运行时间是如何变化的。
  • 空间复杂度:描述算法执行时所需内存空间的增长情况。与时间复杂度类似,空间复杂度也可以用大 O 表示法来表示。

常见的时间复杂度

  • O(1):常数时间复杂度,表示算法的执行时间不随输入规模的增加而变化。
  • O(log n):对数时间复杂度,表示算法的执行时间随着输入规模的增加而缓慢增长。例如,二分查找算法。
  • O(n):线性时间复杂度,表示算法的执行时间与输入规模成正比。
  • O(n²):平方时间复杂度,表示算法的执行时间随着输入规模的平方增长。例如,冒泡排序、插入排序等。
  • O(n log n):对数线性时间复杂度,表示算法的执行时间比线性增长快,但比平方增长慢。例如,快速排序和归并排序。

space_complexity_common_types
time_complexity_common_types

这一部分内容将在第二章细讲
实例

  • 在查找某个元素时,线性查找(O(n))的时间复杂度较高,适用于小规模数据。而二分查找(O(log n))则适用于已经排序好的数据,效率要高得多。

数据结构

数据结构定义

数据结构(data structure)是指组织和存储数据的方式,它涉及数据内容、数据间的关系以及对数据的操作方法。良好的数据结构设计能够有效提高程序的性能,达到高效处理数据的目的。数据结构的设计目标包括:

  • 空间效率:尽量减少内存占用,节省计算机资源。
  • 操作效率:使数据的访问、插入、删除、更新等操作尽可能快速,提升算法的执行效率。
  • 简洁性:提供简洁且直观的数据表示和逻辑结构,以便算法能高效运行。
  • 平衡性:数据结构的设计是一个权衡过程,为了在某一方面取得优化,往往需要在其他方面做出妥协。例如,哈希表能够提供快速的查找操作,但它的空间消耗可能较大。

常见的数据结构

  • 线性结构:如数组、链表、栈、队列。
  • 树形结构:如二叉树、平衡二叉树、B 树。
  • 图形结构:如无向图、有向图、加权图。
  • 哈希结构:哈希表用于快速查找。

数据结构与算法的关系

数据结构与算法是紧密相关的,它们的结合体现在以下几个方面:

  • 数据结构是算法的基础:数据结构为算法提供了有序的存储结构和方法,通过结构化的存储方式组织数据,并为算法提供快速的访问和修改操作。例如,数组和链表是最常见的数据结构,分别适合不同的算法需求。
  • 算法为数据结构赋予功能:数据结构本身仅存储数据,只有与算法结合,才能发挥其应有的作用。通过不同的算法,可以对同一数据结构进行各种操作,如排序、查找、遍历等。
  • 数据结构的选择影响算法的效率:同一问题可以通过不同的数据结构来实现,选择合适的数据结构能够显著提高算法的效率。例如,图的遍历可以通过邻接矩阵或邻接表实现,选择不同的数据结构会影响算法的性能。

relationship_between_data_structure_and_algorithm

实例

  • 在实现图的最短路径算法时,使用邻接矩阵的空间复杂度较高,但适合密集图;而使用邻接表则适用于稀疏图,能够节省内存并提高效率。
  • 在实现深度优先搜索(DFS)时,栈(Stack)是一个重要的辅助数据结构,它能够帮助我们跟踪节点的遍历路径。

总结

数据结构与算法是计算机科学的核心,良好的数据结构设计能够帮助我们高效地存储和操作数据,而合理选择和优化算法可以显著提高程序的性能。理解它们之间的关系,能够帮助我们在实际编程中做出更合适的选择,提高代码的执行效率和可维护性。