如何编写算法?

2025年3月17日 | 阅读 12 分钟

描述算法

算法基础

"一套有限的规则或指令,用于计算或其他问题解决操作" 或 "一种在有限步骤内解决数学问题的方法,通常涉及递归操作" 是算法一词的两种定义。

因此,算法是一套有限的程序,用于解决特定问题。

算法是一组用于解决问题或执行任务的指令。在构建程序之前,算法通常以伪代码的形式编写,结合你的母语和一种或多种编程语言。本文将向你展示如何构建一个基本算法来启动你的应用程序。算法的利用

在许多领域,算法都至关重要,并且有多种用途。算法广泛应用于各种领域,例如:

  • 算法是计算机编程的基石,用于解决从简单的排序和搜索到更复杂的人工智能和机器学习问题。
  • 算法在数学中用于解决诸如图确定图中的最短路径或一组线性方程的最佳答案等问题。
  • 运筹学:算法用于在资源分配、物流和运输等领域进行决策和优化。
  • 人工智能:人工智能和机器学习建立在算法之上,这些算法用于创建能够执行图像识别、自然语言处理和决策等任务的智能系统。
  • 数据科学:算法在营销、银行和医疗保健等行业中用于分析、处理和提取海量数据中的见解。
  • 这只是算法众多用途中的一小部分。随着新技术和新领域的不断发展,算法在现代生活中的作用日益重要。

算法的范围从简单到复杂,具体取决于你的目标。

How to Write an Algorithm

可以通过制作新食谱的过程来理解它。遵循新食谱时,必须阅读说明并正确执行每个步骤。最终结果是新餐点烹饪至完美。你使用手机、电脑、笔记本电脑或计算器时,都在使用算法。同样,算法也有助于程序员完成任务以产生所需的结果。

开发的算法是语言无关的,仅包含简单的指令,可用于用任何语言实现,并仍能产生所需的结果。

为什么需要算法?

  1. 需要算法来高效有效地解决复杂问题。
  2. 它们有助于自动化操作,提高其可靠性、速度和可用性。
  3. 算法还使计算机能够执行对人类来说手动执行会非常困难或不可能完成的任务。
  4. 它们用于简化流程、分析数据、提供预测以及为数学、计算机科学、工程、金融等各个行业的难题提供解决方案。

是什么让算法成为算法?

How to Write an Algorithm

与使用日常食谱印刷说明不同,你不会遵循它们。同样,并非所有写下的计算机指令都是算法。某些指令必须满足以下要求才能被视为算法:

  • 明确无歧义:算法必须明确无歧义。其每个动作都必须具有明确的含义,并且从头到尾都清晰可见。
  • 明确定义的输入:如果算法请求输入,则输入必须满足特定标准。它可能接受也可能不接受输入。
  • 明确定义的输出:算法必须精确地定义其输出。它应该生成至少一个输出。
  • 有限性:有限的算法在有限的时间内结束。
  • 可行性:该方法必须简单、通用且易于使用现有资源来实现。它不能包含任何尖端技术或任何不切实际的东西。
  • 语言无关:创建的算法必须是语言无关的,这意味着它必须包含简单的指令,这些指令可以用任何语言实现,同时仍能产生所需的结果。
  • 输入:算法可以有一个或多个输入。每个包含主运算符的表达式都必须接受一个或多个输入。
  • 输出:每个算法至少生成一个输出。任何包含主运算符的指令都必须接受零个或多个输入。
  • 清晰度:算法中的每个指令都需要清晰、具体且易于理解。可以参考任何算法指令来理解需要做什么。任何基本指令运算符的定义都必须没有歧义。
  • 有限性:在所有测试场景下,算法都必须在有限的步骤内结束。任何使用主运算符的指令都必须在特定时间内结束。没有基本条件的无限循环或递归函数不具备有限性。
  • 有效性:算法必须使用最基本、最实用、最简单的过程来创建,以便可以用纸和笔即可追溯。

算法特征

  • 它应该在设定的时间内结束。
  • 必须至少产生一个输出。
  • 它不应该需要任何输入。
  • 它应该是确定性的,这意味着结果应该与输入场景完全匹配。
  • 每个算法步骤都必须高效,即每个步骤都必须产生结果。

算法类型

