数据结构(Java版)第一期:时间复杂度和空间复杂度

目录

一、数据结构的概念

1.1. 什么是数据结构

1.2. 算法与数据结构的关系 

二、算法效率

三、时间复杂度 

3.1. 大O的渐进表⽰法 

3.2. 计算冒泡排序的时间复杂度

3.3. 计算二分查找的时间复杂度

四、空间复杂度

4.1. 空间复杂度 

4.2. 冒泡排序的空间复杂度

4.3. 斐波那契数列的空间复杂度 

五、学习时间复杂度和空间复杂度的好处


一、数据结构的概念

1.1. 什么是数据结构

       什么是数据结构呢?相信很多老铁尤其是非计算机专业的老铁还是第一次听说这个词。通俗地说,数据结构就是在内存当中对我们的数据进行一个管理和建立数据见关系,我们熟知的内存条(如下图所示)就是存储数据的介质,我们对数据的管理就是存储在内存条上的。

       计算机这个学科最重要的是做软件开发,软件可以帮助我们实现各种功能,比如我们微信好友列表里面,表面上就是一堆姓名的数据,透过计算机我们看到的只是01010,而这些数据就存在内存条上。

1.2. 算法与数据结构的关系 

       算法就是定义良好的计算过程,它取⼀个或⼀组的值为输⼊,并产⽣出⼀个或⼀组值作 为输出。简单来说算法就是利用计算机处理问题的步骤,比如我们对数据进行一个排名,就要用到排序算法,以及需要这个区域来进行排名,就需要堆来实现。

        那么数据结构与算法之间的关系呢?二者相辅相成,你中有我,我中有你。解决一些算法问题需要用到数据结构;实现一些数据结构时,又需要用到一些算法。 

二、算法效率

       如何衡量⼀个算法的好坏,就需要用到算法效率去衡量。算法效率分析分为两种:第⼀种是时间效率,第⼆种是空间效率。时间效率被称为时间复杂度,⽽空 间效率被称作空间复杂度。时间复杂度主要衡量的是⼀个算法的运⾏速度,⽽空间复杂度主要衡量⼀ 个算法所需要的额外空间。

        通俗点说,时间复杂度和空间复杂度用来衡量代码消耗资源开销的多少,衡量的标准应该是与代码有关,与运行的设备无关。  

三、时间复杂度 

       ⼀个算法所花费的时间与其中语句的执⾏次数成正⽐例,算法中的 基本操作的执⾏次数,为算法的时间复杂度。站在数学的角度来看,时间复杂度可以看作是计算关键操作的次数与使用问题规模的函数关系,再对这个函数关系进行一个化简和近似。化简就是只取最高次项,把最高次项的系数也忽略掉,记作O() 。 

         下面博主将结合代码带大家来具体体会一下时间复杂度。

3.1. 大O的渐进表⽰法 

import java.util.Scanner;public class Main {public static int func(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--)>0){count++;}return count;}public static void main(String[] args) {Scanner num = new Scanner(System.in);int b = num.nextInt();int a = func(b);System.out.println(a);}
}

         上面的基本操作就是count的自增,那么count的被执行次数与N的函数关系就是count = N^{2} + 2N + 10。那么我们就要记作O(N^{2})

import java.util.Scanner;public class Main {public static int func(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--)>0){count++;}return count;}public static void main(String[] args) {Scanner num = new Scanner(System.in);int b = num.nextInt();int a = func(b);System.out.println(a);}
}

       上面这段代码的函数关系是count = N^{2} + 10,那么依旧是记作O(N^{2})。随着N值的增大,两个函数的值会越来越接近。

       所以说,计算时间复杂度,一定要先找到核心的基本操作是什么。这个基本操作可能是打印、修改、比较或者是删除。 

        我们下面一段代码,因为描述问题规模的方式,不一定就只有一个变量,也可以是多个。此时我们应该记作O(M + N)

import java.util.Scanner;public class Main {public static int func2(int M,int N){int count = 0;for (int k = 0; k < M; k++) {count++;}for (int k = 0; k < N; k++) {count++;}return count;}public static void main(String[] args) {Scanner num = new Scanner(System.in);int m = num.nextInt();int n = num.nextInt();System.out.println(func2(m, n));}
}

       我们再来看下面一段代码,下面的时间复杂度就比较固定了,基本操作的次数与N无关,无论N是多少,count永远被循环了100次。那么此时的时间复杂度要记作O(1),常数级时间复杂度。及时这里的i<1亿,时间复杂度照样是O(1)

