数据结构 - 算法效率|时间复杂度|空间复杂度

目录

1.算法效率

2.时间复杂度

2.1定义

2.2大O渐近表示法

2.3常见时间复杂度计算举例

3.空间复杂度

3.1定义

3.2常见空间复杂度计算举例


1.算法效率

算法的效率常用算法复杂度来衡量,算法复杂度描述了算法在输入数据规模变化时,其运行时间和空间占用情况的变化趋势。

算法在编写成可执行程序后,运行时需要耗费时间资源和空间(内存)资源,所以我们常从时间和空间两个维度来评判算法的好坏,即时间复杂度和空间复杂度。

在计算机诞生之初,储存容量很小,所以对于空间很是在意,但随着计算机行业的迅速发展,计算机的存储容量已经达到了很高的程度,所以我们如今已经不需要再特别关注一个算法的空间复杂度。

2.时间复杂度

2.1定义

时间复杂度是衡量算法执行所需时间的指标,表示算法执行时间随输入规模增加而增长的速度。

在计算机科学中,算法的时间复杂度是一个函数,它定量描述了该算法的运行时间。一个算法执行所耗费的时间,从理论上说,是不能算出来的,只有我们把的程序放在机器上跑起来,才能知道。但是我们需要每个算法都上机测试吗?是可以都上机测试,但是这很麻烦,所以才有了时间复杂度这个分析方式。

一个算法所花费的时间与其中语句的执行次数成正比例,算法中的基本操作的执行次数,为算法的时间复杂度。

2.2大O渐近表示法

大O渐近表示法是一种用于描述算法时间复杂度的符号表示方法。它表示算法的最坏情况下执行时间的上界。在大O表示法中,O后面跟着一个函数,表示该函数的增长率与输入规模的关系。

大O渐近表示法的推导:

  1.   用常数1取代运行时间中的所有加法常数。
  2.   在修改后的运行次数函数中,只保留最高阶项。
  3.   如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。

大O的渐进表示法去掉了那些对结果影响不大的项,简洁明了的表示出了执行次数。 

下面以一段代码介绍大O渐近表示法的推导:

#include<stdio.h>
void Func1(int N)
{
	int count = 0;
	for (int i = 0; i < N; ++i)
	{
		for (int j = 0; j < 2 * N; ++j)
		{
			++count;
		}
	}

	for (int k = 0; k < 2 * N; ++k)
	{
		++count;
	}
	int M = 10;
	while (M--)
	{
		++count;
	}

	printf("%d\n", count);
}

int main()
{
	Func1(5);

	return 0;
}

可以看出

F(N) = N * (2 * N) + 2 * N + 10

首先我们用常数1取代运行时间中的所有加法常数:

F(N) = N * (2 * N) + 2 * N + 1

然后保留最高阶项:

 F(N) = 2 * N^2

如果最高阶项存在且不是1,则去除与这个项目相乘的常数:

 F(N) = N^2

即:

O(N^2) 

2.3常见时间复杂度计算举例

void Func1(int N, int M)
{
 int count = 0;
 for (int k = 0; k < M; ++ k)
 {
 ++count;
 }
 for (int k = 0; k < N ; ++ k)
 {
 ++count;
 }
 printf("%d\n", count);
}

时间复杂度:O(M + N) 


 

void Func2(int N)
{
 int count = 0;
 for (int k = 0; k < 100; ++ k)
 {
 ++count;
 }
 printf("%d\n", count);
}

时间复杂度:O(1)


 

