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

在这里插入图片描述

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

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;elsereturn mid;}return -1;
}

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SQL server中:常见问题汇总(如:修改表时不允许修改表结构、将截断字符串或二进制数据等)

SQL server中&#xff1a;常见问题汇总 1.修改表时提示&#xff1a;不允许修改表结构步骤图例注意 2.将截断字符串或二进制数据。3.在将 varchar 值 null 转换成数据类型 int 时失败。4.插入insert 、更新update、删除drop数据失败&#xff0c;主外键FOREIGN KEY 冲突5.列不允许…

SpringAOP源码解析之advice构建排序(二)

上一章我们知道Spring开启AOP之后会注册AnnotationAwareAspectJAutoProxyCreator类的定义信息&#xff0c;所以在属性注入之后initializeBean的applyBeanPostProcessorsAfterInitialization方法执行的时候调用AnnotationAwareAspectJAutoProxyCreator父类(AbstractAutoProxyCre…

三步,金蝶K3的数据可视化了

数据可视化的一大特点就是“一图胜千言”&#xff0c;没什么能比图表更直观展现数据的了。那&#xff0c;金蝶K3系统上那海量数据能不能也做成数据可视化报表&#xff1f;操作复杂吗&#xff0c;难度大吗&#xff1f; 换了别的软件来做&#xff0c;操作多、难度大是板上钉钉&a…

(ubuntu)安装nginx

文章目录 前言回顾Linux命令在线安装&#xff1a;相关命令&#xff1a;相关路径常用配置&#xff1a; 卸载nginxbug相关: 前言 提示&#xff1a;别再问我的规划是什么了&#xff1a;呼吸&#xff0c;难道不算一个吗&#xff1f; --E.M齐奥朗 回顾Linux命令 # 查看当前进程的所…

pdf误删恢复如何恢复?分享4种恢复方法!

如何将pdf误删恢复&#xff1f;使用电脑的时候&#xff0c;经常会需要使用到pdf文件&#xff0c;但是有时候&#xff0c;因为一些操作上的失误&#xff0c;我们会丢失一些重要的文件。如果你不小心将pdf误删了&#xff0c;该如何进行恢复呢&#xff1f; PDF文件丢失的原因可以…

Jenkins部署失败:JDK ‘jdk1.8.0_381‘ not supported to run Maven projects

Jenkins部署报错&#xff1a;JDK ‘jdk1.8.0_381’ not supported to run Maven projects提示使用的jdk有问题&#xff0c;启动的jdk版本不能满足项目启动。 登录Jenkins管理页面&#xff0c;系统管理——全局工具配置——JDK安装配置满足条件的JDK版本&#xff0c;保存配置&…

YOLOv7改进:新颖的上下文解耦头TSCODE,即插即用,各个数据集下实现暴力涨点

💡💡💡本文属于原创独家改进:上下文解耦头TSCODE,进行深、浅层的特征融合,最后再分别输入到头部进行相应的解码输出,实现暴力暴力涨点 上下文解耦头TSCODE| 亲测在多个数据集实现暴力涨点,对遮挡场景、小目标场景提升也明显; 收录: YOLOv7高阶自研专栏介绍: …

零售数据分析模板分享(通用型)

零售数据来源多&#xff0c;数据量大&#xff0c;导致数据的清洗整理工作量大&#xff0c;由于零售的特殊性&#xff0c;其指标计算组合更是多变&#xff0c;进一步导致了零售数据分析工作量激增&#xff0c;往往很难及时分析数据&#xff0c;发现问题。那怎么办&#xff1f;可…

模仿企业微信界面

备注&#xff1a;未实现相关功能&#xff0c;仅模仿界面&#xff0c;不能作为商业用途&#xff0c;若有侵权&#xff0c;请联系删除。 <Window x:Class"模仿企业微信界面.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"…

CVE-2023-46227 Apache inlong JDBC URL反序列化漏洞

项目介绍 Apache InLong&#xff08;应龙&#xff09;是一站式、全场景的海量数据集成框架&#xff0c;同时支持数据接入、数据同步和数据订阅&#xff0c;提供自动、安全、可靠和高性能的数据传输能力&#xff0c;方便业务构建基于流式的数据分析、建模和应用。 项目地址 h…

