【数据结构】复杂度的重要性—–决定程序运行的效率

ops/2024/9/24 15:39:17/

数据结构】复杂度的重要性—–决定程序运行的效率

前言

在我们写算法的时候,常常会需要考虑一个问题:这个算法好不好?而这个“好”实际上就取决于是算法的复杂度。

在这里插入图片描述

算法复杂度Algorithmic Complexity)是指算法在编写成可执行程序后,运行时所需要的资源,资源包括时间资源和内存资源。应用于数学和计算机导论。

我们知道,同一个问题可以使用不同的算法来解决,而这里的不同一般来说也是可以从复杂度来看出的,当然,也不排除有相同复杂度但不同写法的算法,这里只作参考。

一个算法的好坏影响到了很多实际性的问题,在程序中效率是极其重要的,一个算法的评价主要从时间复杂度和空间复杂度来考虑。

在介绍这两个复杂度之前,我们需要了解一个概念:复杂度并不是具体的数值或者是大小表示,它实际上是一个量级的概念

比如O(n)和O(n+1)。很明显,它们是同一个量级,只差了1,那么它们实际上可以写成同一个,也就是O(n),甚至像O(2n),它和上面两者也是同一个量级;但是,像O(n)和O(n^2),这俩实际上并不属于同一个量级。它们之间隔了一个次方,那么就有可能存在大小的很大差距,所以这两个复杂度是两个不同的个体。

接下来对这两个复杂度进行具体介绍。

时间复杂度

基本定义和理解

时间复杂度衡量的是算法运行时间随输入规模的增长情况。

对于算法的运行时间,在实际中,由于每台计算机的硬件和软件环境的不同,往往不能精确计算执行所需时间。所以我们在讨论时间复杂度的时候,仅仅从理论角度,也就是视作计算机的环境不变,来进行讨论。

影响算法时间代价的具体有两个方面:问题规模语句频度

A.问题规模算法求解问题输入量的多少,是问题大小的本质表示,一般用整数n表示。

B.语句频度是一条语句的重复执行次数。一般来说,这个次数会用一个函数来表示,而这个函数代表着算法执行时间的增长率算法执行时间的增长率称作渐进时间复杂度,也就简称为时间复杂度

时间复杂度通常使用O(n)来表示,算法的复杂度存在最好、最坏等情况,那么在这里我们取算法的最坏运行情况作为O(n)

在我们进行时间复杂度的解答时,实际上不需要这么复杂的解释。我们可以将其总结为一句话:

只分析算法中最耗时的操作。

由于我们考虑的是算法的最坏运行情况,并且是以量级来计算,那么我们实际上只需要分析算法中最耗时的操作即可。

分析步骤

1.确定输入规模 (n):输入规模通常是算法中主要变量的数量,例如数组的长度。

2.识别基本操作:确定算法中最耗时的操作,其他比较繁琐、或者特殊的语句忽视。

3.分析每部分的操作次数:计算基本操作在不同结构中的次数,例如循环、递归。

4.累加所有部分的操作次数:将各部分的操作次数加起来,得到总操作次数。

5.用大O符号表示:忽略常数和低阶项,提取时间复杂度的主要部分。这里的目的实际上就是统一量级。

使用这样的步骤,我们就可以较好地解决时间复杂度的分析了。

举例

示例1:简单循环

def sum_array(arr):total = 0for i in range(len(arr)):total += arr[i]return total

步骤1:确定输入规模

输入是数组 arr,其长度为 n

步骤2:识别基本操作

基本操作是加法 total += arr[i]

步骤3:分析每部分的操作次数

  • total = 0:1 次
  • for i in range(len(arr)):循环执行 n
  • total += arr[i]:循环体内执行 n

步骤4:累加所有部分的操作次数

总操作次数为 1+n+n=1+2n1 + n + n = 1 + 2n1+n+n=1+2n。

步骤5:用大O符号表示

忽略常数项和系数,时间复杂度为 O(n)。

示例2:嵌套循环

def bubble_sort(arr):n = len(arr)for i in range(n):for j in range(0, n-i-1):if arr[j] > arr[j+1]:arr[j], arr[j+1] = arr[j+1], arr[j]

步骤1:确定输入规模

输入是数组 arr,其长度为 n

步骤2:识别基本操作

基本操作是比较和交换 if arr[j] > arr[j+1]arr[j], arr[j+1] = arr[j+1], arr[j]

步骤3:分析每部分的操作次数

步骤4:累加所有部分的操作次数

