数据结构01——时间复杂度和空间复杂度

一.什么是数据结构

数据结构(Data Structure)是计算机存储、组织数据的方式,指相互之间存在⼀种或多种特定关系的数据集合。
不存在一种通用的数据结构针对于所有应用场景,所以产生了多种多样的数据结构来适配不同的环境:例如顺序表、链表、堆栈、二叉树、队列等
二.算法
算法(Algorithim)是定义良好的计算过程,指的是针对一个或一组输出,经过该算法后,产生一个或着多个输出的中间过程。而评判算法优劣的其中一个因素就是时间复杂度和空间复杂度
以力扣189旋转数组为例:
给定了一个需要右旋的数组以及右旋的次数,最简单的方法即是将最后一个下标的元素取出放入中间变量tmp,其余元素依次右移一个下标,共循环k次即可。根据思路写出代码:

void rotate(int* nums, int numsSize, int k) {

int i =0;

for(i=0;i<k;i++)//每次往右挪一个数,循环k次。

{

int tmp = nums[numsSize-1];

int j = 0;

for(j=numsSize-1;j>0;j--)

{

nums[j]=nums[j-1];

}

nums[0]=tmp;

}

}

运行可以发现两个测试用例可以通过,但是提交却发现:

检查代码发现没有出现死循环的情况 ,那应该确实是代码运行时间超出了系统规定的时间。

根据此案例,引出今天的主题——时间复杂度和空间复杂度

三.复杂度

在代码写好后,运行则需要消耗时间资源和空间(内存)资源,因此衡量一个算法的好坏是根据时间和空间来衡量的

3.1时间复杂度

在计算机科学中,定义时间复杂度为函数式T(N)。它描述的是算法的运行时间随变量不同而发生变化的一种趋势,它并不是实际的运行时间,而是一种趋势。要理解清楚它不是具体的某个值,而是一种趋势。

首先提出表示时间复杂度的方法,然后根据具体案例分析如何应用这个方法计算时间复杂度:

表示时间复杂度的方法为:大O渐进法。

其具体规则为:

1.时间复杂度函数式T(N)中,只保留最高阶项,去掉那些低阶项,因为当N不断变大时,

低阶项对结果影响越来越⼩,当N无穷大时,就可以忽略不计了。

2.如果最⾼阶项存在且不是1,则去除这个项⽬的常数系数,因为当N不断变⼤,这个系数

对结果影响越来越小,当N无穷大时,就可以忽略不计了。

3.T(N)中如果没有N相关的项⽬,只有常数项,用常数1取代所有加法常数。

接下来结合具体代码案例,并应用上述的三个规则来计算时间复杂度

void Func1(int N)
{
int count = 0;
for (int k = 0; k < 2 * N ; ++ k)
{
++count;
}
int M = 10;
while (M--)
{
++count;
}
printf("%d\n", count);
}
首先看这个代码的for循环中出现了变量N,while循环中虽然也出现了变量M,但其为定值,循环10次,大致可以写为O(N+10),而根据第一条规则,只保留高阶项,最后答案是O(N)。
再来看第二个例子:

void Func2(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);

}

这段代码定义了两个变量N和M,又进行了两个for循环,分别循环N次和M次,所以其时间复杂度为O(M+N);如果M>>N,N就可以忽略不计,O(M);同理如果N>>M,M忽略不计,O(N)。

void Func3(int N) {

int count = 0;

for (int k = 0; k < 100; ++k) {

++count;

}

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

}

在Fun3这个函数例子中,并没有出现关于N变量的循环等操作,所以其时间复杂度为一个常数,而对于常数,根据第三条规则将其写作O(1)。

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

const char* p_begin = s;

while (*p_begin != character) {

if (*p_begin == '\0')

return NULL;

p_begin++;

}

return p_begin;

}

对于strchr这个函数,仔细观看出现的while循环则会发现,它的时间复杂度取决于这个while循环,而while循环中似乎不是一个可以明确说出循环多少次的变量,是根据要查找的character有关。运气好的话,第一个是,时间复杂度为O(1);运气不好的话,最后一个是,其时间复杂度为字符串的长度,O(N);但 O(N)也就是最坏的情况了,如果最坏情怀下都能满足要求,那其它情况肯定能满足要求。所以对于分类讨论的情况,就按照最坏的情况。

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次:(内层)循环x次 。 第一次:n-1;第二次:n-2;第三次:n-3; ------第n-1次:1 。把总循环次数加起来则为:

可看出是等差数列,求和则为 :,根据大O渐进法第二条规则,时间复杂度为O(N^2)。

void func5(int n) {

int cnt = 1;

while (cnt < n) {

cnt *= 2;

}

}

fun5这段代码较为简单,while循环的终止条件是<n,内部则为每次×2,相当于数出来需要2的多少次相乘就会大于n,其实就是,对数函数的形式。

而当n接近无穷大时,对数函数的底数对于其影响并不大,所以在表示时间复杂度时,都将其统一写成