import java.util.Scanner;public class Main {public static int func3(int N){int count = 0;for (int i = 0; i < 100; i++) {count++;}return count;}public static void main(String[] args) {Scanner num = new Scanner(System.in);int a = num.nextInt();System.out.println(func3(a));}
}

         如果说出现了两段代码,一个时间复杂度是O(N),另一个是O(1),那么O(N)不一定比O(1)慢,有可能当N比较小时,时间复杂度要比O(1)。所以说,在这里要牢记时间复杂度衡量的是问题规模和时间的变化趋势,不能直接决定快慢。

3.2. 计算冒泡排序的时间复杂度

public class Main {public static void BubbleSort(int[] arrays){for (int end = arrays.length; end > 0; end--) {boolean sorted = true;for (int i = 0; i < end; i++) {if(arrays[i-1] > arrays[i]){Swap(arrays, i - 1, i);sorted = false;}}if (sorted == true){break;}}}
}

         我们想要计算这个BubbleSort的时间复杂度,同理,首先也要搞清楚基本操作是什么。其中我们调用Swap方法进行交换的时候,在里面是不涉及内嵌循环的,所以计算时间复杂度的时候不用计算Swap内部的交换。我们先看外层循环,起始end的值是数组的长度N;内层循环呢,由于end的值不固定,当end=N时,i循环了N次,当end=N-1时,i循环了N-1次。所以时间复杂度的计算就是N+(N-1)+……+2+1,结果就是O(N^{2})

3.3. 计算二分查找的时间复杂度

public class Main {public static int BinarySearch(int[] arrays,int value){int begin = 0;int end = arrays.length - 1;while(begin <= end){int mid = begin + ((end-begin) / 2);if (arrays[mid] < value){begin = mid + 1;}else if(arrays[mid] > value){end = mid - 1;}else{return mid;}}return -1;}
}

       二分查找,每循环一次,区间就会缩小一半,当区间缩小为1的时候,我们才得出“找到或者是没找到”的结论。我们可能说不好直接得出时间复杂度来,那我们就利用特殊值法。当数组元素为8时,最多要经历4次循环;当数组元素为16时,最多要经历5次循环。所以我们可以得出时间复杂度为2^{循环次数}=N

       对数级别的复杂度,及时问题规模变得很大,核心操作次数增长依然缓慢。 

       综合冒泡排序和二分查找的时间复杂度时,准确地说要涉及到三种情况:1.最好情况下,最需要循环一次就能找到;2.平均情况下,循环一半的次数;3.最坏情况下,循环了最多次。

四、空间复杂度

4.1. 空间复杂度 

        空间复杂度是衡量代码运行中消耗的临时空间,也就是我们的代码在运行时所创建的空间,至运行结束被销毁的空间。比如一个数组,长度为N,在后续代码中,并没有创建任何临时的空间。此时这个数组的空间复杂度就是常数级复杂度O(1)

4.2. 冒泡排序的空间复杂度

​public class Main {public static void BubbleSort(int[] arrays){for (int end = arrays.length; end > 0; end--) {boolean sorted = true;for (int i = 0; i < end; i++) {if(arrays[i-1] > arrays[i]){Swap(arrays, i - 1, i);sorted = false;}}if (sorted == true){break;}}}
}​

       上面的代码都创建了三个临时变量,sorted和i都创建了N次,那么空间复杂度就是2N+1,也就是O(N)。但其实不是的,因为空间和时间不一样,时间是一去不复返的,而空间是可以重复利用的,都是销毁了前一个才创建下一个,前一个和下一个共用同一块空间。一共三个临时变量,所以空间复杂度就是O(1)

4.3. 斐波那契数列的空间复杂度 

int[] fibonacci(int n) {long[] fibArray = new long[n + 1];fibArray[0] = 0;fibArray[1] = 1;for (int i = 2; i <= n ; i++) {fibArray[i] = fibArray[i - 1] + fibArray [i - 2];}return fibArray;}

       我们可以看到这次创建了临时空间,方法进来之后才创建,方法出去之后才销毁。下面除了i,也没有创建额外的临时空间了,所以上面代码的空间复杂度才是O(N)