void bubbleSort(int arr[], int n) 
{
    int i, j, temp;
    for (i = 0; i < n-1; i++) {
        for (j = 0; j < n-i-1; j++) {
            if (arr[j] > arr[j+1]) {
                temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
}

对于长度为n的数组,冒泡排序的最坏情况时间复杂度为O(n^2)。这是因为在最坏情况下,需要进行n-1轮比较和交换,每轮最多需要进行n-1次比较和交换操作。

在最好情况下,即输入数组已经是有序的,冒泡排序只需要进行一次遍历,即O(n)的时间复杂度

所以它的大O渐近表示法:

O(N^2) 


 

int BinarySearch(int* a, int n, int x)
{
	assert(a);
	int begin = 0;
	int end = n - 1;
	while (begin < end)
	{
		int mid = begin + ((end - begin) >> 1);
		if (a[mid] < x)
			begin = mid + 1;
		else if (a[mid] > x)
			end = mid;
		else
			return mid;
	}
	return -1;
}

二分查找的时间复杂度为 O(\log_{2}N) ,因为每一次迭代都会将查找范围减半。因此,总的查找时间取决于进行了多少次这样的迭代。由于每次迭代都将查找范围减半,所以查找时间以对数的方式增长,即时间复杂度为 O(\log_{2}N)


 

long long Fac(size_t N)
{
	if (0 == N)
		return 1;

	return Fac(N - 1) * N;
}

每次调用函数 Fac(N),都会产生一个新的函数调用 Fac(N - 1),直到 N 减小到 0 为止。因此,这个递归树的深度为 N。在每一层递归中,都会进行一次乘法运算。

因此,这个递归函数的时间复杂度为 O(N)


 

long long Fib(size_t N)
{
	if (N < 3)
		return 1;

	return Fib(N - 1) + Fib(N - 2);
}

要计算这个递归函数的时间复杂度,可以使用递归树的方法来分析(如下图)。在递归树中,每个节点代表一次函数调用,树的高度表示递归的深度,而每层的节点数表示每次递归调用的次数。

对于斐波那契数列的递归函数,由于每次调用会分解为两个子问题(计算第N-1项和第N-2项),因此递归树的分支数是2且每个节点的时间复杂度都是O(1),因为每次递归调用都只涉及一次加法运算。递归的深度为N。

因此,这个递归函数的时间复杂度是 O(2^N),因为递归树的分支数是2,且深度为N。

 

3.空间复杂度

3.1定义

空间复杂度也是一个数学表达式,是对一个算法在运行过程中临时开辟的额外占用存储空间大小的量度 。

‘额外’的解释:函数运行时所需要的栈空间(存储参数、局部变量、一些寄存器信息等)在编译期间已经确定好了,此空间复杂度主要通过函数在运行时候显式申请的额外空间来确定。

空间复杂度不是用程序占用了多少字节的空间来衡量,因为这样意义不大,空间复杂度算的是变量的个数。 空间复杂度计算规则基本跟时间复杂度类似,也使用大O渐进表示法

3.2常见空间复杂度计算举例

long long Fac(size_t N)
{
	if (N == 0)
		return 1;

	return Fac(N - 1) * N;
}

递归函数的空间复杂度取决于递归调用的深度。每次递归调用都会在内存中创建一个新的函数调用帧(包含函数的参数、局部变量等信息)。由于递归调用的次数与输入参数 N 的大小成正比,因此空间复杂度为 O(N)。


long long Fib(size_t N)
{
	if (N < 3)
		return 1;

	return Fib(N - 1) + Fib(N - 2);
}

这个斐波那契函数的时间复杂度我们已经计算过为O(2^N),那么它的空间复杂度也为 O(2^N) 吗?

先说结论,斐波那契函数的空间复杂度为O(N)。

这与函数的调用有关,要知道在函数调用时不是Fib(N - 1) 和 Fib(N - 2)一起调用的,而是调用Fib(N - 1) --> Fib(N - 2) --> ....... Fib(2)这样一层一层的调用的,每次调完上一层对的函数栈帧就已经销毁了。

所以:时间是一去不复返的,而空间是可以重复利用的。

函数栈帧详细信息见:

https://blog.csdn.net/BuiderCodes/article/details/136876577icon-default.png?t=N7T8https://blog.csdn.net/BuiderCodes/article/details/136876577

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/503267.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

路径规划——搜索算法详解(五):Dynamic A Star(D*)算法详解与Matlab代码

昨天休息了一天&#xff0c;今天继续学习搜索算法&#xff01;前几天已经分别介绍了Dijkstra算法、Floyd算法、RRT算法、A*算法&#xff0c;无独有偶&#xff0c;上述算法都只适用于静态环境下两点规划的场景&#xff0c;但是大部分场景是实时变化的&#xff0c;这对规划算法提…

阿里云4核8G服务器ECS u1实例租用优惠价格955元一年

阿里云4核8G服务器优惠价格955元一年&#xff0c;配置为ECS通用算力型u1实例&#xff08;ecs.u1-c1m2.xlarge&#xff09;4核8G配置、1M到3M带宽可选、ESSD Entry系统盘20G到40G可选&#xff0c;CPU采用Intel(R) Xeon(R) Platinum处理器&#xff0c;阿里云活动链接 aliyunfuwuq…

手写红黑树【数据结构】

手写红黑树【数据结构】 前言版权推荐手写红黑树一、理论知识红黑树的特征增加删除 二、手写代码初始-树结点初始-红黑树初始-遍历初始-判断红黑树是否有效查找增加-1.父为黑&#xff0c;直接插入增加-2. 父叔为红&#xff0c;颜色调换增加-3. 父红叔黑&#xff0c;颜色调换&am…

相机标定学习记录

相机标定是计算机视觉和机器视觉领域中的一项基本技术&#xff0c;它的主要目的是通过获取相机的内部参数&#xff08;内参&#xff09;和外部参数&#xff08;外参&#xff09;&#xff0c;以及镜头畸变参数&#xff0c;建立起现实世界中的点与相机成像平面上对应像素点之间准…

WPF中继承ItemsControl子类控件数据模板获取选中属性

需求场景 列表类控件&#xff0c;如 ListBox、ListView、DataGrid等。显示的行数据中&#xff0c;部分内容依靠选中时触发控制&#xff0c;例如选中行时行记录复选&#xff0c;部分列内容控制显隐。 案例源码以ListView 为例。 Xaml 部分 <ListView ItemsSource"{Bi…

【Node.js】图片验证码识别

现在越来越多的网站采取图片验证码&#xff0c;防止机器恶意向服务端发送请求。但是常规的图片验证码也不是非常安全了。有非常多第三方库可以对图片上的数字文字等进行识别。 代码实现 首先安装依赖&#xff1a; npm install node-native-ocrnpm&#xff1a;(node-native-oc…

HCIA网络基础11-静态路由

文章目录 自治系统LAN和广播域路由选择路由表数据包转发最长匹配原则路由优先级路由度量静态路由配置静态路由负载分担路由备份缺省路由 以太网交换机工作在数据链路层&#xff0c;用于在网络内进行数据转发。而企业网络的拓扑结构一般会比较复杂&#xff0c;不同的部门&#x…

Mistral 7B v0.2 基础模型开源,大模型微调实践来了

Mistral AI在3月24日突然发布并开源了 Mistral 7B v0.2模型&#xff0c;有如下几个特点&#xff1a; 和上一代Mistral v0.1版本相比&#xff0c;上下文窗口长度从8k提升到32k&#xff0c;上下文窗口&#xff08;context window&#xff09;是指语言模型在进行预测或生成文本时&…

设计模式6--抽象工厂模式

定义 案例一 案例二 优缺点

重新温习广软puthon爬虫技术。

下面是我不断试错的一个过程&#xff0c;好多知识点全忘记了&#xff0c;只能不断调实例&#xff0c;不断优化&#xff0c;重构&#xff0c;实现自己的需求。下面是我的运行截图。还是导包的问题。 个人感觉关键的还是这几部&#xff0c;被划了下划线的&#xff0c;存在问题&a…

最优算法100例之17- 环形连续子数组的最大和

专栏主页:计算机专业基础知识总结(适用于期末复习考研刷题求职面试)系列文章https://blog.csdn.net/seeker1994/category_12585732.html 题目描述 给定一个长度为 nn 的环形整数数组,请你求出该数组的 非空 连续子数组 的最大可能和 。 环形数组 意味着数组的末端将会与开…

设计模式9--单例模式

定义 案例一 案例二 优缺点

Windows中忘记MySQL ROOT密码的解决方法

在需要ROOT身份登录MySQL但又忘记密码时&#xff0c;可以先已管理员身份运行cmd命令窗口,输入以下命令停止MySQL服务 net stop mysql 随后cd到MySQL安装目录下的bin目录下 D: //我的安装在D盘 cd D:\MySQL\bin 使用跳过权限验证的方式起启动MySQL mysqld --console --skip-g…

从零开始机器学习(机器学习 监督学习之线性回归 损失函数及可视化 梯度下降 线性回归的平方误差损失函数 lab实验)

文章目录 机器学习定义监督学习之线性回归损失函数及可视化梯度下降线性回归的平方误差损失函数lab实验 机器学习定义 机器学习就是机器通过不断训练数据集从逐渐知道正确的结果 机器学习包括监督学习和非监督学习 监督学习&#xff1a;需要输入数据和结果数据来不断训练学习…

大数据面试专题 -- kafka

1、什么是消息队列&#xff1f; 是一个用于存放数据的组件&#xff0c;用于系统之间或者是模块之间的消息传递。 2、消息队列的应用场景&#xff1f; 主要是用于模块之间的解耦合、异步处理、日志处理、流量削峰 3、什么是kafka&#xff1f; kafka是一种基于订阅发布模式的…

Linux 著名的sudo、su是什么?怎么用?

一、su 什么是su&#xff1f; su命令&#xff08;简称是&#xff1a;substitute 或者 switch user &#xff09;用于切换到另一个用户&#xff0c;没有指定用户名&#xff0c;则默认情况下将以root用户登录。 为了向后兼容&#xff0c;su默认不改变当前目录&#xff0c;只设…

专升本-云计算

被誉为第三次信息技术革命 什么是云计算&#xff1f; 云计算是一种商业的计算模式&#xff0c;它将任务分布在大量计算机构成的资源池上&#xff0c;用户可以按需通过网络存储空间&#xff0c;计算能力和信息等服务 云计算的产生和发展&#xff1a; 起源&#xff1a;上世纪6…

【力扣刷题日记】1173.即时食物配送I

前言 练习sql语句&#xff0c;所有题目来自于力扣&#xff08;https://leetcode.cn/problemset/database/&#xff09;的免费数据库练习题。 今日题目&#xff1a; 1173.即时食物配送I 表&#xff1a;Delivery 列名类型delivery_idintcustomer_idintorder_datedatecustomer…

Qt使用opencv打开摄像头

1.效果图 2.代码 #include "widget.h"#include <QApplication>#include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp>#include <QImage> #include <QLabel> #incl…

实现 Element UI el-table 树形数据的懒加载

当面对大量数据时&#xff0c;一次性加载所有数据可能会导致性能问题。为了解决这一问题&#xff0c;我们可以实现树形数据的懒加载。本文将介绍如何在使用 Element UI 的 Vue 应用中为 el-table 组件的树形数据添加懒加载功能。 懒加载的基本概念 懒加载是一种优化网页或应用…