有许多不同类型的算法。一些强大的算法包括:

  1. 算法的第一次尝试是蛮力算法。当我们遇到问题时,蛮力算法是首先想到的方法。
  2. 递归算法:递归是递归算法的基础。在这种情况下,问题被分解成更小的部分,并由同一个函数反复调用。
  3. 回溯法通过遍历所有可能的解决方案来构建答案。使用这种方法,我们继续根据标准构建答案。每当一个解决方案失败时,我们都会返回到原始问题,在新问题上进行构建,并重复该过程,直到问题解决或所有潜在解决方案都被考虑。
  4. 搜索算法:搜索算法在给定的数据结构中查找单个元素或一组元素。根据它们的处理方式或要查找的元素所属的数据结构,它们可以有多种形式。
  5. 排序算法:排序是根据需要组织一组事实的过程。排序算法是帮助完成此任务的算法。数据分组通常使用排序算法按升序或降序排序。
  6. 哈希算法在操作上类似于搜索算法。然而,它们有一个带有键 ID 的索引。在哈希中,将一个键分配给特定数据。
  7. 分治法:此方法将一个问题分解为更小的问题,分别解决每个问题,然后合并结果以提供整体答案。该过程包括以下三个步骤:
    • 除以
    • 解决
    • 合并
  8. 贪心算法:该算法逐块构建解决方案。下一个部分的即时优势是该部分解决方案的基础。下一部分的答案将提供最大的好处。
  9. 动态规划技术:为避免重复计算问题的相同部分,该技术应用已发现的答案。它将问题分解为更易于管理的重叠子问题并解决每个子问题。
  10. 随机化算法:我们在随机化算法中使用随机数来提供快速优势。预期结果部分取决于随机数。

请参阅“算法类型”文章,了解更多关于不同类型算法的信息。

算法的优点

算法提供以下好处:

  • 它们易于理解;
  • 它们是解决特定问题的解决方案的分步描述;
  • 由于问题被分解成更小的部分或阶段,因此程序员更容易将算法转化为工作程序。

算法的缺点

算法的缺点包括:

  • 编写算法所需的时间,这使其耗时。
  • 使用算法理解复杂推理可能非常困难。
  • 算法(重要)使显示分支和循环语句更加困难。

编写算法的步骤

How to Write an Algorithm

确定代码的结果。你试图解决什么具体问题,或者它应该为你做什么?一旦你清楚地知道自己想实现什么,你就可以决定达到目标所需的步骤。

How to Write an Algorithm

在第二步选择一个起点。为了确定过程的阶段,你必须首先选择起点和终点。回答以下问题以确定起点:

  • 有哪些信息或输入可用?
  • 这些数据存储在哪里?
  • 可以使用哪些公式来解决当前问题?
  • 使用可用数据的规则是什么?
  • 数据值之间可能存在哪些联系?
How to Write an Algorithm

找到算法的结论。与找到算法的起点类似,你可以通过关注以下问题来确定其终点:

  • 我们将从该过程中收集哪些信息?
  • 开始和结束之间有什么变化?
  • 什么将被更改或删除?
How to Write an Algorithm

列出从头到尾的每个步骤。首先进行大的移动。考虑你的目标是吃千层面晚餐的情况。你已经决定找到一个食谱是最好的起点,并且到晚上 7 点,你将拥有一份已经煮好并可以食用的千层面。你的行动可能类似于:

  • 执行在线食谱搜索。
  • 检查你的厨房里是否已有食材。
  • 列出你需要购买的食材。
  • 购买缺少的组件。
  • 回家。
  • 准备千层面。
  • 烘烤后让千层面冷却。
How to Write an Algorithm

选择完成每个阶段的方法。创建了分步蓝图后,考虑如何对每个阶段进行编码。你将使用哪种语言?你有哪些工具可以使用?在该语言中最快的完成每个步骤的方法是什么?选择代码的一部分并将其包含在你的算法中。描述完整个过程后,扩展每个阶段。

  • 例如,我们算法中制作千层面的第一步是在线搜索食谱。但这个搜索涉及到什么?要精确。例如:
  • 启动电脑。
  • 检查你的互联网连接是否正常。如果之前没有连接,请建立网络连接。
  • 启动你的网页浏览器。
  • 输入你的搜索条件。
  • 选择一个食谱链接。
  • 检查食谱是否符合你的要求。
  • 丢弃任何非素食食谱。
  • 检查食谱是否至少包含 5 份。
  • 尝试重复这些步骤,直到找到正确的组合。
  • 考虑你拥有的资源,例如你正在为其创建程序的系统的功能。就千层面而言,我们假设制作菜肴的人熟悉在线搜索、使用烤箱等。
How to Write an Algorithm

分析算法。创建算法后,就可以评估工作流程了。你需要你的算法来开始开发你的程序,因为它旨在做特定的事情。考虑以下问题,并根据需要回答:[2]

  • 算法是否完成了任务或解决了问题?
  • 输入和输出是否定义明确?
  • 最终目标是否应该扩展以包含更多内容?任何进一步的细节?
  • 是否有任何流程可以简化?
  • 算法结论的准确性是否得到保证?