五、学习时间复杂度和空间复杂度的好处

     学习时间复杂度,目的是为了能够正确的使用数据结构。数据结构有很多种,比如数组、队列、哈希表、栈、二叉树以及平衡树等,这些数据结构在不同场景中会有不同的应用。要想知道那种数据结构更合适,就要使用时间复杂度和空间复杂度来衡量。 

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

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

相关文章

微信小程序全局配置:导航栏、下拉刷新与上拉触底设置教程

微信小程序全局配置:导航栏、下拉刷新与上拉触底设置教程 引言 微信小程序作为一种新兴的轻量级应用,凭借其便捷性和丰富的功能受到了广泛的欢迎。在开发小程序的过程中,合理配置全局属性是提升用户体验的关键。本文将深入探讨小程序的全局配置中的window选项,重点介绍导…

语言模型中的多模态链式推理

神经网络的公式推导 简介摘要引言多模态思维链推理的挑战多模态CoT框架多模态CoT模型架构细节编码模块融合模块解码模块 实验结果运行代码补充细节安装包下载Flan-T5数据集准备rougenltkall-MiniLM-L6-v2运行 简介 本文主要对2023一篇论文《Multimodal Chain-of-Thought Reason…

LLaMA-Mesh: Unifying 3D Mesh Generation with Language Models 论文解读

目录 一、概述 二、相关工作 1、LLMs到多模态 2、3D对象生成 3、自回归的Mesh生成 三、LLaMA-Mesh 1、3D表示 2、预训练模型 3、有监督的微调数据集 4、数据集演示 四、实验 1、生成的多样性 2、不同模型text-to-Mesh的比较 3、通用语境的评估 一、概述 该论文首…

【Go】-go中的锁机制

目录 一、锁的基础知识 1. 互斥量/互斥锁 2. CAS&#xff08;compare and swap&#xff09; 3. 自旋锁 4. 读写锁 5. 乐观锁 & 悲观锁 6. 死锁 二、go中锁机制 1. Mutex-互斥锁 2. RWMutex-读写锁 2.1 RWMutex流程概览 2.2 写锁饥饿问题 2.3. golang的读写锁源…

.NET9 - 新功能体验(二)

书接上回&#xff0c;我们继续来聊聊.NET9和C#13带来的新变化。 01、新的泛型约束 allows ref struct 这是在 C# 13 中&#xff0c;引入的一项新的泛型约束功能&#xff0c;允许对泛型类型参数应用 ref struct 约束。 可能这样说不够直观&#xff0c;简单来说就是Span、ReadO…

抗癌药物“曲妥珠单抗”,或将纳入2025版《中国药典》!

在抗癌药物的浩瀚星空中&#xff0c;曲妥珠单抗如同一颗璀璨的星辰&#xff0c;以其卓越的治疗效果和广泛的应用前景&#xff0c;照亮了无数HER2阳性癌症患者的生命之路。近日&#xff0c;从国家药典委员会传来振奋人心的消息——注射用曲妥珠单抗正式进入《中国药典》2025版国…

JavaParser 的全面介绍

JavaParser 是什么&#xff1f; JavaParser 的快速介绍可以参考&#xff1a; # JavaParser的快速介绍 JavaParser是一个用于解析Java源码的开源工具&#xff0c;它提供了一种简单而有效的方式来解析和操作Java代码。JavaParser解析源码的方式主要基于其将Java代码转换为抽象语…

图形化界面MySQL(MySQL)(超级详细)

1.官网地址 MySQL :: Download MySQL Workbench 1.1在Linux直接点击NO thanks..... 下载完后是这个页面 1.2任何远端登录&#xff0c;再把jj数据库给授权 1.3建立新用户 进行连接 点击这个就运行了 只执行show tables&#xff1b;要先选中 圆圈处支持自己输入 点击这个就执…

【夹板涨停战法】技术形态,原理和操盘技术图文教程

夹板涨停战法的基本形态和原理 夹板涨停是指两股强大的做多力量以夹击的方式紧紧的封夹空头&#xff0c;把空头力量打趴下&#xff0c;让空头的做空希望被破灭。 两股强大的多头力量对付空头&#xff0c;多头战胜&#xff0c;轻易灭掉空头&#xff0c;一切在强大做多力量的把…

【2024 Optimal Control 16-745】Julia语法

