数据结构初阶——时间复杂度

news2024/10/5 15:30:22

在这里插入图片描述

朋友们我们又见面了,今天我们来学习数据结构的时间复杂度,在讲数据结构之前,大家可能只知道我们学习的是数据结构,但是还是不知道数据结构的具体定义,其实就是在内存上的数据。然后我们就像通讯录一样对它进行增删查改。

1. 什么是数据结构?

数据结构(Data Structure)是计算机存储、组织数据的方式,指相互之间存在一种或多种特定关系的数据元素的集合。

今天我们的内容就是数据结构中的时间复杂度,时间复杂度听起来好像是在比较它们的运算时间,其实并不是只是字面上的意思,我们来细看吧。

目录

1.算法效率
2.时间复杂度
3.空间复杂度
4. 常见时间复杂度以及复杂度oj练习

我们今天围绕着上面的内容来依次学习。

1.算法效率

1.1 如何衡量一个算法的好坏

我们下面给一个代码,是斐波那契的递归实现,代码很简短,但是我们觉得它的效率高吗。

long long Fib(int N)
{
	 if(N < 3)
	 return 1;
	 
	 return Fib(N-1) + Fib(N-2);
}

上面的代码只有简单的几行,但是却能递归的求出我们想要的第N个斐波那契数。
但是递归是有缺陷的,当深度够深的时候,它的效率大大的减慢。还不如我们用迭代的方式实现,所以代码越简单,并不是效率高。

那我们应该拿什么来衡量一个算法的效率呢

1.2算法的复杂度

算法在编写成可执行程序后,运行时需要耗费时间资源和空间(内存)资源 。因此衡量一个算法的好坏,一般是从时间和空间两个维度来衡量的,即时间复杂度和空间复杂度。
时间复杂度主要衡量一个算法的运行快慢,而空间复杂度主要衡量一个算法运行所需要的额外空间。在计算机发展的早期,计算机的存储容量很小。所以对空间复杂度很是在乎。但是经过计算机行业的迅速发展,计算机的存储容量已经达到了很高的程度。所以我们如今已经不需要再特别关注一个算法的空间复杂度。

2.时间复杂度

时间复杂度的概念

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

那我们下面来给一个例子,我们来算一下在这段代码里count执行了几次

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);
}

我们可以看到第一个for循环是个双层的for循环,所以执行N的2次方 ,第二个又是执行2*N次
然后加上一个常数M。整合起来就是-》

在这里插入图片描述
当我们的N趋向于无穷大的时候,我们这里只看最高次的项就行了,我们用大O的渐进表示方那就是O(N*N)

2.2 大O的渐进表示法

大O符号(Big O notation):是用于描述函数渐进行为的数学符号。
推导大O阶方法:
1、用常数1取代运行时间中的所有加法常数。
2、在修改后的运行次数函数中,只保留最高阶项。
3、如果最高阶项存在且不是1,则去除与这个项

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

我们的算法是存在最好,最坏和平均情况的,为什么这样说呢

这个可以拿我们的算法中最常见的排序来说,就举冒泡排序来讲,冒泡排序最好的情况就是遍历第一遍数组的时候,发现有序,就可以排序好了,这就是我们的最好情况,但是也有最坏的情况,那就是如果我们的数组是逆序的话,那就是最坏的情况,最坏的情况下的时间复杂度用大O渐进表示那就是O(N*N)大家可以写成O(N的平法),打那个符号的时候变成……,大家理解就行了

那这里我们就可以对它进行分类,我们分为最坏情况,最好情况,还有平均情况。

最坏情况:任意输入规模的最大运行次数(上界)
平均情况:任意输入规模的期望运行次数
最好情况:任意输入规模的最小运行次数(下界)

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