如何分析算法?

一个标准的算法必须是高效的才能有效。因此,必须监视算法的有效性。可能有两个阶段:

  1. 先验分析:“先验”是拉丁语,意为“之前”。因此,先验分析是指在使用方法之前进行验证。当算法被写成理论步骤时,它在此处进行测试。假设所有其他变量,例如处理器速度,保持不变且不影响实现,则评估算法的效率。通常,算法设计者会这样做。硬件和编译器语言的类型对我们的调查没有影响。它为程序的复杂性提供了粗略的解决方案。
  2. 后验分析:前缀“后验”表示“之后”。因此,在实现算法后对其进行测试称为后验分析。通过实际应用并用任何编程语言运行来测试方法。这种分析有助于获得关于正确性(对于每种可能的输入,它是否显示或返回正确的结果)、所需空间、使用时间等的准确且真实的分析报告。换句话说,它取决于硬件和编译器语言。

如何确定算法复杂度?

算法的复杂性取决于它使用的空间和时间。因此,算法的复杂度是衡量算法运行并产生预期结果所需的时间以及存储所有数据(输入、临时数据和输出)所需的存储空间大小的度量。因此,这两个因素决定了算法的有效性。

使算法复杂的两个因素是:

  • 时间因子:关键过程的数量,例如排序算法中的比较,用于计算时间。
  • 空间因子:通过添加算法运行所需的全部内存空间来计算空间量。

因此,算法复杂度有两种类别:

1. 空间复杂度:算法需要多少内存来存储变量并生成输出,称为其空间复杂度。这可能适用于临时活动、输入或输出。

如何确定空间复杂度?

计算以下 2 个元素来确定算法的空间复杂度:

  • 固定部分:这描述了算法绝对需要该区域。例如,程序大小、输出变量和输入变量。
  • 可变部分:这描述了该区域可以根据算法的应用方式而变化。例如,动态内存分配、递归堆栈空间、临时变量等。

因此,任何算法 P 的空间复杂度(S(P))P 定义为 S(P) = C + SP(I),其中 C 表示算法的固定部分,S(I) 表示其可变部分,这取决于实例特征 I。

示例

考虑以下线性搜索方法:

步骤 1:开始

从步骤 2 获取数组的 n 个元素,并从步骤 2 的 x 获取要查找的数字。

步骤 3:从 arr[] 的最左侧成员开始,单独比较 arr[] 的每个元素与 x。

步骤 4:如果 x 匹配某个元素,则打印 True。

步骤 5:如果 x 与任何元素都不匹配,则打印 False。

步骤 6:结束

在本例中有两个变量:x 和 arr[],其中 x 是固定部分,arr[] 是 n 个元素的变量部分。因此,S(P) = 1 + n。因此,n(元素数量)决定了空间的复杂性。现在,空间将乘以指定变量和常量类型的​​数据类型。

2. 时间复杂度:算法运行并产生结果所需的时间称为算法的时间复杂度。这可能适用于常规进程、带条件的 if-else 语句、循环语句等。

如何计算时间复杂度?

还确定以下 2 个元素来计算算法的时间复杂度:

  • 恒定时间部分:这部分包含所有只执行一次的指令。例如,输入、输出、if-else、switch、算术运算等。
  • 可变时间部分:这部分包含运行 n 次或更多次的指令。例如,使用循环、递归等。

因此,任何算法 P 的时间复杂度由 T(P) = C + TP(I) 给出,其中 C 表示算法的恒定时间部分,TP(I) 是取决于实例特征 I 的可变部分。

示例

线性搜索方法的时序复杂度确定如下:

第一步:恒定时间

第二步是可变时间(使用 n 个输入)。

步骤 3:- 可变时间(直到数组长度 (n) 或找到元素的索引)

第四步:恒定时间

第五步:恒定时间

第六步:恒定时间

因此,T(P) = 5 + n,或可写为 T(n)。

如何制定算法?

  1. 自然语言:在本节中,我们使用日常英语表达算法。从中理解算法需要付出很多努力。
  2. 流程图:在本节中,算法以图形或可视方式表示。比自然语言更容易理解。
  3. 伪代码:算法用简单的英语注释和类似于真实代码的解释性文本来表示。但是,由于伪代码不具备任何编程语言的语法,因此计算机无法对其进行构建或理解。它是传达算法的最佳方法,因为即使是没有多少编程经验的普通人也能理解。

下一个主题递归算法