👏🏻 你好!欢迎访问IT教程网,0门教程,教程全部原创,计算机教程大全,全免费!

🔥 新增教程

《黑神话 悟空》游戏开发教程,共40节,完全免费,点击学习

《AI副业教程》,完全原创教程,点击学习

13 算法分析之大O表示法

在上一篇中,我们探讨了算法的空间复杂度,了解了如何衡量算法使用的内存资源。在本篇中,我们将深入了解算法分析中的一个关键概念——大O表示法,这一工具可以帮助我们评估算法的时间复杂度。

什么是时间复杂度?

时间复杂度是衡量算法执行时间随输入规模增长而增长的函数,是分析算法效率的重要指标。通过时间复杂度,我们可以预估算法在处理大数据时的表现。在分析算法时,常使用以下几个主要的复杂度量度:

  • $O(1)$:常数时间复杂度
  • $O(\log n)$:对数时间复杂度
  • $O(n)$:线性时间复杂度
  • $O(n \log n)$:线性对数时间复杂度
  • $O(n^2)$:平方时间复杂度
  • $O(2^n)$:指数时间复杂度
  • $O(n!)$:阶乘时间复杂度

每种复杂度都有各自的特点,能够清晰地指示在输入数据增大时算法性能的变化。

大O表示法的基本概念

大O表示法(Big O Notation)是一种用于描述算法复杂度的数学符号。它提供了一种简化的方式来表达算法的最坏情况下的执行时间或空间需求。

表达方式

在使用大O表示法时,通常表示为:

$$
T(n) = O(f(n))
$$

这里,$T(n)$表示算法的时间复杂度,$f(n)$是一个函数,反映输入规模$n$的变化。

定义

一个函数$g(n)$,如果存在常数$C > 0$和$n_0 \geq 0$使得对于所有的$n \geq n_0$都有:

$$
g(n) \leq C \cdot f(n)
$$

则我们可以称$g(n) = O(f(n))$。

大O表示法的例子

例子1:常数时间复杂度 $O(1)$

考虑一个简单的函数:

1
2
def get_first_element(arr):
return arr[0]

无论输入数组的大小如何,get_first_element函数始终只执行一次访问操作。因此,它的时间复杂度为 $O(1)$。

例子2:线性时间复杂度 $O(n)$

我们来看另一个例子,计算数组元素的和:

1
2
3
4
5
def sum_array(arr):
total = 0
for element in arr:
total += element
return total

在这个例子中,循环会遍历每个元素,因此时间复杂度为 $O(n)$,其中$n$是数组的长度。

例子3:平方时间复杂度 $O(n^2)$

考虑选择排序算法,它需要两个嵌套的循环来完成排序:

1
2
3
4
5
6
7
8
def selection_sort(arr):
n = len(arr)
for i in range(n):
min_index = i
for j in range(i + 1, n):
if arr[j] < arr[min_index]:
min_index = j
arr[i], arr[min_index] = arr[min_index], arr[i]

在选择排序中,外层循环执行$n$次,而内层循环在最坏的情况下也将执行$n$次。因此,该算法的时间复杂度为 $O(n^2)$。

例子4:线性对数时间复杂度 $O(n \log n)$

合并排序是一个经典的例子,其时间复杂度为 $O(n \log n)$:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
def merge_sort(arr):
if len(arr) > 1:
mid = len(arr) // 2
L = arr[:mid]
R = arr[mid:]

merge_sort(L)
merge_sort(R)

i = j = k = 0

while i < len(L) and j < len(R):
if L[i] < R[j]:
arr[k] = L[i]
i += 1
else:
arr[k] = R[j]
j += 1
k += 1

while i < len(L):
arr[k] = L[i]
i += 1
k += 1

while j < len(R):
arr[k] = R[j]
j += 1
k += 1

在这个算法中,每次分割数组的操作将数组大小减半,而合并两个子数组的操作则是线性的。因此,总的复杂度为 $O(n \log n)$。

总结

大O表示法是算法分析中一个强有力的工具,通过分析时间复杂度可以有效地评估算法性能。在实际编程中,合理选择算法和数据结构可以显著影响程序的执行效率。在下一篇中,我们将结合具体案例,实践简单的排序算法,进一步理解这一概念。

希望这篇文章能帮助你深入理解大O表示法的基本知识!如果有任何问题,欢迎随时讨论。

分享转发

14 实现一个简单排序算法

在上一篇教程中,我们学习了算法分析的基础知识,特别是如何使用大O表示法来评价算法的时间复杂度和空间复杂度。今天,我们将继续进行实际的算法实践,具体实现一个简单的排序算法——冒泡排序

冒泡排序概述

冒泡排序是一种简单的排序算法。它重复地遍历待排序的数组,比较相邻的元素,并在它们的顺序错误时交换它们。这个过程会一直进行,直到没有需要交换的元素为止。冒泡排序的名字来源于较小的元素“冒泡”到数组的顶端。

