【数据结构】入门及时间空间复杂度的介绍

news2024/10/6 14:26:03

🌱博客主页:大寄一场.

🌱系列专栏:数据结构与算法

  😘博客制作不易欢迎各位👍点赞+⭐收藏+➕关注
75486fdc2eee4efba3dfc46f574e64ef.gif#pic_center

目录

前言

1.什么是数据结构?

2.什么是算法?

3.数据结构和算法的重要性

4.常见的数据结构及算法

一、算法效率的衡量

二、时间复杂度

1. 时间复杂度的定义:

2.大O的渐进表示法

3.小试牛刀

二、空间复杂度

1.空间复杂度的定义:

2.小试牛刀 

三、常见复杂度的对比


前言

在学习数据结构与算法之前我们得先明白以下几点:

1.什么是数据结构

数据结构(Data Structure)是计算机存储、组织数据的方式,指相互之间存在一种或多种特定关系的数据元素的集合,它涉及到如何组织和存储数据,以便在程序中进行高效的访问和操作。

2.什么是算法

算法(Algorithm):就是定义良好的计算过程,他取一个或一组的值为输入,并产生出一个或一组值作为输出。简单来说算法就是一系列的计算步骤,用来将输入数据转化成输出结果。

3.数据结构和算法的重要性

  1. 高效解决问题:数据结构和算法可以帮助我们更有效地解决各种问题,包括排序、搜索、图形遍历等。通过使用合适的数据结构和算法,我们可以大大提高计算效率,节省时间和空间资源。

  2. 可扩展性:随着计算机硬件和软件的发展,我们需要处理的问题变得越来越复杂。数据结构和算法提供了一种可扩展的方法来应对这些挑战,使得我们能够更好地适应不断变化的需求。

  3. 优化程序性能:对于需要大量计算的应用程序,优化程序性能至关重要。数据结构和算法可以帮助我们减少不必要的计算,提高程序运行速度,从而提高用户体验。

  4. 提高代码质量:使用适当的数据结构和算法可以确保我们的代码更加简洁、易于理解和维护。这有助于提高代码质量,降低出错概率,并为团队协作创造更好的环境。

  5. 适用于各种领域:数据结构和算法不仅在计算机科学领域具有重要意义,而且在其他领域也发挥着关键作用。例如,在金融、医疗、物流等领域,高效的数据处理方法同样具有重要价值。

4.常见的数据结构及算法

常见的数据结构包括:

  1. 数组(Array):一组相同类型的数据,通过下标访问。
  2. 链表(Linked List):由节点组成,每个节点包含数据和指向下一个节点的指针。
  3. 栈(Stack):一种后进先出(LIFO)的数据结构,只能在栈顶进行插入和删除操作。
  4. 队列(Queue):一种先进先出(FIFO)的数据结构,只能在队尾进行插入操作,在队头进行删除操作。
  5. 树(Tree):由节点组成,每个节点包含数据和指向子节点的指针。
  6. 图(Graph):由节点和边组成,节点可以有多个相邻节点。

常见的算法包括:

  1. 排序算法(Sorting Algorithm):将一组数据按照一定规则进行排序,如冒泡排序、选择排序、插入排序、快速排序等。
  2. 查找算法(Search Algorithm):在一个有序的数据集中查找指定的数据,如二分查找、线性查找等。
  3. 递归算法(Recursion Algorithm):通过函数自身的调用实现对问题的解决,如斐波那契数列、阶乘等。
  4. 动态规划算法(Dynamic Programming Algorithm):通过将问题分解成更小的子问题来解决复杂问题,如背包问题、最长公共子序列等。
  5. 贪心算法(Greedy Algorithm):每次选择当前最优解来解决问题,如最小生成树算法、最短路径算法等。

一、算法效率的衡量

那么提到算法效率,我们肯定想知道如何衡量一个算法的好坏?

比如对于以下斐波那契数列:

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

斐波那契数列的递归实现方式非常简洁,但简洁一定好吗?那该如何衡量其好与坏呢?

 算法的复杂度

        算法在编写成可执行程序后,运行时需要耗费时间资源和空间(内存)资源 。因此衡量一个算法的好坏,一般是从时间空间两个维度来衡量的,即时间复杂度和空间复杂度

        时间复杂度主要衡量一个算法的运行快慢,而空间复杂度主要衡量一个算法运行所需要的额外空间。在计算机发展的早期,计算机的存储容量很小。所以对空间复杂度很是在乎。但是经过计算机行业的迅速发展,计算机的存储容量已经达到了很高的程度。所以我们如今已经不需要再特别关注一个算法的空间复杂度。

