数据结构小知识------时间与空间复杂度

本章思维导图:

 一,时间复杂度

1.1时间复杂度的概念

🌐:什么是时间复杂度呢?时间复杂度其实就是一个程序运行时它的指令运行的次数

在这里,程序默认每条指令的运行时间是一样的。所以时间复杂度就可以理解为是程序内指令的运行次数。

说一千道一万,不如来个例子:

🌰:时间复杂度为O(n)

int main() {
	int i = 0;
	int n = 0;
	scanf("%d", &n);
	for (i = 0;i < n;i++) {
		printf("执行%d次\n", i+1);
	}
	return 0;
}

这个程序的时间复杂度便是O(n),这个程序的时间复杂度的计算其实就看for循环的执行次数,很明显for循环会执行n次,所以这个程序的时间复杂度是O(n)。

🌰:时间复杂度为O(n^2)

int main() {
	int i = 0;
	int j = 0;
	int n = 0;
	scanf("%d", &n);
	for (i = 1;i <= n;i++) {
		for (j = 1;j <= n;j++) {
			printf("执行了%d次\n", i * j);
		}
	}
	return 0;
}

这个程序的时间复杂度便是O(n^2),因为这个程序有两个for循环。当第一层循环计算一次时,第二层循环就要计算n次。所以当第二层循环计算了n次时整个程序就计算了n^2次。所以这个程序的时间复杂度是O(n^2)。

1.2时间复杂度的计算

🌐:细心的小伙伴一定会发现我在对时间复杂度进行描述的时候使用了O()的表示方法。这个表示方法其实就叫作大O表示法。在算法导论里面,大O表示法表示的就是算法在最坏的情况下的运行时间。

1.2.1:大O表示法的几个计算特点

1.只保留最高阶的项

🌐因为计算机的运算速度十分的快,所以在一个程序内可能只有最高阶的项可以影响它。所以在我们使用大O表示法的时候,就可以舍弃其它项只保留最高阶的项来对程序的运行速度进行表示。在这里也表明了大O表示法注定是一个估计的值而不是一个精确的值。

举个例子:🌰

int main() {
	int i = 0;
	int j = 0;
	int n = 0;
	scanf("%d", &n);
	for (i = 1;i <= n;i++) {
		printf("执行了%d次\n", i);
	}
	for (i = 1;i <= n;i++) {
		for (j = 1;j <= n;j++) {
			printf("执行了%d次\n", i * j);
		}
	}
	return 0;
}

在这里,很明显我写的这个程序的执行次数是n+n^2次。但是当我们用大O表示法的时候,我们是不会用O(n+n^2)来表示。我们用的还是用O(n^2)来表示。因为在使用大O表示法时我们只保留最高阶的项。在这里就是n^2。

2.常数次用O(1)表示

🌐在程序中,如果指令只使用了常数次的话,那我们就可以用O(1)来表示这个程序的时间复杂度。不管这个常数有多大它的时间复杂度都是O(1),这是因为计算机的运行速度实在是太快了。

 举个例子:🌰

int main() {
	int i = 0;
	for (i = 0;i < 5;i++) {
		printf("执行%d次\n", i);
	}
	return 0;
}

这个5是常数,所以这个for循环执行的次数是常数次。因此,这个代码的时间复杂度就是O(1)

int main() {
	int i = 0;
	for (i = 0;i < 50000000;i++) {
		printf("执行%d次\n", i);
	}
	return 0;
}

现在把5换成50000000,即使大小变大了很多。但是50000000还是一个常数,所以这个代码的时间复杂度还是O(1)。

3.大O表示法里的logn的底数是2 而不是10

🌐我们大多数的初学者可能已经习惯了logn的底数是10了,但是要时刻记住在计算机中logn的底数是2。

二,空间复杂度

2.1空间复杂度的概念

🌐什么是空间复杂度呢?空间复杂度就是一个算法在运行过程中占用内存空间的大小的度量。这个内存空间与执行文件的大小没有半毛钱的关系。也就是说时间复杂度与执行文件的大小没有关系。

 举个例子:

🌰

int main() {
	int i = 0;
	int n = 0;
	scanf("%d", &n);
	for (i = 0;i < n;i++) {
		printf("执行%d次\n", i+1);
	}
	return 0;
}

这个程序的空间复杂度便是O(1),因为这个程序创建的变量是可数的,只有2个。所以它的空间复杂度就是O(1)

int main() {
	int i = 0;
	int n = 0;
	scanf("%d", &n);
	int arr[] = { 0 };
	for (i = 0;i < n;i++) {
		arr[i] = i;
	}
	return 0;
}

 像这个代码的空间复杂度便是O(n)因为这个代码要开辟n个空间大小的数组,所以这个程序的空间复杂度就是O(n)。

 2.2空间复杂度的计算

空间复杂度的计算其实时间复杂度的计算差不多,只是计算的对象从时间变成了空间。

只要套用时间复杂度的计算方法,然后再将计算时间变成计算空间就可以了。

3.斐波那契数列的时间与空间复杂度的计算方法 