那我们要评价一个时间复杂度的大O渐进法就得使用最坏的情况,我们下面来看几个例子。
在讲之前,大家算他们的时间复杂度的时候不能只看代码,也不是看这个代码实行了几次,而是我们要看他的算法思想,这样才能算出他们的时间复杂度,我们可以假设这个例子,比如我们要写一个代码,大家肯定都在牛客网上和leetcode上见过一些题目对我们的时间复杂度有限制,所以我们在写代码肯定要先构思路,那这个时候就要去想它的思想,这也是时间复杂度的好处,所以我们在计算它的时间复杂度的时候我们需要去看它的思想,而不是它的代码。

// 计算Func2的时间复杂度?
void Func2(int N)
{
	int count = 0;
	for (int k = 0; k < 2 * N; ++k)
	{
		++count;
	}
	int M = 10;
	while (M--)
	{
		++count;
	}
	printf("%d\n", count);
}

那我们来计算这个的时间复杂度
前面几个例子我们都是先计算准确的,然后在计算用大O渐进表示的。
我们可以看到这里的count执行次数Func2() = 2*N +10
所以我们可以写成O(N)。

大家可能对这里有点疑问就是为什么我们系数可以直接去掉,这里我给出的原因就是当N趋向于无穷大的时候,极限就是N,所以可以直接去掉系数,还有就是常量也可以直接去掉,这里还要和大家说我们如果执行的是常量次的话,我们也可以直接写成O(1).(后面也有例子)

// 计算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);
}

这里首先我们可以看到的是M和N都是变量,所以要分开分析,如果M和N差不多大的时候我们就可以写成O(M+N),当M远大于N的时候,就可以写成O(M),相反如果N远大于M的时候,我们就可以写成O(N),那如果他们两个是差不多大的时候,我们就可以写成O(N)。

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

这题大家一定要擦亮自己的眼睛,不要以为K是个变量,这里就是常数项,所以就可以写成O(1)

下面这个是一个库函数,如果不了解的话,可能就想不出来,但是我们可以用Cplusplus进行查询

const char * strchr ( const char * str, int character );

在这里插入图片描述
它的作用就是找到字符在这个字符串中的位置。
那我们就好比查找一样,是需要遍历一下这个字符串的,然后遇到这个字符就返回它的地址,那我们如果假设要找的这个字符在最后的位置,那我们就是遍历字符串,所以就是O(N)。

// 计算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;
	}
}

在冒泡排序中再次强调我们计算时间复杂度的时候是要看他们的思想,不是看他们的代码,比如现在这个代码的话,冒泡排序第一次是找到最大的数字(假设是升序)放到这个数组的末尾,那第一次比较的次数是(n-1)次,因为一次排序,我们的最大的数已经找到,所以下一次比较的次数就是n-2,依次下去到1就是一个等差数列,那后面也不多说了,最后用等差数列的结果我们在根据大O渐进法来计算就行。答案就是O(N*N)

我们再来看一个二分查找的题目。


int BinarySearch(int* a, int n, int x)
{
	assert(a);
	int begin = 0;
	int end = n - 1;
	// [begin, end]:begin和end是左闭右闭区间,因此有=号
	while (begin <= end)
	{
		int mid = begin + ((end - begin) >> 1);
		if (a[mid] < x)
			begin = mid + 1;
		else if (a[mid] > x)
			end = mid - 1;
		else
			return mid;
	}
	return -1;
}

二分查找的思路就是一次查找我们会去掉一半的数据,然后在在另一个区域里进行查找,所以二分查找的效率是特变高的,那我们来计算它的时间复杂度也就好理解很多了,就是(logN)

其实这些有些内容我在之前更过,但是感觉不是特别好,加上我总是忘记之前学得,在学一遍,在写一遍代码,也让自己回忆一下,那今天的分享就到这里,明天继续学习。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Qt 目录操作(QDir 类)及展示系统文件实战 QFilelnfo 类介绍和获取文件属性项目实战