分析这里的操作次数,我们可以使用更为简单的方法,请注意,这里的for循环中还嵌套了一个for循环,那么我们可以理解为:在进行大循环的时候,也会进行一次小循环,而小循环中的语句会进行n次,那么就是O(n);而大循环会进行n次小循环,那么总的时间复杂度就是O(n*n)也就是O(n^2)。

注意:遇见嵌套类的题目,我们都这样计算:嵌套中有几个循环,就是n的几次方。

步骤5:用大O符号表示

忽略常数项和系数,时间复杂度为 O(n^2)。

示例3:二分查找

def binary_search(arr, target):left, right = 0, len(arr) - 1while left <= right:mid = (left + right) // 2if arr[mid] == target:return midelse if arr[mid] < target:left = mid + 1else:right = mid - 1return -1

步骤1:确定输入规模

输入是数组 arr,其长度为 n

步骤2:识别基本操作

基本操作是比较 arr[mid] == target

步骤3:分析每部分的操作次数

  • left, right = 0, len(arr) - 1:1 次
  • while left <= right:循环次数由 leftright 的变化决定,每次循环减半,最多执行log2(n)次。

步骤4:累加所有部分的操作次数

总操作次数为 1+log2(n)

步骤5:用大O符号表示

忽略常数项和低阶项,时间复杂度为 O(log n)。

经过以上的介绍和举例,相信各位已经能够游刃有余地解决时间复杂度的问题了。

空间复杂度

基本定义和理解

与时间复杂度类似,空间复杂度是指算法在计算机内执行时所需存储空间的度量。当我们需要区别算法时,我们应该看到的是每个算法的不同处,由于输入的初始数据所占的存储空间是已经确定的,那么在计算空间复杂度时,我们往往只分析执行过程中所需要额外的存储空间大小。

分析步骤

1.确定输入规模 (n):输入规模通常是算法中主要变量的数量,例如数组的长度。

2.识别存储需求:确定算法中每个变量和数据结构所需的存储空间。

3.分析每部分的存储空间需求:计算不同部分占用的空间,如局部变量、数组、递归调用栈等。

4.累加所有部分的存储空间需求:将各部分的存储空间加起来,得到总的空间需求。

5.用大O符号表示:忽略常数和低阶项,提取空间复杂度的主要部分。

举例

示例1:简单循环

def sum_array(arr):total = 0for i in range(len(arr)):total += arr[i]return total

步骤1:确定输入规模

输入是数组 arr,其长度为 n

步骤2:识别存储需求

  • arr:长度为 n,空间需求为 O(n)
  • total:一个整数,空间需求为 O(1)
  • i:一个整数,空间需求为 O(1)

步骤3:分析每部分的存储空间需求

  • arr:O(n)
  • total:O(1)
  • i:O(1)

步骤4:累加所有部分的存储空间需求

总空间需求为 O(n)+O(1)+O(1)=O(n)。

步骤5:用大O符号表示

忽略常数项和低阶项,空间复杂度为 O(n)。

示例2:递归函数

def factorial(n):if n == 0:return 1else:return n * factorial(n-1)

步骤1:确定输入规模

输入是整数 n

步骤2:识别存储需求

  • 递归调用栈:每次递归调用会占用栈空间。

步骤3:分析每部分的存储空间需求

  • 每次递归调用占用 O(1) 空间,最多递归调用 n 次。

步骤4:累加所有部分的存储空间需求

总空间需求为 O(1)∗n=O(n)。

步骤5:用大O符号表示

忽略常数项和低阶项,空间复杂度为 O(n)。

示例3:使用辅助数组

def merge_sort(arr):if len(arr) > 1:mid = len(arr) // 2L = arr[:mid]R = arr[mid:]merge_sort(L)merge_sort(R)i = j = k = 0while i < len(L) and j < len(R):if L[i] < R[j]:arr[k] = L[i]i += 1else:arr[k] = R[j]j += 1k += 1while i < len(L):arr[k] = L[i]i += 1k += 1while j < len(R):arr[k] = R[j]j += 1k += 1

步骤1:确定输入规模

输入是数组 arr,其长度为 n

步骤2:识别存储需求

  • arr:长度为 n,空间需求为 O(n)
  • 辅助数组 LR:总长度为 n,空间需求为 O(n)

步骤3:分析每部分的存储空间需求

  • arr:O(n)
  • 辅助数组 LR:O(n)
  • 局部变量 i, j, k, mid:O(1)

步骤4:累加所有部分的存储空间需求