冒泡排序的基本步骤

  1. 从数组的最左边开始,比较相邻的两个元素。
  2. 如果前一个元素大于后一个元素,则交换它们。
  3. 向右移动一个位置,重复步骤1和2,直到到达数组的末尾。
  4. 经过一轮的比较,最大的元素会被“冒泡”到数组的末尾。
  5. 忽略最后一个已经排序的元素,重复上述步骤,直到所有元素都排序完成。

冒泡排序的时间复杂度

冒泡排序的最坏和平均时间复杂度为 $O(n^2)$,其中 $n$ 是数组的长度。在最佳情况下(当数组已经是排好序的),时间复杂度为 $O(n)$。这是因为只需要遍历一遍,如果没有进行任何交换,就可以提前结束排序。

实现冒泡排序

下面是用 Python 实现的冒泡排序算法的示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def bubble_sort(arr):
n = len(arr)
for i in range(n):
# 标记是否进行了交换
swapped = False
for j in range(0, n-i-1):
# 比较相邻的元素
if arr[j] > arr[j+1]:
# 交换元素
arr[j], arr[j+1] = arr[j+1], arr[j]
swapped = True
# 如果没有进行交换,数组已经排好序,提前退出
if not swapped:
break
return arr

# 测试冒泡排序
sample_array = [64, 34, 25, 12, 22, 11, 90]
sorted_array = bubble_sort(sample_array)
print("排序后的数组:", sorted_array)

代码解析

  1. 通过 len(arr) 获取数组的长度,确定需要的遍历次数。
  2. 外层循环用于控制排序的轮数;内层循环用于逐对比较相邻元素。
  3. swapped 变量用于优化,当某一轮没有进行交换时,说明数组已经有序,可以提前结束排序过程。
  4. 最后返回排序后的数组。

案例分析

让我们来分析一下上面的示例代码:

  • 初始数组为 [64, 34, 25, 12, 22, 11, 90]
  • 第一轮比较后数组状态:
    • [34, 25, 12, 22, 11, 64, 90] (64与34交换)
    • [25, 12, 22, 11, 34, 64, 90] (34与25交换)
    • [12, 22, 11, 25, 34, 64, 90] (25与12交换)
    • [12, 11, 22, 25, 34, 64, 90] (22与11交换)
    • [11, 12, 22, 25, 34, 64, 90] (11与12交换)
    • 最后,90已经是最大的元素,所以下一轮比较会略过。

经过数轮的比较与交换,最终得到排序后的数组为 [11, 12, 22, 25, 34, 64, 90]

结语

今天我们学习了冒泡排序这一基本的排序算法,通过简单的示例和代码实现,掌握了其基本思想和实现方式。冒泡排序简单易懂,但在大型数据集上效率较低,常常在实际应用中用更高效的排序算法替代。在下一篇文章中,我们将继续深入探索另一个简单的查找算法。

希望大家在实际编程中多多练习,熟悉排序算法的实现方式。

分享转发

15 简单算法实践之实现一个查找算法

在上一篇教程中,我们探讨了简单的排序算法,例如冒泡排序、选择排序等。在这一篇中,我们将关注于查找算法,特别是如何实现一个简单的查找算法。查找算法的主要目标是从一组数据中寻找特定值的位置或确认该值是否存在。

1. 查找算法简介

查找算法通常分为两大类:线性查找二分查找。我们将重点介绍线性查找,因为它简单易懂,适合初学者。

1.1 线性查找

线性查找(也被称为串行查找)是一种简单的查找方法。它的思路是从数据集合的第一个元素开始,逐个检查每个元素,直到找到目标元素或检查完所有元素。

1.1.1 算法步骤

  1. 从集合的第一个元素开始。
  2. 检查当前元素是否与目标值相等。
  3. 如果相等,则返回该元素的位置。
  4. 如果不相等,则检查下一个元素。
  5. 如果到达集合末尾仍未找到目标值,则返回“未找到”的提示。

2. 线性查找的实现

接下来,我们用Python语言实现一个简单的线性查找算法。

2.1 代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def linear_search(arr, target):
"""
线性查找算法
:param arr: 要查找的元素集合
:param target: 目标值
:return: 目标值的位置或未找到的提示
"""
for index in range(len(arr)):
if arr[index] == target:
return f"目标值 {target} 在位置 {index}"
return f"未找到目标值 {target}"

# 示例
numbers = [4, 2, 7, 1, 3]
target_value = 7
result = linear_search(numbers, target_value)
print(result)

2.2 示例解析

在上面的代码示例中,我们定义了一个名为 linear_search 的函数,该函数接受一个列表 arr 和一个目标值 target 作为参数。这个函数会遍历整个列表,检查每个元素是否等于目标值,并返回其位置,或者在未找到时返回相应消息。