一、目录操作(QDir 类) QDir 类提供访问系统目录结构 QDir 类提供对目录结构及其内容的访问。QDir 用于操作路径名、访问有关路径和文件的信息以及操作底层文件系统。它还可以用于访问 Qt 的资源系统 Qt 使用“/”作为通用目录分隔符&#xff0c;与“/”在 URL 中用作路径分…

istio介绍(一)

1. 概念 1.1 虚拟服务 虚拟服务提供流量路由功能&#xff0c;它基于 Istio 和平台提供的基本的连通性和服务发现能力&#xff0c;让您配置如何在服务网格内将请求路由到服务 示例&#xff1a; apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata:nam…

高项.项目管理经验、理念、教训

一、项目管理的一些经验 管项目重在管理&#xff0c;而不是死抠无关紧要的技术细节等等。 真正的团队一定是11>2&#xff0c;要把重心放在凝聚团队协力&#xff0c;共同完成目标上。 项目的推进永远都是不确定性的&#xff0c;真正考验项目经理的是不断出现的需求变更和状…

vue重修之路由【上】

文章目录 单页应用程序: SPA - Single Page Application路由简介Vue Reouter简介VueRouter的使用&#xff08;52&#xff09;组件的存放目录问题组件分类存放目录 路由的封装抽离 单页应用程序: SPA - Single Page Application 单页面应用(SPA): 所有功能在 一个html页面 上 单…

常用的跨域解决方案有哪些?