Linux系统安装redis并配置为服务

一、Linux环境 1、下载 官网提供的源码下载地址&#xff1a; https://github.com/redis/redis/archive/7.0.5.tar.gz 2、将源码上传至服务器 3、解压缩 # 将解压缩后的文件放置在同目录的source文件夹下 tar -zxvf redis-7.0.5.tar.gz -C ./source4、编译安装 对源码进行编…

FFmpeg 解析Glide 缓存下的图片文件报错(Impossible to open xxx)

简单介绍下背景 我们业务有个功能把图片放到一个文件中&#xff0c;统一进行播放 &#xff0c;但是遇到一个棘手问题&#xff0c;某一个情况下 的图片 就是打不开 就是报错。以为是编译参数 。哪些格式没有加上。但经过测试 该加的都加了。 所以 不是编译参数的问题。 Impossi…

ElasticSearch:实现高效数据搜索与分析的利器!项目中如何应用落地,让我带你实操指南。

1.难点解答 收集到几个问题&#xff1a; elasticsearch是单独建一个项目&#xff0c;作为全文搜索使用&#xff0c;还是直接在项目中直接用&#xff1f; ES 服务器是要单独部署的&#xff0c;你可以把 ES 理解为 Redis。 新增数据时&#xff0c;插入到mysql中&#xff0c;需不…

Webpack 基础以及常用插件使用方法

目录 一、前言二、修改打包入/出口配置步骤 三、常用插件使用html-webpack-plugin打包 CSS 代码提取 CSS 代码优化压缩过程打包 less 代码打包图片文件 一、前言 本质上&#xff0c;Webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。当 webpack 处理应用程序时…

多级缓存入门

文章目录 什么是多级缓存JVM进程缓存环境准备安装MySQL导入Demo工程导入商品查询页面 初识Caffeine Lua语法初识Lua第一个lua程序变量和循环Lua的数据类型声明变量循环 条件控制、函数函数条件控制 多级缓存安装OpenRestyOpenResty快速入门反向代理流程OpenResty监听请求编写it…

【数据结构】堆的详解

文章目录 堆的简介堆的实现堆的插入数据堆的删除数据 堆排序向上调整和向下调整的时间复杂度的分析 大量数据的topk问题 堆的简介 今天要写的数据结构是堆&#xff0c;什么是堆呢&#xff1f;堆其实是一种完全二叉树&#xff0c;只不过它是有条件的。 堆分为两种&#xff0c;一…

网站搬家的多种方法

网站搬家&#xff0c;把网站从一个服务器迁移到另一个服务器&#xff0c;涉及到网站文件和数据库的备份、上传、导入等操作&#xff0c;最重要的是备份网站&#xff0c;避免迁移出现问题无法恢复网站。 根据不同的情景和需求&#xff0c;网站搬家的方法有多种&#xff0c;下面…

Mysql,SqlServer,Oracle获取库名 表名 列名

先看下需求背景&#xff1a; 获取某个数据源连接下所有库名&#xff0c;库下所有表名&#xff0c;表中所有字段 1.MySql 先说MySql吧&#xff0c;最简单 1.1获得所有数据库库名 这是一个mysql和sqlserver公用的方法&#xff0c;这里url不用担心数据库问题&#xff0c;他其实…

[Ubuntu 18.04] 搭建文件夹共享之Samba服务器

Samba是一个开源项目,允许Windows用户在Linux和Unix系统上进行文件共享。 Samba服务器是一个可以让Linux或Unix系统在网络上充当Windows NT/2000/XP/2003等网络操作系统的共享资源的软件。它允许用户通过SMB/CIFS协议在Linux或Unix系统与Windows共享资源。 Samba服务器的主要…

Android Apk一键打包上传至蒲公英平台的gradle脚本

一、背景 项目中每次手动打包后&#xff0c;生成的测试包&#xff0c;都需要手动打开蒲公英平台的网址&#xff0c;登录账号&#xff0c;手动上传apk。之前写过一键上传至fir平台的脚本&#xff0c;想着这次可以搞一下一键打包上传至蒲公英的gradle脚本&#xff0c;提高下工作…