二、时间复杂度

那么我们首先了解一下什么是时间复杂度。

1. 时间复杂度的定义:

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

即:找到某条基本语句与问题规模N之间的数学表达式,就是算出了该算法的时间复杂度。

  实际中我们计算时间复杂度时,我们其实并不一定要计算精确的执行次数,而只需要大概执行次数,那么这里我们使用大O的渐进表示法。

2.大O的渐进表示法

大O符号(Big O notation):是用于描述函数渐进行为的数学符号。

推导大O阶方法:

1、用常数1取代运行时间中的所有加法常数。

2、在修改后的运行次数函数中,只保留最高阶项。

3、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。

另外有些算法的时间复杂度存在最好、平均和最坏情况:

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

例如:在一个长度为N数组中搜索一个数据x

  • 最好情况:1次找到
  • 最坏情况:N次找到
  • 平均情况:N/2次找到

在实际中一般情况关注的是算法的最坏运行情况,所以数组中搜索数据时间复杂度为O(N)

那么光说理论肯定不好理解,那么我们牛刀小试一下:

3.小试牛刀

实例1:

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

        操作执行了2N+10次->O(2n+10);

        通过推导大O阶方法->时间复杂度为 O(N)

实例2:

// 计算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,

        若M>N,则O(M);

        若M<N,则O(N,);

        这时我们并不知道M,N哪个大,所以时间复杂度为 O(N+M)

实例3:

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

         操作执行了10次->O(10)

         通过推导大O阶方法,常数的时间复杂度为 O(1)

实例4:

// 计算strchr的时间复杂度?
const char * strchr ( const char * str, int character );
char *strchr(const char *str, int c) {
    for (; *str != c; str++) {
        
    }
    return (char *)str;
}

     

        最好1次->O(1)

        最坏N次->O(N)

        故时间复杂度为 O(N)

实例5:

// 计算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次->O(N)

        最坏(N*(N+1)/2次->O((N*(N+1)/2)     

        故时间复杂度为 O(N^2)

实例6:

// 计算BinarySearch的时间复杂度?
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;
}

最好1次,

最坏log2(n)次,

时间复杂度为 O(logN)

第几次查询剩余待查询元素数量
1N/2
2N/(2^2)
3N/(2^3)
NN/(2^N)

ps:为何是logN 而不是log2 (N)

假如有logaB(a为底数),由换底公式可得:

img

logcA(c为底数)为常数,

由O的运算规则"O( C × f(N) )=O( f(N ) ),

其中C是一个正的常数

得O(logaB)=O(logcB)

可知算法的时间复杂度与不同底数只有常数的关系,均可以省略自然可以用logN代替。

实例7:

// 计算阶乘递归Fac的时间复杂度?
long long Fac(size_t N)
{
 if(0 == N)
     return 1;
​
 return Fac(N-1)*N;
}

通过计算分析发现基本操作递归了N次,时间复杂度为O(N)

实例8:

// 计算斐波那契递归Fib的时间复杂度?
long long Fib(size_t N)
{
 if(N < 3)
     return 1;
​
 return Fib(N-1) + Fib(N-2);
}

通过计算分析发现基本操作递归了2^N次,时间复杂度为O(2^N)。(建议画图递归栈帧的二叉树讲解)

二、空间复杂度

1.空间复杂度的定义:

空间复杂度也是一个数学表达式,是对一个算法在运行过程中临时占用存储空间大小的量度 

空间复杂度不是程序占用了多少bytes的空间,因为这个也没太大意义,所以空间复杂度算的是变量的个数。空间复杂度计算规则基本跟实践复杂度类似,也使用大O渐进表示法

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

2.小试牛刀 

实例1:

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

     使用了常数个额外空间,所以空间复杂度为 O(1)

实例2:

// 计算Fibonacci的空间复杂度?
// 返回斐波那契数列的前n项
long long* Fibonacci(size_t n)
{
 if(n==0)
      return NULL;
​
 long long * fibArray = (long long *)malloc((n+1) * sizeof(long long));
 fibArray[0] = 0;
 fibArray[1] = 1;
 for (int i = 2; i <= n ; ++i)
 {
     fibArray[i] = fibArray[i - 1] + fibArray [i - 2];
 }
​
 return fibArray;
}

        动态开辟了N个空间,空间复杂度为 O(N)

实例3:

// 计算阶乘递归Fac的空间复杂度?
long long Fac(size_t N)
{
 if(N == 0)
     return 1;
​
    return Fac(N-1)*N;
}

        递归调用了N次,开辟了N个栈帧,每个栈帧使用了常数个空间。空间复杂度为O(N)

三、常见复杂度的对比

执行次数举例非正式术语
52013140(1)常数阶
3n+40(n)线性阶
3n^2+4n+50(n^2)平方阶
3log(2)n+40(logn)对数阶
2n+3nlog(2)n+140(nlogn)nlogn阶
n^3+2n^2+4n+60(n^3)立方阶
2^n0(2^n)指数阶

 

 

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

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

相关文章

【杂记】Rest风格

文章目录 1.什么是Rest&#xff1f;2.URI URL URN3.什么是Restful架构风格4.状态转换 1.什么是Rest&#xff1f; Rest是一种软件架构的风格。 英文名称&#xff1a;REpresentational State Transfer&#xff08;表现层状态转移&#xff09; 加上主语&#xff1a;Resource Repr…

Linux网络基础-3

在上一篇网络基础的博客当中&#xff0c;我们对应用层协议--HTTP协议进行了详解&#xff0c;接下来我们对传输层协议进行详解 目录 1.传输层协议 2.UDP协议 2.1协议内容 2.2协议格式 2.3协议特性 3.TCP协议 3.1协议内容 3.2协议格式 3.3协议特性 3.3.1三次握手建立连…

Bootstrap开发之——Bootstrap安装及使用(02)

一 概述 Bootstrap下载npm安装bootstrap并使用(vue中使用)bootstrap通过本地lib导入并使用(html)bootstrap通过cdn导入并使用(html) 二 Bootstrap下载 2.1 Bootstrap下载(v3.x版本为例) 在Bootstrap中文官网&#xff0c;点击顶部的入门标签&#xff0c;在如下图页面点击下载…

Linux——对权限的理解

文章目录 总述Linux权限的概念Linux 权限管理Linux对文件访问者的分类文件类型和访问权限a.文件类型b.基本权限文件权限修改的相关方法 其他问题在首次创建时文件的权限属性是固定的吗&#xff1f;目录的权限粘滞位 总述 本篇博客将主要讲解linux系统中权限的概念&#xff0c;权…

Sort练习题

sort 练习 练习题 题目&#xff1a;浮点数排序 #define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <algorithm> //sort()排序 #include <cmath> //round()来找最近的整数 using namespace std; const double EPSILON 1e-6; //两个浮点…

web框架:Iris快速入门

web框架&#xff1a;Iris快速入门 1 介绍及安装 介绍 Iris是一款用Go开发的web应用框架&#xff0c;被称为速度最快的Go后端开发框架。官网地址&#xff1a;https://www.iris-go.com/中文教程地址&#xff1a;http://www.codebaoku.com/iris/iris-index.html 安装 环境要求&a…

QTableView编程——Model/View架构(单元格随意拖拽交换)

QTableView编程——Model/View架构 基础知识 添加表头 //准备数据模型QStandardItemModel *student_model new QStandardItemModel();student_model->setHorizontalHeaderItem(0, new QStandardItem(QObject::tr("Name")));student_model->setHorizontalHea…

【Redis】Redis位图(bitmap)介绍和在签到场景的应用

文章目录 一、前言二、redis位图相关指令setbit命令getbit命令bitcount命令bitfield命令bitpos命令bitop命令 三、应用场景累计签到应用场景连续签到应用场景日期签到场景应用详情 一、前言 基本原理&#xff1a; 《Redis设计与实现》中对位图的实现描述是&#xff1a;Redis使…

做软件测试我该如何快速摸清一家公司的基本情况?

当你准备进入一家新的公司作为软件测试人员时&#xff0c;了解公司的基本情况对于你快速适应新环境和工作非常重要。下面是几个方面可以帮助你快速摸清一家公司的基本情况&#xff1a; 如果你想学习软件测试&#xff0c;我这边给你推荐一套视频&#xff0c;这个视频可以说是B站…

8. 高性能业务表结构设计和索引知识深化

MySQL性能调优 1. 数据库表设计1.1 范式化设计1.1.1 什么是范式&#xff1f;1.1.2 第一范式&#xff08;1NF&#xff09;1.1.2 第二范式&#xff08;2NF&#xff09;1.1.3 第三范式&#xff08;3NF&#xff09; 1.2 反范式设计1.2.1 什么叫反范式化设计 1.3 范式化和反范式总结…

分析SpringBoot 底层机制【Tomcat 启动分析+Spring 容器初始化+Tomcat 如何关联Spring 容器之源码分析

目录 分析SpringBoot 底层机制【Tomcat 启动分析Spring 容器初始化Tomcat 如何关联Spring 容器之源码分析 搭建SpringBoot 底层机制开发环境 创建Maven 项目wyx-springboot 修改pom.xml , 导入相关依赖 创建MainApp.java 启动项目ok, 大家注意Tomcat 也启动了[这里思考, …

机器学习期末复习 BP神经网络的推导,4X4X3,激活函数变为Logistic函数,其他不变

刚写完了bp神经网络的实验课代码&#xff0c;对这个比较熟悉&#xff08;后面给出实现代码&#xff09; Logistic函数也就是sigmod函数&#xff0c;表达式是这样的&#xff1a; def sigmod(x):return 1/(1math.exp(-x)) sigmod函数是隐层和输出层的激活函数&#xff08;sigmo…

如何本地搭建Plex私人影音云盘教程,实现Plex家庭影音中心,打造超级多媒体中心

文章目录 1.前言2. Plex网站搭建2.1 Plex下载和安装2.2 Plex网页测试2.3 cpolar的安装和注册 3. 本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4. 公网访问测试5. 结语 转发自CSDN远程穿透的文章&#xff1a;免费搭建Plex家庭影音中心 - 打造超级多媒体中心【公网远程访问…

WEBPACK、VITE 常用配置(对照)及迁移指南

文中 Webpack 版本为 5.x&#xff0c;Vite 版本为 4.3.x webpack 是新一代构建工具里面的老大哥了&#xff0c;从 2013 年发布已经持续升级 10 年&#xff0c;形成完备的生态环境。vite 则是下一代前端开发与构建工具&#xff0c;2019年发布&#xff0c;最新发布版本 4.3.3&…

文件操作安全之-文件上传告警运营篇

本文从文件上传的定义&#xff0c;文件上传的IDS规则&#xff0c;文件上传的示例&#xff0c;文件上传的告警研判&#xff0c;文件上传的处置建议等几个方面阐述如何通过文件上传类型的告警的线索&#xff0c;开展日常安全运营工作&#xff0c;从而挖掘有意义的安全事件。 文件…

rtl仿真器-iverilog icarus安装和测试

Icarus Verilog是一个轻量、免费、开源的Verilog编译器&#xff0c;基于C实现&#xff0c;开发者是 Stephen Williams &#xff0c;遵循 GNU GPL license 许可证&#xff0c;安装文件中已经包含 GTKWave支持Verilog/VHDL文件的编译和仿真&#xff0c;命令行操作方式&#xff0c…

C语言函数大全-- _w 开头的函数(1)

C语言函数大全 本篇介绍C语言函数大全-- _w 开头的函数 1. _waccess 1.1 函数说明 函数声明函数功能int _waccess(const wchar_t* path, int mode);用于测试文件或目录是否存在&#xff0c;并检查程序是否具有对它们的访问权限 参数&#xff1a; path &#xff1a; 待测试的…

Elasticsearch(三)

Elasticsearch(三) 数据聚合 聚合的分类 文档&#xff1a;https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations.html 聚合可以实现对文档数据的统计、分析、运算。聚合常见的有三类&#xff1a; 桶聚合&#xff1a;用来对文档做分组 Te…

【P22】JMeter 调试后置处理程序(Debug PostProcessor)

&#xff08;1&#xff09;、测试计划右键 <<< 添加 <<< 线程&#xff08;用户&#xff09;<<< 线程组 默认参数即可 &#xff08;2&#xff09;、线程组右键 <<< 添加 <<< 取样器 <<< 调试取样器 默认参数即可 &…