【数据结构与算法——TypeScript】算法的复杂度分析、 数组和链表的对比

news/2024/11/24 14:06:04/

【数据结构与算法——TypeScript】

算法的复杂度分析

什么是算法复杂度(现实案例)?

❤️‍🔥 前面已经解释了什么是算法? 其实就是解决问题的一系列步骤操作、逻辑。
对于同一个问题,我们往往有很多种解决思路和方法,也就是可以采用不同的算法。

  • 举个例子(现实例子):在一个庞大的图书馆中,我们需要找一本书

    • 在图书已经按照某种方式摆好的情况下(数据结构是固定的)
  • 方式一:顺序查找

    • 一本一本找,直到找到想要的书;
  • 方式二:先分类找,分类中找这本书

    • 先找到分类,在分类中再顺序或某种方式查找
  • 方式三:找到检索电脑,查找书的位置,直到找到

    • 图书馆通常有自己的图书管理系统
    • 利用图书管理系统先找到书的位置,再直接过去找到

什么是算法复杂度(程序案例)?

🖥 在具体一个程序中的案例:让我们用两种不同算法查找数组中(数组有序)给定元素的复杂度

  • ✅ 方式一:顺序查找
    • 这种算法 从头到尾遍历整个数组,依次比较每个元素和给定元素的值
    • 如果 找到相等的元素,则返回下标;如果 遍历完整个数组都没找到,则返回 -1

复杂度-顺序查找

  /**- 顺序查找- @param array 查找的数组- @param 查找的元素- @returns 查找到的索引,未找到返回-1*/function sequentSearch(array: number[], num: number) {for (let i = 0; i < array.length; i++) {const element = array[i];if (element === num) return i;}return -1;}const index = sequentSearch([1, 3, 5, 10, 100, 222, 333, 334, 555, 556], 222);console.log(index);
  • ✅ 方式二:二分查找

    • 这种算法假设数组是有序的,每次 选择数组中间的元素与给定元素进行比较
    • 如果 相等,则返回下标;如果 给定元素比中间元素小,则在数组的左半部分继续查找
    • 如果 给定元素比中间大,则在数组的右半部分继续查找
    • 这样 每次查找都会将查找范围减半,直到找到想等的元素或者查找范围为空

    在这里插入图片描述

    function binarySearch(array: number[], num: number) {
    // 1. 定义左右索引
    let left = 0;
    let right = array.length - 1;// 2.开始查找
    while (left <= right) {let mid = Math.floor((left + right) / 2);const midNum = array[mid];if (midNum === num) {return mid;} else if (midNum < num) {left = mid + 1;} else {right = mid - 1;}
    }
    return -1;
    }
    const index = binarySearch([1, 3, 5, 10, 100, 222, 333, 334, 555, 556], 222);
    console.log(index);
    export {};
    

测试顺序查找和二分查找的代码

  • 使用🔧工具: npm install hy-algokit
import sequentSearch from './01_查找算法-顺序查找';
import binarySearch from './02_查找算法-二分查找';
import { testOrderSearchEfficiency } from 'hy-algokit';
testOrderSearchEfficiency(sequentSearch);
testOrderSearchEfficiency(binarySearch);

在这里插入图片描述

  • ❤️‍🔥 顺序查找算法的时间复杂度是 O(n)

  • ❤️‍🔥 二分查找算法的时间复杂度是 O(log n)

大O表示法(Big O notation)

  • 大O表示法(Big O notation)英文翻译为大O符号,中文通常翻译为大O表示法(标记法)。
  • 大O符号在分析 算法效率的时候非常有用
    • 🌰 举例:解决 **一个规模为n的问题所花费的时间(或需要步骤的数目)可以表示为:
      • T(n)= 4n⌃2^ - 2n + 2**
      • n 增大 时, n^2^ 项开始 占据主导地位,其他各项可以被忽略
    • 🌰 : 当 n = 500
      • 4n2 项是 2n 项的 1000倍大,因此在大多数场合下, 省略后者对表达式的值的影响将是乐意忽略不计的

      • 进一步,如果我们与任一其他级的表达式比较, n2的系数也是无关紧要的的。

      • 这样,针对第一个例子, T(n)= 4 n2 - 2n + 2,大O符号就记下剩余的部分,写作:

        • T(n) ∈ O(n2)

          或者

        • T(n) = O(n2)

  • ❣️ 我们就说该算法 具有n2 阶(平方阶)的时间复杂度,表示为O(n2)

常见的对数阶

  • 常用的函数阶
符号名称
O(1)常数(阶、下同)
O(log n)对数
O(n)线性、次线性
O(n log n)线性对数、或者对数线性、拟线性、超线性
O(n2)平方
O(n2) , Interger(c > 1)多项式,有时叫作‘代数’(阶)
O(cn)指数,有时叫作“几何”(阶)