3.1斐波那契数列的介绍

 斐波那契数列又名兔子数列,像:1,1,2,3,5,8,13,21,34,55,89

这样的数列就是一个斐波那契数列。可以很明显的看出斐波那契数列的特点是从第三项开始,每一项都等于前两项的和。

现在我们来编写一个代码来求斐波那契数列的第n项的结果:

代码如下:

int Fib(int n) {
	if (n <= 0) {
		return 0;
	}
	else if (n == 1) {
		return 1;
	}
	else {
		return Fib(n - 1)+Fib(n-2);
	}

}
int main() {
	int n = 0;
	scanf("%d", &n);
	int ret = Fib(n);
	printf("%d\n", ret);
	return 0;
}

 这段代码确实容易写出来,但现在的问题是:这段代码的时间复杂度是多少呢?空间复杂度是多少呢?

3.1时间复杂度

要算时间复杂度,其实就是要算这个递归调用了多少次Fib()函数。那我们只要求出这段代码调用了多少次Fib函数便大功告成了。

3.2 计算时间复杂度

 现在假设n==5,计算一下时间复杂度。计算这个时间复杂度便是要计算函数Fib被调用的次数,现在我借助图像来详细介绍一下Fib函数被调用的次数:

在这个图里面,可以清楚的数出来这个图里面的节点数有15个。当我们用一个阶乘的方式来表示15时,15==2^(n-1)-1==(2^n)/2-1。当我们用大O 表示法来表示的时候就变成了O(2^n)。(只保留最高一层项)。

3.3空间复杂度

这个斐波那契数列的空间复杂度是什么呢?众说周知,空间复杂度表示的是在一个程序在运行时开辟的空间大小。在递归中这个空间该怎么算了?递归中的空间复杂度是:递归深度*每次递归时的空间复杂度。像上面的Fib(5)的空间复杂度就是O(1)*5。递归的空间复杂度就是O(5)。当我们将这个空间复杂度一般化时,它的空间复杂度就是O(n)。

3.4优化

可以看到这个递归的时间复杂度是非常大的,当n非常大的时候这种递归的方法的耗时就会非常长。所以我们要对这个递归方法进行优化来让它变得高效一点。在这里优化的目的就是减少递归的次数,也就是将return Fib(n-1)+Fib(n-2)改一下。

 优化:时间复杂度

int Fib(int first, int second, int n) {
	if (n <= 0) {
		return 0;
	}
	else if (n < 3) {
		return 1;
	}
	else if (n == 3) {
		return first + second;
	}
	else {
		return Fib(second, first + second, n - 1);//将两次递归改为一次
	}


}
int main() {
	int n = 0;
	scanf("%d", &n);
	int ret = Fib(1,1,n);
	printf("%d\n", ret);
	return 0;
}

这个程序的时间复杂度是多少呢?答案是O(n),空间复杂度也是O(n)。

再次优化:优化空间复杂度

int main() {
	int a = 1;
	int b = 1;
	int c = 1;
	int n = 0;
	scanf("%d", &n);
	n = n - 2;
	while (n--) {
		c = a + b;
		a = b;
		b = c;
	}
	printf("%d\n", c);
	return 0;
}

这个程序的空间复杂度就是O(1),时间复杂度还是O(n).

结束,今天的分享就到此为止,谢谢你的阅读。 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
数据结构算法是计算机科学中非常重要的基础知识数据结构是指在计算机中组织和存储数据的方式,而算法则是解决问题的步骤和方法。下面是关于数据结构算法的基础知识: 1. 数据结构学习的内容: - 数据结构学习主要包括如何用程序代码将现实世界的问题信息化,以及如何用计算机高效地处理这些信息并创造高价值。 - 数据结构学习的目标是掌握各种数据结构的特点、操作和应用场景,以便在解决实际问题时能够选择合适的数据结构。 2. 数据的定义: - 数据是对客观事物的符号表示,是计算机程序的基本元素。 - 数据可以是数字、字符、字符串、图像等各种形式。 3. 程序 = 数据结构 + 算法: - 程序数据结构算法组成,数据结构用于组织和存储数据,算法用于处理数据。 - 数据结构算法程序设计的核心内容,对程序的效率和质量有着重要影响。 4. 算法的特性: - 有穷性:算法必须在有限的步骤内结束。 - 确定性:算法中的每条指令都有确切的含义,对于相同的输入只能得到相同的输出。 - 可行性:算法中描述的操作都可以通过已经实现的基本运算执行有限次来实现。 5. “好”算法的特质: - 正确性:算法应该能够正确地解决问题。 - 可读性:算法应具有良好的可读性,以帮助人们理解。 - 健壮性:算法能够适当地处理非法输入,而不会产生奇怪的输出结果。 - 高效率与低存储需求:算法执行速度快,时间复杂度低;算法不占用过多的内存,空间复杂度低。 6. 算法效率的度量: - 时间复杂度:用来估计算法时间开销与问题规模的关系。 - 空间复杂度:用来估计算法的存储空间需求与问题规模的关系。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值