如果我们用 numbers = [4, 2, 7, 1, 3] 作为待查找的数组,目标值为 7,函数会返回 目标值 7 在位置 2。如果我们将目标值更改为 5,则会返回 未找到目标值 5

3. 线性查找的复杂度

线性查找的时间复杂度为 $O(n)$,其中 $n$ 是数据集合的元素个数。这意味着在最坏的情况下,查找的效率随着元素数量的增加而线性增长。

4. 小结

在这一篇中,我们实现了一个简单的线性查找算法,掌握了如何遍历列表并查找元素的位置。此技术非常基础,但它在许多情况下仍然是十分有效的。

在下一篇教程中,我们将进行一个简单的项目作业,通过实际案例将前面学习的算法应用于解决真实问题。希望大家已准备好,将会结合我们之前学习的排序和查找算法,完成一个有趣的编程项目!

分享转发

16 简单算法实践之实现一个排序算法

在上一篇中,我们探讨了如何实现一个简单的查找算法。此次,我们将继续深入学习,实践一个常见的排序算法:冒泡排序。通过这一算法,我们将了解如何对一组数字进行排序,同时加深对算法运作机制的理解。

冒泡排序简介

冒泡排序是一种简单的排序算法。它的基本概念是通过反复比较相邻的元素,将较大的元素逐渐“冒泡”到数组的末尾。虽然冒泡排序的效率相对较低,尤其在处理大数据时,但它是算法教学中的经典例子,能够帮助我们理解排序的基本思想。

工作原理

冒泡排序的基本步骤如下:

  1. 从数组的第一个元素开始,比较相邻的两个元素。
  2. 如果前一个元素大于后一个元素,则交换这两个元素。
  3. 重复步骤1和步骤2,直至数组末尾。
  4. 针对每一个遍历,最大的元素将被“冒泡”到末尾。
  5. 对剩余的部分重复以上步骤,直到整个数组有序。

在伪代码中,冒泡排序可以表示为:

1
2
3
4
for i from 0 to n-1:
for j from 0 to n-i-1:
if arr[j] > arr[j+1]:
swap(arr[j], arr[j+1])

其中,n 是数组的长度,arr 是需要排序的数组。

实际案例

让我们通过一个具体的例子来演示冒泡排序的工作流程。

假设我们有一个数组:

1
arr = [64, 34, 25, 12, 22, 11, 90]

我们希望对这个数组进行升序排序。按照冒泡排序的算法步骤,我们将进行如下操作:

  1. 第一轮:

    • 比较 64 和 34 → 交换,数组变为 [34, 64, 25, 12, 22, 11, 90]
    • 比较 64 和 25 → 交换,数组变为 [34, 25, 64, 12, 22, 11, 90]
    • 比较 64 和 12 → 交换,数组变为 [34, 25, 12, 64, 22, 11, 90]
    • 比较 64 和 22 → 交换,数组变为 [34, 25, 12, 22, 64, 11, 90]
    • 比较 64 和 11 → 交换,数组变为 [34, 25, 12, 22, 11, 64, 90]
    • 比较 64 和 90 → 不交换,保持不变。

    第一轮后,最大的元素 90 被放在了最后。

  2. 第二轮:

    • 同样的过程,将未排序部分 [34, 25, 12, 22, 11, 64] 进行比较和交换。

经过几轮后,我们的数组将逐步变为:

1
[11, 12, 22, 25, 34, 64, 90]

代码实现

下面是使用 Python 编写的冒泡排序实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def bubble_sort(arr):
n = len(arr)
for i in range(n):
# 在每一轮中,设置一个标志位
swapped = False
for j in range(0, n-i-1):
if arr[j] > arr[j+1]:
arr[j], arr[j+1] = arr[j+1], arr[j] # 交换
swapped = True
# 如果没有元素交换,说明数组已经有序
if not swapped:
break

# 示例
arr = [64, 34, 25, 12, 22, 11, 90]
bubble_sort(arr)
print("排序后的数组:", arr)

在上述代码中,我们定义了一个函数 bubble_sort,输入是一个待排序的数组 arr。我们引入了一个标志位 swapped,以优化算法——如果在某一轮中没有进行任何交换,则说明数组已然有序,提前结束排序。

小结

在本篇中,我们实现了一个简单但经典的排序算法——冒泡排序。通过代码示例和具体案例,我们了解了该算法的工作机制和具体实现。冒泡排序适合小规模数据的排序学习,但在实际应用中,我们往往会使用更高效的排序算法。

在下一篇中,我们将介绍另一个常见的排序算法:选择排序,并进行更深入的分析与实现。希望通过这些系列教程,能够帮助算法小白们逐步掌握和应用基本的算法知识。

分享转发