long long Fac(size_t N) {

if (N == 0)

return 1;

return Fac(N - 1) * N;

}

最后考虑到递归的情况,递归的时间复杂度= 单次时间复杂度*递归次数。对于上述阶乘递归,单次时间复杂度为1,共递归n次,最后时间复杂度为O(n)。

3.2空间复杂度

空间复杂度的定义为在一个运算执行的过程中,有多少额外开辟的空间。计算规则也是大O渐进法的三条规。

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

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;

}

}

例如这段代码 ,在函数运行过程中,额外开辟的空间只有int exchange 和size_t 为常数,所以空间复杂度为O(1)。

而对于fun5的递归来说,空间复杂度 = 单次运行的空间复杂度* 递归次数,单次递归的空间复杂度为O(1),共有n次,所以总的空间复杂度为O(N);

下述是两张常见复杂度的图

再次回到开头的题目实例,如果用依次向后移动的方法,其时间复杂度为O(N^2),而题目中提供的元素个数最多为10^5,总时间为10^10ms相当于10^7s,会超过时间限制。

下述提供两种可通过的解题思路

1.

void rotate(int* nums, int numsSize, int k) {

// 把创建一个新数组,把要取下来的数放到新数组里,排好后,整体放入原数组

int arr[numsSize];

int i =0;

for(i=0;i<numsSize;i++)

{

arr[(i+k)%numsSize] = nums[i];

}

for(i=0;i<numsSize;i++)

{

nums[i]=arr[i];

}

}

整体思路为创建一个新数组,将需要移动的元素放入数组的相应位置,然后整体将原数组替换。

2.

void rotate(int* nums, int numsSize, int k) {


// 分段旋转,整体逆序

if (k > numsSize)

k %= numsSize;

int left = numsSize - k;

int right = numsSize - 1;

while (left < right) {

int tmp = nums[left];

nums[left] = nums[right];

nums[right] = tmp;

left++;

right--;

}

left = 0;

right = numsSize - 1 - k;

while (left < right) {

int tmp = nums[left];

nums[left] = nums[right];

nums[right] = tmp;

left++;

right--;

}

left = 0;

right = numsSize - 1;

while (left < right) {

int tmp = nums[left];

nums[left] = nums[right];

nums[right] = tmp;

left++;

right--;

}

}

这个思路为将最后k个需要移动的元素进行逆序,剩下的元素逆序,然后整体逆序 。

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

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

相关文章

Java中strip与trim()的区别

TOC Java中strip与trim()的区别 jdk11及以上版本&#xff0c;java的String支持strip()方法&#xff0c;那么原来的删除空白trim()与strip()的区别时什么&#xff1f; 区别 trim()&#xff1a;仅处理字符串首尾的ASCII空白字符串&#xff08;小于等于\u0020字符&#xff0c;…

Python入门——字符串

Python快速入门&#xff08;1&#xff09;——字符串字符串索引访问常用倒序访问截取/切片常用方法长度判空大小写删除空白分割最近需要使用到python&#xff0c;本系列适合有其他编程语言&#xff08;C/C/Java&#xff09;基础的同学&#xff0c;帮助大家一起快速上手Python&a…

多级缓存必要性

Java多级缓存设计&#xff1a;应对微博明星官宣的高并发场景 一、多级缓存原理与必要性 1.1 为什么需要多级缓存&#xff1f; 单级缓存的问题&#xff1a; 性能瓶颈&#xff1a;所有请求都打到同一缓存层&#xff0c;压力集中容错性差&#xff1a;缓存层故障直接影响整体可…

OpenHarmony Flutter 分布式安全防护:跨设备身份认证与数据加密传输方案 - 指南

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

tp3.2性能暂时优化调整

// 1. 禁用TP3.2的冗余组件(在入口文件index.php最顶部添加)define(APP_DEBUG, false); // 关闭调试模式(必须)define(BIND_MODULE,Api); // 绑定模块,减少模块扫描define(THINK_PATH, __DIR__./ThinkPHP/);// 禁…

百万数据报表操作 - 努力-

百万数据报表操作百万数据报表操作,Excel报表一、百万数据报表概述 1.1 百万数据报表概述 我们都知道Excel可以分为早期的Excel2003版本(使用POI的HSSF对象操作)和Excel2007版本(使用POI的XSSF操作),两者对百万数…

电商系统-下单功能 - 努力-

电商系统-下单功能电商系统-下单功能,SpringCloud一、 订单结算页 本文介绍:订单结算页,用户地址列表,支付方式选择,用户商品清单,生成订单 ,分布式ID,库存扣减,增加用户积分业务功能。 1.1 订单结算页 用户收货…

软件测试—即时通讯测试方法

一、即时通讯实现方式 1.短轮询&#xff08;Short Polling&#xff09; 短轮询是一种客户端定期向服务器发送HTTP请求以检查是否有新数据的简单技术。无论服务器是否有新数据&#xff0c;客户端都会在固定的时间间隔后再次请求。 实现机制 客户端向服务器发送HTTP请求&#xff…