空间复杂度

  • 空间复杂度指的是,程序运行过程中所需要的额外存储空间。

    • 空间复杂度 也可以用大O表示法来表示;
    • **空间复杂度的计算方法与时间复杂度类似,**通常需要分析程序中 需要额外分配的内存空间,如数组、变量、对象、递归调用等
  • 🌰 :举例

    • 对于一个简单的 递归算法来说,每次调用会在内存中分配新的栈帧,这些栈帧占用了额外的空间
      • 因此,该算法的空间复杂度是 O(n),其中n是递归深度
    • 而对于 迭代算法来说,在 **每次迭代中不需要分配额外的空间,**因此 其空间复杂度为O(1)
  • 当空间复杂度很大时,可能会导致内存不足,程序崩溃。

  • 在平时进行算法优化时,我们通常会进行如下考虑:

    • 使用尽量少的空间(优化空间复杂度)
    • 使用尽量少的时间(优化时间复杂度)
    • 特定情况下:使用 空间换时间或使用 时间换空间

数组和链表的对比

  • 使用大O表示法来对比一下数组和链表的时间复杂度(增删改查)
Data StructureAccessSearchInsertionDeletion
ArrayO(1)O(N)O(N)O(N)
Linked ListO(N)O(N)O(1)O(1)
  • 数组是一种连续的存储结构,通过下标可以直接访问数组中的任意元素

    • 时间复杂度: 对于数组,随机访问时间复杂度为O(1),插入和删除操作的时间复杂度为O(n)。
    • 空间复杂度:数组需要连续的存储空间,空间复杂度为 O(n)
  • 链表,是一种链式存储结构,通过指针链接起来的节点组成,访问链表中元素需要从头结点开始遍历

    • **时间复杂度:**对于链表,随机访问时间复杂度为O(n),插入和删除的时间复杂度为O(1)
    • **空间复杂度:**链表需要为每个节点分配存储空间,空间复杂度为O(n)
  • 💖 在实际开发中,选择使用数组还是链表需要根据具体应用场景来决定

    • 如果数据量不大,且需要频繁随机访问元素,使用数组可能会更好
    • 如果数据量很大,或者需要频繁插入和删除元素,使用链表可能会更好

【数据结构与算法——TypeScript】系列笔记:
1. 【数据结构与算法——TypeScript】数组、栈、队列、链表


http://www.ppmy.cn/news/1005973.html

相关文章

DoIP学习笔记系列:(四)用CAPL脚本读取DID的关键点

文章目录 1. 如何在CAPL中读取DID?1.1 避坑如何新建CAPL工程,在此不再赘述,本章主要分享一下如何在CAPL中调用DoIP接口、diag接口进行DoIP和诊断的测试。 1. 如何在CAPL中读取DID? 通常在实际项目中,会有很多DID,各种版本号、各种观测量,如果手动点,显然很麻烦,如果要…

Filebeat+ELK 部署

目录 //在 Node1 节点上操作 1&#xff0e;安装 Filebeat 2&#xff0e;设置 filebeat 的主配置文件 3&#xff0e;在 Logstash 组件所在节点上新建一个 Logstash 配置文件 4&#xff0e;浏览器访问 http://192.168.193.40:5601 登录 Kibana&#xff0c;单击“Create In…

在vue项目中封装WebSockets请求

在Vue项目中封装WebSocket请求包括以下步骤&#xff1a; 1. 安装WebSocket库&#xff1a;首先&#xff0c;导入WebSocket库&#xff0c;例如vue-native-websocket或socket.io-client。根据项目需求选择适当的库&#xff0c;并根据官方文档进行安装和配置。 2. 创建WebSocket服务…

Redis 如何解决缓存雪崩、缓存击穿、缓存穿透难题

前言 Redis 作为一门热门的缓存技术&#xff0c;引入了缓存层&#xff0c;就会有缓存异常的三个问题&#xff0c;分别是缓存击穿、缓存穿透、缓存雪崩。我们用本篇文章来讲解下如何解决&#xff01; 缓存击穿 缓存击穿: 指的是缓存中的某个热点数据过期了&#xff0c;但是此…

测试人员简单使用Jenkins

一、测试人员使用jenkins干什么&#xff1f; 部署测试环境 二、相关配置说明 一般由开发人员进行具体配置 1.Repository URL&#xff1a;填写git地址 2.填写开发分支&#xff0c;测试人员可通过相应分支进行测试环境的构建部署 当多个版本并行时&#xff0c;开发人员可以通过…

获取SQL语句表名,判断DDL类型

1.在maven中引入jsqlparser依赖 <!--sql语句解析--><dependency><groupId>com.github.jsqlparser</groupId><artifactId>jsqlparser</artifactId><version>4.4</version></dependency>2.解析SQL语句具体代码 此代码解析…

人工智能学习07--pytorch23--目标检测:Deformable-DETR训练自己的数据集

参考 https://blog.csdn.net/qq_44808827/article/details/125326909https://blog.csdn.net/dystsp/article/details/125949720?utm_mediumdistribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-0-125949720-blog-125326909.235^v38^pc_releva…

QtAV for ubuntu16.04

下载ubuntu https://releases.ubuntu.com/16.04/ubuntu-16.04.7-desktop-amd64.iso 下载ffmpeg https://ffmpeg.org/download.html 下载QtAV https://github.com/wang-bin/QtAV/releases 更新 sudo apt update 安装库 sudo apt-get install libglu1-mesa-dev freeglut3-dev…