算法库
了解更多关于算法的知识,以及如何使用编程语言内置的算法库。
引言
算法是一组步骤的表达。通过描述每一步的操作,我们指导计算机执行特定任务。通常,我们可以使用自然语言来描述每一步的动作。
考虑以下简单描述:
- 输入一个整数。
- 输入另一个整数。
- 比较两个整数并返回最大值。
- 比较两个整数并返回最小值。
如果需要同时求出最小值和最大值,我们可以编写自己的通用算法,也可以使用 C++ 中可用的算法模板库中预写好的算法。
算法就像一条从问题通向解决方案的路径。许多高级编程语言都自带算法库。其原因只有一个:任何通过计算机等设备进行计数或计算的过程,都需要遵循一系列步骤或指令。计算机科学家用“算法”这个词来描述一组操作指令。
在某些情况下,这些指令可能很简单,如上所述。但在大多数情况下,它们要复杂得多。对于复杂的场景,我们需要借助算法库的帮助。否则,我们必须手动处理底层细节,这会耗费大量时间,使我们无法专注于构建应用程序中的其他重要部分。
让我们以之前学过的欧几里得算法为例。它是一种用于计算两个整数最大公约数(GCD)的方法。
我们可以这样展示该算法:
- 取两个整数 和 。
- 将 除以 ,得到余数 。
- 将 的值替换为 ,将 的值替换为原来的 。
- 重复此过程,直到 。
- 当 时,停止计算,此时 即为最大公约数。
清晰且无歧义地描述所需执行的动作非常重要。
总结来说,数据作为输入进入计算机。随后,算法接管并对数据进行处理。最后,处理后的数据以输出形式呈现。
全球范围内正在运行的算法有万亿级别,甚至更多。而且这个数字只会持续增长。因为随着数据量的增加,我们需要以更有序的方式组织数据。因此,我们需要像 C++ 中的容器类或 Java 中的集合框架这样的工具。本章将对此进行深入讨论。
我们可以手动管理一个小规模的数据集,但一家 IT 产品公司需要专门的算法来成功交付其复杂的产品。因此,显然为了避免在海量数据处理中陷入底层细节,我们需要算法库。
让我们再次以欧几里得算法为例。它是一种用于计算两个整数最大公约数(GCD)的方法。
我们可以这样展示该算法:
- 取两个整数 和 。
- 将 除以 ,得到余数 。
- 将 的值替换为 ,将 的值替换为原来的 。
- 重复此过程,直到 。
- 当 时,停止计算,此时 即为最大公约数。
清晰且无歧义地描述所需执行的动作非常重要。
总结来说,数据作为输入进入计算机。随后,算法接管并对数据进行处理。最后,处理后的数据以输出形式呈现。
全球范围内正在运行的算法有万亿级别,甚至更多。而且这个数字只会持续增长。因为随着数据量的增加,我们需要以更有序的方式组织数据。因此,我们需要像 C++ 中的容器类或 Java 中的集合框架这样的工具。本章将对此进行深入讨论。
我们可以手动管理一个小规模的数据集,但一家 IT 产品公司需要专门的算法来成功交付其复杂的产品。因此,显然为了避免在海量数据处理中陷入底层细节,我们需要算法库。
让我们看两个 C++ 代码片段,以理解为何需要算法库。它是 标准模板库(STL) 的一部分。STL 提供了许多标准算法的泛型版本,可以替代我们繁琐的底层实现。
实现 Maximum() 和 Minimum() 方法
第一个例子展示了一个简单的程序:从用户那里获取两个整数,并输出它们的最大值和最小值。
1#include <iostream> 2using namespace std; 3 4int main() { 5 int num1, num2; 6 cout << "Please enter a number (integer): "; 7 cin >> num1; 8 cout << "Please enter a number (integer): "; 9 cin >> num2; 10 11 if (num1 > num2) 12 cout << "Maximum value: " << num1 << endl; 13 else 14 cout << "Maximum value: " << num2 << endl; 15 16 if (num1 < num2) 17 cout << "Minimum value: " << num1 << endl; 18 else 19 cout << "Minimum value: " << num2 << endl; 20 21 return 0; 22}
在此代码中,我们对如何在 C++ 中寻找两个数的最大值和最小值进行了非常基础的实现。运行程序后,提示输入两个整数。输入后,即可获得最大值和最小值。
1Please enter a number (integer): 210 3Please enter a number (integer): 45 5Maximum value: 10 6Minimum value: 5
使用算法库中的 max() 和 min() 方法
然而,如果我们使用 C++ 算法库,可以用更少的代码行完成同样的任务。
1#include <iostream> 2#include <algorithm> 3using namespace std; 4 5int main() { 6 int num1, num2; 7 cout << "Please enter a number (integer): "; 8 cin >> num1; 9 cout << "Please enter a number (integer): "; 10 cin >> num2; 11 12 cout << "Maximum value: " << max(num1, num2) << endl; 13 cout << "Minimum value: " << min(num1, num2) << endl; 14 15 return 0; 16}
在上述代码中:
- 第 3 行:包含
algorithm头文件,这是关键所在。 - 第 15–16 行:现在可以直接使用
max()和min()方法,底层逻辑由库自动处理。
用更少的代码行,我们得到了相同的结果。
1Please enter a number (integer): 210 3Please enter a number (integer): 45 5Maximum value: 10 6Minimum value: 5
每种高级语言都试图通过其框架或库解决类似问题。一些常见的算法术语包括排序、打乱和搜索。
使用 Java 集合框架对列表进行排序
在 Java 中,算法来自 Collection 类,平台提供的大多数算法都作用于 List 实例。少数也适用于任意选择的 Collection 实例。
让我们看一个例子:使用 Collections.sort() 方法将字母列表按升序排列。
1import java.util.Arrays; 2import java.util.Collections; 3import java.util.List; 4 5//SortExampleOne 6class Main { 7 public static void main(String[] args) { 8 List<String> list = Arrays.asList("x", "n", "y", "a", "s", "j"); 9 Collections.sort(list); 10 System.out.println(list); 11 } 12}
上述算法以静态方法的形式呈现,其第一个参数是操作的目标集合。运行代码后,输出如下:
1[a, j, n, s, x, y]
当列表规模较小时,我们可以手动实现底层逻辑,但面对大规模数据时,最好借助算法库。
让我们看下面这段代码:
1import java.util.Arrays; 2 3//SortExampleTwo 4class Main { 5 public static void main(String[] args) { 6 int[] anyArray = {210, 45, 258, 326, -12, 0, 89, 4, 9}; 7 System.out.println("Before Sorting : "); 8 System.out.println(Arrays.toString(anyArray)); 9 System.out.println("After Sorting : "); 10 for (int i = 0; i < anyArray.length; i++) { 11 int index = i; 12 for (int j = i + 1; j < anyArray.length; j++) 13 if (anyArray[j] < anyArray[index]) 14 index = j; 15 16 int smallerNumber = anyArray[index]; 17 anyArray[index] = anyArray[i]; 18 anyArray[i] = smallerNumber; 19 System.out.println(anyArray[i]); 20 } 21 } 22}
输出结果为按升序排列的元素:
1Before Sorting : 2[210, 45, 258, 326, -12, 0, 89, 4, 9] 3After Sorting : 4-12 50 64 79 845 989 10210 11258 12326
上述 Java 代码演示了一种称为 选择排序 的简单排序算法,用于整数数组。
- 第 6–8 行:声明一个名为
anyArray的数组,并打印原始未排序数组。 - 第 10–18 行:使用嵌套循环结构对数组进行排序。遍历数组,找出未排序部分的最小元素索引,并将其与当前位置交换。
- 第 19 行:排序过程中逐个打印已排序的元素。
最终结果是一个按升序排列的数组。
上述程序重新排列了列表,使其元素按升序排列。然而,我们是从零开始编写代码,这其实是不必要的。我们可以使用 Java 集合框架来完成相同操作,例如以下代码:
1import java.util.Arrays; 2import java.util.Collections; 3import java.util.List; 4 5//SortExampleThree 6class Main { 7 public static void main(String[] args) { 8 List<Integer> list = Arrays.asList(210, 45, 258, 326, -12, 0, 89, 4, 9); 9 Collections.sort(list); 10 System.out.println(list); 11 } 12}
运行代码后,输出如下:
1[-12, 0, 4, 9, 45, 89, 210, 258, 326]
使用 STL 对列表进行排序
我们也可以在 C++ 中完成同样的事情。STL 无缝集成算法与容器,提供了一个全面的框架,用于管理和操作数据结构。Java 集合框架也以自己的方式实现了类似功能。
比较 C++ 和 Java 有助于我们更好地理解算法与数据结构之间的关系。
让我们看看上面的代码在 C++ 中使用 std::sort() 方法的实现:
1#include <algorithm> 2#include <array> 3#include <iostream> 4 5int main() { 6 std::array<int, 9> standardArray = {210, 45, 258, 326, -12, 0, 89, 4, 9}; 7 // 使用默认操作符排序 8 std::sort(standardArray.begin(), standardArray.end()); 9 for (auto autoVariable : standardArray) { 10 std::cout << autoVariable << " "; 11 } 12 std::cout << '\n'; 13 // 使用 STL 比较函数对象进行降序排序 14 std::sort(standardArray.begin(), standardArray.end(), std::greater<int>()); 15 for (auto autoVariable : standardArray) { 16 std::cout << autoVariable << " "; 17 } 18 std::cout << '\n'; 19}
如代码所示,std::sort() 方法默认接受两个参数:起始点和结束点。之后,它会自动将列表按升序排列,无需手动操作,不像 Java 中那样。
除了将整数集合按升序排列,我们还可以轻松反转顺序。C++ STL 通过传入额外参数即可实现这一点:
1std::sort(standardArray.begin(), standardArray.end(), std::greater<int>());
我们得到如下输出,展示了列表在升序和降序下的排列结果:
1-12 0 4 9 45 89 210 258 326 2326 258 210 89 45 9 4 0 -12
在上述代码中:
- 第 6 行:使用 STL 的
std::array<>模板创建standardArray数组,可指定数据类型和长度。 - 第 8–17 行:分别按升序和降序排序,并将结果打印到控制台。
- 第 14 行:使用比较函数对象
std::greater<int>实现降序排序。
- 第 14 行:使用比较函数对象
本课介绍了算法库的基本概念。