告别if-else噩梦:流程编排技术

作为一个优秀的程序员&#xff0c;要守住职业的底线。能简单快速的完成的一件事&#xff0c;就一定要用简单的方案快速完成。不可过度的设计&#xff0c;始终保持系统的简洁&#xff01; 曾几何时&#xff0c;我对于流程编排这件事 嗤之以鼻&#xff0c;为什么呢&#xff1f;我…

attn_scores注意力分计算-记录

querys 是 2*6*2&#xff0c;keys也是2*6*2 attn_scores querys keys.transpose(1,2)attn_scores 最终维度是 266&#xff1b;数值上是两个矩阵的批量矩阵乘法结果&#xff0c;每个样本对应一个 66 的注意力分数矩阵 transpose(1,2) 交换 keys 的第 1 维和第 2 维&#xff1…

多头注意力中的张量重塑

view PyTorch 的view() 是张量「重塑&#xff08;Reshape&#xff09;」函数&#xff0c;用于改变张量的维度形状但不改变数据本身 在多头注意力中&#xff0c;view()的核心作用是将总隐藏维度拆分为「注意力头数 单头维度」&#xff0c;实现多头并行计算 核心规则 tensor.vie…

第二周作业wp

第二周作业wp [SWPUCTF 2021 新生赛]easyupload3.0 题目提示已经很明显了&#xff0c;我们要提交一个.jpg的文件。那么我们就把一个木马文件做成jpg文件。 这里我们把文件成功上传&#xff0c;然后通过蚁剑连接 连接之后&#xff0c;寻找flag。 如图&#xff0c;成功找到。 2…

吐血推荐专科生必用TOP9AI论文网站

吐血推荐专科生必用TOP9AI论文网站 2026年专科生论文写作工具测评&#xff1a;为何需要一份精准榜单&#xff1f; 随着AI技术在教育领域的深入应用&#xff0c;越来越多的专科生开始借助AI工具提升论文写作效率。然而&#xff0c;面对市场上五花八门的论文辅助平台&#xff0c;…

Python 调用大模型(LLM) - 努力-

Python 调用大模型(LLM)Python 调用大模型(LLM),提示词工程一、提示词工程 提示词(Prompt):是引导大模型(LLM)进行内容生成的命令(一句话、一个问题等)。 提示词工程(Prompt Enginnering):通过有技巧的编写提示…

Python核心语法-Python自定义模块、Python包 - 努力-

Python核心语法-Python自定义模块、Python包Python核心语法,Python自定义模块、Python包一、python 模块 Python模块(module):一个Python文件(.py)就是一个模块,模块是Python程序的基本组织单位。在模块中可以定义…

亲测好用9个一键生成论文工具,助本科生轻松写论文!

亲测好用9个一键生成论文工具&#xff0c;助本科生轻松写论文&#xff01; AI 工具的崛起&#xff0c;让论文写作不再难 对于本科生来说&#xff0c;写论文一直是令人头疼的事情。从选题、查资料到撰写和降重&#xff0c;每一个环节都可能成为“卡壳”的点。而随着 AI 技术的不…

为什么您的机房必须选择本地化 U 位资产管理系统?供应商服务深度解析

机房 U 位资产管理是数据中心运营的核心环节&#xff0c;传统云端管理模式在实时性、数据安全与服务响应上的短板&#xff0c;进一步放大了空间利用率低、资产跟踪难、安全合规难三大痛点&#xff0c;成为机房高效运营的阻碍。本地化 U 位资产管理系统依托数据本地存储、实时交…

人群仿真软件:Vadere_(3).用户界面操作

用户界面操作 1. 基本操作 Vadere是一款强大的人群仿真软件&#xff0c;其用户界面设计旨在为用户提供直观且易用的操作体验。在本节中&#xff0c;我们将详细介绍如何进行基本的用户界面操作&#xff0c;包括启动软件、创建和加载仿真场景、基本导航和工具栏的使用。 1.1 启…

人群仿真软件:Vadere_(1).Vadere简介与安装

Vadere简介与安装 Vadere简介 Vadere是一款开源的人群仿真软件&#xff0c;旨在模拟复杂环境中的行人流动行为。它结合了多种先进的仿真算法和模型&#xff0c;能够准确地预测和分析人群在不同环境下的动态行为。Vadere不仅可以用于学术研究&#xff0c;还可以在城市规划、建…

人群仿真软件:Vadere_(2).Vadere基本操作与界面

Vadere基本操作与界面 启动Vadere 启动过程 Vadere是一款基于Java的人群仿真软件&#xff0c;可以通过以下步骤启动&#xff1a; 安装Java环境&#xff1a;确保您的计算机上安装了Java运行环境&#xff08;JRE&#xff09;或Java开发工具包&#xff08;JDK&#xff09;。您可…