Lecture 2 θ和它的导数符号是通过 Julia 中的变量命名方式实现的 变量 θ 的输入&#xff1a; 在 Julia 中&#xff0c;θ 是一个合法的变量名&#xff0c;就像普通的字母 x 或 y 一样。要输入 θ&#xff0c;可以使用以下方法&#xff1a; 在 Jupyter Notebook 或 Julia REP…

Java项目实战II基于SPringBoot的玩具销售商城管理系统(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、核心代码 五、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 随着儿童娱乐与教育需求的…

Linux系统使用valgrind分析C++程序内存资源使用情况

内存占用是我们开发的时候需要重点关注的一个问题&#xff0c;我们可以人工根据代码推理出一个消耗内存较大的函数&#xff0c;也可以推理出大概会消耗多少内存&#xff0c;但是这种方法不仅麻烦&#xff0c;而且得到的只是推理的数据&#xff0c;而不是实际的数据。 我们可以…

stm32如何接收舵机的控制信号(而不是控制舵机)

看到很多如何stm32用pwm信号控制舵机的文章,老生常谈了 我来写一个stm32接收pwm信号的例子 ,这个pwm信号是用来控制舵机的 背景: 我需要接收航模接收机的,用来控制舵机的pwm信号, 得到这个信号后,做其他事情. 初版代码 pwm.h#ifndef _pwm_H #define _pwm_H#include "s…

RK3588 HDMI2.1电路参考设计原理

RK3588是瑞芯微电子&#xff08;Rockchip&#xff09;旗下的一款高性能应用处理器芯片&#xff0c;采用了ARM的big.LITTLE架构&#xff0c;结合了四个高性能的Cortex-A76核心和四个高效能的Cortex-A55核心。 big.LITTLE技术通过结合高性能的“大核”&#xff08;big cores&…

【大数据学习 | Spark-Core】详解分区个数

RDD默认带有分区的&#xff0c;那么创建完毕rdd以后他的分区数量是多少&#xff1f; 从hdfs读取文件的方式是最正规的方式&#xff0c;我们通过计算原理可以推出blk的个数和分区数量是一致的&#xff0c;本地化计算。 我们可以发现数据的读取使用的是textInputFormat&#xff…

艾体宝干货丨差异解读:IT 和 OT 网络的数据包和网络分析

IT 网络&#xff08;传统网络&#xff09; IT 网络是现代计算的支柱&#xff0c;为数据交换、通信和处理提供了基础设施。典型应用包括 办公网络数据中心云服务互联网连接 这些网络依靠 TCP/IP、DNS 和 HTTP 等标准协议来促进设备之间的通信。通信路径可能随时发生变化&…

AOC显示器915Sw按键失灵维修记

大家好&#xff0c;我是 程序员码递夫 今天给大家分享的是自己维修老古董AOC液晶显示器按键失灵的的过程&#xff0c;实属DIY记录。 1、引子 家里有台老古董的19寸AOC液晶显示器&#xff08;型号915Sw&#xff09;, 一直作为我的副显示器陪伴着左右&#xff0c;显示还正常&a…

Vscode进行Java开发环境搭建

Vscode进行Java开发环境搭建 搭建Java开发环境(Windows)1.Jdk安装2.VsCode安装3.Java插件4.安装 Spring 插件5.安装 Mybatis 插件5.安装Maven环境6.Jrebel插件7.IntelliJ IDEA Keybindings8. 收尾 VS Code&#xff08;Visual Studio Code&#xff09;是由微软开发的一款免费、开…

【MATLAB源码-第218期】基于matlab的北方苍鹰优化算法(NGO)无人机三维路径规划,输出做短路径图和适应度曲线.

操作环境&#xff1a; MATLAB 2022a 1、算法描述 北方苍鹰优化算法&#xff08;Northern Goshawk Optimization&#xff0c;简称NGO&#xff09;是一种新兴的智能优化算法&#xff0c;灵感来源于北方苍鹰的捕猎行为。北方苍鹰是一种敏捷且高效的猛禽&#xff0c;广泛分布于北…

戴尔 AI Factory 上的 Agentic RAG 搭载 NVIDIA 和 Elasticsearch 向量数据库

作者&#xff1a;来自 Elastic Hemant Malik, Dell Team 我们很高兴与戴尔合作撰写白皮书《戴尔 AI Factory with NVIDIA 上的 Agentic RAG》。白皮书是一份供开发人员参考的设计文档&#xff0c;概述了实施 Agentic 检索增强生成 (retrieval augmented generation - RAG) 应用…