【数据结构】时间复杂度和空间复杂度解析

数据结构前言:

1. 什么是数据结构

打个比方来说不同的数据就相当于不同的书籍,我们经常在图书馆可以看到不同类别的书籍会被整理放在书架上方便查看存放,数据结构就是一种计算机存储管理数据的方式。

2. 什么是算法

算法就是一系列的计算步骤,将我们输入的需要计算的数据转化成输出的结果

算法的时间复杂度和空间复杂度:

1. 为什么要计算算法的时间复杂度和空间复杂度

时间复杂度和空间复杂度可以反应一个算法的好坏,好的算法执行能力强,快;差的算法执行能力弱,慢。比如我们打开一个应用的界面,你一打开就进入了首页,还有种情况你打开等了半天还是在封面广告界面,我相信大多数用户都喜欢前者,算法也是如此,好算法计算机1ms就执行出结果,坏的算法往往执行半天,程序一直在跑,甚至于可能失败。

所以我们需要一些理论来衡量算法的优劣,时间复杂度和空间复杂度由此诞生。选择好的算法,往往在思考算法的过程中也可以锻炼我们的思维能力。

时间复杂度:

时间复杂度表面看起来好像跟时间有关,但其实不是计算算法跑了多少时间的,因为我们知道不同的电脑计算能力,跑程序有强弱之分,一个好的算法在老古董电脑上跑也需要很长的时间,所以为了防止这样的情况误差发生,我们的时间复杂度计算的是一个算法执行了多少次命令操作!

cpp 复制代码
如:

int main()
{
	int a =0;
	printf("%d", a);
	return 0;
}

从进入主函数内部我们总共执行了3次指令,我们称这样的时间复杂度为 O(1); -> 后面会解释为啥不是 O(3)

为了方便我们判断,我们只选取最大的执行项数,N^2, 以阶级区分,为什么怎么做呢?,首先我们先了解有多少种时间复杂度:

因为目前计算机的计算速度基本上都是以亿为单位的,当计算的数量上去之后,一些细枝末节就不予考虑了

拿 F(N) = N^2 + 2*N + 10 举例

当N=10时, F(N) =100+30
当N=100时, F(N) =10000+210
当N=1000时, F(N) =1000000+2010

我们称这种取舍的表示符号O() 为****大O的渐进表示法

时间复杂度计算的是最坏的情况,这样可以保证我们的效率最坏也就是那样,知道预期的结果。

cpp 复制代码
// 大家可以根据以下代码测试cpu性能
// 计算出自己计算机的计算能力

int main()
{
	long long int x = 0;

	int begin1 = clock();
	int n = 10000;
	for (int i = 0; i < n; ++i)
	{
		for (int i = 0; i < n; ++i)
		{
			++x;
		}
	}
	int end1 = clock();

	printf("%lld\n", x);
	printf("%d\n", end1 - begin1);
	return 0;
}

下面我们来个题目分析:

题目一:

题目二:

答案:O(N) -> 2*N+10

题目三:

cpp 复制代码
void Func1(int N)
{
	int count = 0;
	for (int i = 0; i < N; ++i)
	{
		for (int j = 0; j < N; ++j)
		{
			++count;
		}
	}
	for (int k = 0; k < 2 * N; ++k)
	{
		++count;
	}
	int M = 10;
	while (M--)
	{
		++count;
	}
    printf("%d\n", count);
}

答案:O(N^2) -> N^2+2*N+10

题目四:

cpp 复制代码
// 计算Func3的时间复杂度?
void Func3(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)

题目五:

cpp 复制代码
// 计算Func4的时间复杂度?
void Func4(int N)
{
	int count = 0;
	for (int k = 0; k < 100; ++k)
	{
		++count;
	}
	printf("%d\n", count);
}

答案: O(1) ->100

题目六:

cpp 复制代码
// 计算BubbleSort的时间复杂度?
void BubbleSort(int* a, int n)
{
	assert(a);
	for (size_t end = n; end > 0; --end)
	{
		int exchange = 0;
		for (size_t i = 1; i < end; ++i)
		{
			if (a[i - 1] > a[i])
			{
				Swap(&a[i - 1], &a[i]);
				exchange = 1;
			}
		}
		if (exchange == 0)
			break;
	}
}

答案:O(N^2) -> N*(N+1)/2

空间复杂度:

同理空间复杂度也不是去真的算空间的大小,而是计算创建了的变量个数。其他方面同理于时间复杂度。

题目一:

cpp 复制代码
// 计算BubbleSort的空间复杂度?
void BubbleSort(int* a, int n)
{
	assert(a);
	for (size_t end = n; end > 0; --end)
	{
		int exchange = 0;
		for (size_t i = 1; i < end; ++i)
		{
			if (a[i - 1] > a[i])
			{
				Swap(&a[i - 1], &a[i]);
				exchange = 1;
			}
		}
		if (exchange == 0)
			break;
	}
}

答案:题目一使用了常数个额外空间,所以空间复杂度为 O(1)

题目二:

cpp 复制代码
// 计算Fibonacci的空间复杂度?
// 返回斐波那契数列的前n项
long long* Fibonacci(size_t n)
{
	if (n == 0)
		return NULL;
	long long* fibArray = (long long*)malloc((n + 1) * sizeof(long long));
	fibArray[0] = 0;
	fibArray[1] = 1;
	for (int i = 2; i <= n; ++i)
	{
		fibArray[i] = fibArray[i - 1] + fibArray[i - 2];
	}
	return fibArray;
}

答案:题目二动态开辟了N个空间,空间复杂度为 O(N)

题目三:

cpp 复制代码
// 计算阶乘递归Fac的空间复杂度?
long long Fac(size_t N)
{
	if (N == 0)
		return 1;
	return Fac(N - 1) * N;
}

答案:题目三递归调用了N次,开辟了N个栈帧,每个栈帧使用了常数个空间。空间复杂度为O(N)

其他关于数据结构的题目分析:

以下的图片内容我小编平时写一些算法题目的思考,大家可以选取看取:

相关推荐
CSharp精选营2 天前
关系型 vs 非关系型:从原理到选型,一文搞定数据库核心分类
数据结构·nosql·关系型数据库·非关系型数据库·技术选型
刘马想放假5 天前
Modbus 全栈技术解析:TCP、RTU、ASCII、RTU over TCP
数据结构·网络协议
北域码匠6 天前
冒泡排序太慢?鸡尾酒排序双向优化,原生 C# 零第三方库完整代码
数据结构·排序算法·泛型·c# 算法·鸡尾酒排序·原生 c# 开发·冒泡排序优化·嵌入式算法
Darling噜啦啦13 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
小小工匠14 天前
Redis - 事务机制:能实现 ACID 属性吗
数据结构·redis·性能优化·并发·持久化
玖玥拾14 天前
C/C++ 数据结构(七)栈、容器适配器
c语言·数据结构·c++··容器适配器
Qres82114 天前
算法复键——树状数组
数据结构·算法
牛油果子哥q14 天前
并查集(DSU)超精讲,路径压缩、按秩合并、万能模板、连通性判定、最小生成树与刷题实战全解
数据结构·c++·最小生成树·并查集
凌波粒14 天前
LeetCode--491.递增子序列(回溯算法)
数据结构·算法·leetcode
WL学习笔记14 天前
单项不带头不循环链表
数据结构·链表