总空间需求为 O(n)+O(n)+O(1)=2O(n)+O(1)=O(n)。

步骤5:用大O符号表示

忽略常数项和低阶项,空间复杂度为 O(n)。

注意:在空间复杂度的计算中,大部分都是O(n)和O(1),这两个复杂度是最为常见的。

如何理解和应用复杂度分析

理解复杂度分析的核心是**能够评估算法在最坏、最好和平均情况下的性能。**这有助于我们在开发过程中选择最合适的算法数据结构以确保程序的高效运行。

算法的高效性往往在算法指标中占据较高位置,所以只要我们使得复杂度越,高效性越,那么算法也就会越

的存储空间需求**

总空间需求为 O(n)+O(n)+O(1)=2O(n)+O(1)=O(n)。

步骤5:用大O符号表示

忽略常数项和低阶项,空间复杂度为 O(n)。

注意:在空间复杂度的计算中,大部分都是O(n)和O(1),这两个复杂度是最为常见的。

如何理解和应用复杂度分析

理解复杂度分析的核心是**能够评估算法在最坏、最好和平均情况下的性能。**这有助于我们在开发过程中选择最合适的算法数据结构以确保程序的高效运行。

算法的高效性往往在算法指标中占据较高位置,所以只要我们使得复杂度越,高效性越,那么算法也就会越


http://www.ppmy.cn/ops/46726.html

相关文章

植物大战僵尸杂交版破解C++实现

文章目录 前言准备工作&#xff1a;基地址与偏移UI界面设计和绑定项目模板总览图生成与实现信号处理1、阳光值更新:BTN12、三种钱币值更新:BTN2-BTN43、冷却刷新:BTN54、锁定阳光&#xff1a;check15、无冷却&#xff1a;check26、OnTimer&#xff08;&#xff09;和OnClose&am…

埃及媒体分发投放-新闻媒体通稿发布

埃及商业新闻 大舍传媒近日宣布将在埃及商业新闻领域展开新的媒体分发投放。作为埃及最具影响力的商业新闻平台之一&#xff0c;埃及商业新闻将为大舍传媒提供广阔的市场和受众群体。这一合作意味着大舍传媒将有机会通过埃及商业新闻的平台向埃及的商业精英和投资者传递最新的…

文件系统小册(FusePosixK8s csi)【1 Fuse】

文件系统小册&#xff08;Fuse&Posix&K8s csi&#xff09;【1 Fuse&#xff1a;用户空间的文件系统】 Fuse(filesystem in userspace),是一个用户空间的文件系统。通过fuse内核模块的支持&#xff0c;开发者只需要根据fuse提供的接口实现具体的文件操作就可以实现一个文…

利用人工智能实现量子计算

转载自&#xff1a;利用人工智能实现量子计算 2024年 5月 12日 By Mark Wolf https://developer.nvidia.com/zh-cn/blog/enabling-quantum-computing-with-ai/ 文章目录 一、概述二、改进量子处理器三、校正噪声量子位的误差四、开发高效的量子算法五、探索量子计算的人工智能 …

k8s-mysql主从部署

一.环境信息 mysql版本 :8.0 k8s 版本1.22 使用nfs作为共享存储 二.配置mysql主节点yaml apiVersion: v1 kind: ConfigMap metadata:name: mysql-master-confignamespace: mysqllabels:app: mysql-master-config data:my.cnf: |[client]default-character-setutf8[mysql]d…

动态SQL IF语句

IF语句学习 第一种写法(标准) 我们先来看以下标准写法: select * from .. <where> <if test""> and ....... <if test""> and ....... <where> 我们用了一个where标签 , 内嵌if语句 第二种写法: 这是第二种写法:不用where标…

哪款充电宝性价比高值得买?2024年性价比高充电宝排行榜

在如今移动电源市场琳琅满目的品牌和产品中&#xff0c;选择一款适合自己的充电宝成为消费者关注的焦点。面对众多品牌和种类繁多的充电宝&#xff0c;消费者如何做出明智的选择&#xff1f;本文将为大家揭示如何选择高品质的充电宝&#xff0c;避免劣质电池和虚假参数的风险。…

Python深度学习:【模型系列】Transformer面试灵魂20问

1. transformer简介 Transformer模型是一种基于自注意力机制的神经网络架构,主要用于处理序列数据,如自然语言处理任务。它由Google在2017年提出,并在“Attention is All You Need”这篇论文中首次公开。Transformer模型的核心思想是利用自注意力机制来捕捉序列中的依赖关系…