在 Web 开发中,跨域是指在浏览器环境下,通过 JavaScript 代码从一个域名的网页去访问另一个域名的资源。由于同源策略的限制,跨域请求通常会被浏览器阻止,为了实现跨域访问,HTML5 提供了一些机制来解决这个问题。 以下是一些常用的跨域解决方案: 1:JSONP(JSON with P…

展馆导览系统之AR互动式导航与展品语音讲解应用

一、项目背景 随着科技的进步和人们对于文化、艺术、历史等方面需求的提升&#xff0c;展馆在人们的生活中扮演着越来越重要的角色。然而&#xff0c;传统的展馆导览方式&#xff0c;如纸质导览、人工讲解等&#xff0c;已无法满足参观者的多元化需求。为了提升参观者的体验&a…

​CUDA学习笔记(六)Warp解析

本篇博文转载于https://www.cnblogs.com/1024incn/tag/CUDA/&#xff0c;仅用于学习。 Warp 逻辑上&#xff0c;所有thread是并行的&#xff0c;但是&#xff0c;从硬件的角度来说&#xff0c;实际上并不是所有的thread能够在同一时刻执行&#xff0c;接下来我们将解释有关wa…

​CUDA学习笔记(五)GPU架构

本篇博文转载于https://www.cnblogs.com/1024incn/tag/CUDA/&#xff0c;仅用于学习。 GPU架构 SM&#xff08;Streaming Multiprocessors&#xff09;是GPU架构中非常重要的部分&#xff0c;GPU硬件的并行性就是由SM决定的。 以Fermi架构为例&#xff0c;其包含以下主要组成…

什么是SpringMVC?简单好理解!

1、SpringMVC是什么&#xff1f; SpringMVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级web框架&#xff0c;通过把Model&#xff0c;View&#xff0c;Controller分离&#xff0c;将web层进行职责解耦&#xff0c;把复杂的web应用分成逻辑清晰的几部分。简化开发&…

并发编程-线程池ThreadPoolExecutor底层原理分析(一)

问题&#xff1a; 线程池的核心线程数、最大线程数该如何设置&#xff1f; 线程池执行任务的具体流程是怎样的&#xff1f; 线程池的五种状态是如何流转的&#xff1f; 线程池中的线程是如何关闭的&#xff1f; 线程池为什么一定得是阻塞队列&#xff1f; 线程发生异常&…

蓝桥杯 (饮料换购,C++)

思路&#xff1a; 1、先加上初始的饮料数n。 2、再加上n可以兑换的饮料数n/3&#xff0c;求多余的瓶盖n%3。循环直至瓶盖数无法兑换新的一瓶饮料。 #include<iostream> using namespace std; int main() {int n,a0,sum0;cin >> n;sum n;while (n){n n a;//加上上…

【软考】11.5 测试原则/阶段/测试用例设计/调试

《测试原则和方法》 测试原则 测试&#xff1a;为了发现错误而执行程序的过程成功的测试&#xff1a;发现了至今尚未发现的错误的测试 测试方法 静态测试&#xff08;有效发现30%-70%的错误&#xff09; a. &#xff08;文档&#xff09;检查单 b. &#xff08;代码&#xff…

学习SpringMVC,建立连接,请求,响应 SpringBoot初学,如何前后端交互(后端版)?最简单的能通过网址访问的后端服务器代码举例

要想通过SpringBoot写一个简单的处理请求的服务器&#xff08;方法&#xff09;&#xff0c;需要有以下步骤 建立连接请求响应 来复习的话直接在文章末尾看源码就行 1、创建SpringBoot项目 https://blog.csdn.net/dream_ready/article/details/133948253 2、编写Controller建…

WebSocket的入门秘籍?

一、是什么 WebSocket&#xff0c;是一种网络传输协议&#xff0c;位于OSI模型的应用层。可在单个TCP连接上进行全双工通信&#xff0c;能更好的节省服务器资源和带宽并达到实时通迅 客户端和服务器只需要完成一次握手&#xff0c;两者之间就可以创建持久性的连接&#xff0c…

postman打开后,以前的接口记录不在,问题解决

要不这些文件保存在C:\Users\{用户名}\AppData\Roaming\Postman 比如&#xff0c;你目前使用的window登录用户是abc&#xff0c;那么地址便是C:\Users\abc\AppData\Roaming\Postman 打开后&#xff0c;这个目录下会有一些命名为backup-yyyy-MM-ddThh-mm-ss.SSSZ.json类似的文…

[python 刷题] 287 Find the Duplicate Number

[python 刷题] 287 Find the Duplicate Number 题目&#xff1a; Given an array of integers nums containing n 1 integers where each integer is in the range [1, n] inclusive. There is only one repeated number in nums, return this repeated number. You must sol…

zookeeper的介绍和用docker搭建zookeeper集群,以及Go语言使用zookeeper

typora-copy-images-to: imgs Zookeeper的使用 1、Zookeeper简介 Apache ZooKeeper 是 Apache 软件基金会的一个软件项目&#xff0c;为大型分布式系统提供开源分布式配置服务、同步服务和命名注册。ZooKeeper原本是Hadoop的一个子项目&#xff0c;但现在它本身已经是一个顶级…

新年学新语言Go之三

一、前言 这一篇简单介绍一下Go中的数组、切片、map和指针。 二、数组 Go语言的数组和Java差不多都是定长的&#xff0c;用于存储有相同类型的元素&#xff0c;数组在内存中是连续分配的&#xff0c;索引数组中任意数据速度都非常快。 注&#xff1a;Go声明变量和其它强类型…

C++前缀和算法的应用:得到连续 K 个 1 的最少相邻交换次数 原理源码测试用例

本文涉及的基础知识点 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 滑动窗口 题目 给你一个整数数组 nums 和一个整数 k 。 nums 仅包含 0 和 1 。每一次移动&#xff0c;你可以选择 相邻 两个数字并将它们交换。 请你返回使 nums 中包…

FL Studio中文最新21破解版本水果软件下载

那么&#xff0c;大家知道编曲是什么吗&#xff1f;编曲和作曲又有什么区别呢&#xff1f; 一首歌的制作过程通常是由作词或作曲开始的&#xff0c;作曲就是运用基本乐理、和声学、复调、配器法、曲式结构的技术理论体系来表达创作者音乐思想的方法。说白了其实就是制作一首歌…