数据结构——概念与时间空间复杂度

目录

前言

一相关概念

1什么是数据结构

2什么是算法

二算法效率

1如何衡量算法效率的好坏

2算法的复杂度

三时间复杂度

1时间复杂度表示

2计算时间复杂度

2.1题一 

2.2题二

2.3题三

2.4题四

 2.5题五

 2.6题六

2.7题七 

2.8题八 

四空间复杂度

1题一

2题二

3题三

4题四

五轮转数组 


前言

数据结构与算法在后期找工作时非常重要(笔试与面试都有,都要求手撕),所以学习时没学完一个知识点要找对应的题去做,反复练习(敲代码)才会使你的认识提升一个档次,下来也要进行归类,画图总结,复习时才轻松点~

一相关概念

1什么是数据结构

数据结构(Data Structure)是计算机存储、组织数据的方式,指相互之间存在一种或多种特定关系的数据元素的集合

简单来说数据结构:在内存中管理数据;而与数据库又有什么关系呢?

               数据库:   在磁盘中管理数据

在C语言中写过的通讯录其实就是数据结构中的一种(数据结构称为顺序表)

而数据结构中不仅只有顺序表,还有链表,栈,队列,树,图...学好数据结构本质就是对常见的数据结构有一定的认识与使用,在后面工作时这些认识也是非常重要的!

2什么是算法

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

二算法效率

1如何衡量算法效率的好坏

对应斐波那契数列:

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

 斐波那契数列的递归实现方式非常简洁,但简洁一定好吗?这样实现是否效率?

2算法的复杂度

算法在编写成可执行程序后,运行时需要耗费时间资源和空间(内存)资源(不同电脑消耗与运行速度不同);衡量一个算法的好坏,一般是从时间空间两个维度来衡量的,即:                                时间复杂度空间复杂度

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

对于面试时的考察主要是写算法题时要求指定的时间复杂度去设计:

三时间复杂度

时间复杂度算法的时间复杂度是一个函数,它定量描述了该算法的运行时间。             

一个算法执行所耗费的时间从理论上说,是算不出来的;只有你把你的程序放在机器上跑起来,才能知道。但是我们需要每个算法都上机测试吗?                                                                              是可以都上机测试,但是这很麻烦,所以才有了时间复杂度这个分析方式。                               

一个算法所花费的时间与其中语句的执行次数成正比例,算法中的基本操作的执行次数,为算法
的时间复杂度。

找时间复杂度:找到某条基本语句与问题规模N之间的数学函数,把对函数影响最大的项数找出来

1时间复杂度表示

一般用大O的渐进表示法
大O符号(Big O notation):是用于描述函数渐进行为的数学符号                                                推导大O阶方法:
1、用常数1取代运行时间中的所有加法常数。
2、在修改后的运行次数函数中,只保留最高阶项。
3、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶

另外有些算法的时间复杂度可能存在最好、平均和最坏情况
一般情况关注的是算法的最坏运行情况

这个道理就好像你中午约别人吃饭,至于要什么时候去,你要想好:正常情况下12:00就下课了,约12:02好?如果下课后有点事(有道题要问老师)岂不是会迟到,约12:15好?那如果最差情况老师拖堂了30分钟呢?所以按照最坏的情况来约时间12:40去吃饭好!其实这也是最好的安排!如果预期老师真的拖堂了,按照约定时间吃饭刚刚好;如果没拖堂的话,我就还有几十分钟的时间来做下一步的打算(回宿舍洗个头换个衣服什么的),按照最坏的情况来说便是最好的打算! 

2计算时间复杂度

2.1题一 

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);
}

Fun1实际执行的操作数:

实际中计算时间复杂度时,不是计算精确的执行次数,而只需要大概执行次数即可;

F(N)中N^2对该函数影响最大(当N越大时,N^2呈现线性增长),所以O(N) = N^2

2.2题二

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);
}

Func2的数学函数:O(N) = 2*N + 10 ,但2可以省略,所以O(N) = N

常数项去掉可以理解,为什么也要把2给忽略掉

你可以这么想:假设当前科技探索到了两颗适合人类居住的星球:一个距离1亿光年,一个距离2亿光年,无论是近的还是远的,当前技术都无法到达那里,所以对于我们来说:无论是近还是远都是无所谓的(方正都到不了),这里省略2也类似的道理~

2.3题三

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);
}

 遇到这种情况就要判断是N大还是M大? 

如果是N大,O(N) = N ;如果是M大,O(N) = M

2.4题四

void Func4(int N)
{
    int count = 0;
    for (int k = 0; k < 100; ++k)
    {
        ++count;
    }
    printf("%d\n", count);
}

N不影响循环的次数,所以:O(N) = 1(常数次) 

 2.5题五

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

该函数是库里面的函数,功能:在str字符串中找到character字符;

所以共有三种情况:

好的情况(第一次就找到了):O(N) = 1 ;

中等情况(在中间位置找到了):O(N) = 2/N

坏的情况(最后一个才找到/找到最后一个后也不是它就是找不到了):O(N) = N;

取最坏的情况作为时间复杂度O(N) = N

 2.6题六

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;
    }
}

如果只是看到两个for循环就判断O(N) = N^2,70%到80%的情况是正确的:分析一般要根据代码思路(本质)来分析得出O(N)(快排实现也是两个循环,但O(N) = N)

以上是实现冒泡函数的代码实现;

第一趟是 n-1 ,第二趟是 n-2,第三趟是 n-3...最后一趟 1;

这刚好就是一个等差数列,进行求和(总的代码执行次数):

n*(a1+an) / 2 = (n-1)*(n-1+1) /2 = (n-1)*n / 1

所以时间复杂度O(N) = N^2

2.7题七 

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;
}

时间复杂度O(N) = log N(log默认下面的数是2)

2.8题八 

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

这里可能有人算的时候是将每层进行相乘,这是不对的!!

因为我们计算的是代码执行的次数

所以时间复杂度O(N) = 2^N

四空间复杂度

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

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

空间复杂度主要通过函数在运行时候显式申请的额外空间来确定

为了区分时间复杂度与空间复杂度,空间复杂度我们用小写n来表示

1题一

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(n) = 1 

2题二

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个数时返回一个大小为n斐波那契数组(储存的是计算好的值)

申请了临时空间,所以O(n) = n 

3题三

long long Fac(size_t N)
{
    if (N == 0)
        return 1;
    return Fac(N - 1) * N;
}

递归的方式计算阶乘,递归层数是N-1层;递归时要计算空间复杂度是用累加的方式进行计算(而时间一去不复返,不能累加),所以O(n) = n 

4题四

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

计算时间复杂度时利用每层递归的层数形成的是一个等比数列的关系后进行累加得到O(N) = 2^N;那么计算空间复杂度也是这样,答案也是O(n) = 2^n?

如果这么想的话,那那就错了!递归的顺序按照下面红线的方式递归  

走到Fib(2)返回到Fib(3)时往下再递归时并不是重新开辟空间,而是重复利用Fib(2)递归时的空间,为什么??

因为此时Fib(2)的空间已经还给OS了,而OS对待即将销毁的空间,不是直接进行我们想象中的销毁,而是让后面来的数据进行覆盖!

所以递归层数 N-2 才是该函数的空间复杂度O(n) = n

五轮转数组 

class Solution
{
public:
    void rotate(vector<int> &nums, int k)
    {
        // O(N) = N O(n) = 1
        // int n=nums.size();
        // k%=n;//一定要%
        // reverse(nums.begin(),nums.begin()+n-k);//前n-k个数翻转
        // reverse(nums.begin()+n-k,nums.end());//后k个数翻转
        // reverse(nums.begin(),nums.end());

        // o(N) = N O(n) = N 空间换时间
        int n = nums.size();
        k %= n;
        vector<int> ret;
        for (int i = n - k; i < n; i++)
            ret.push_back(nums[i]);
        for (int i = 0; i < n - k; i++)
            ret.push_back(nums[i]);
        nums = ret;
    }
};

以上便是全部内容,有问题欢迎在评论区指正,感谢观看!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【转帖】eclipse-24-09版本后,怎么还原原来版本的搜索功能

【1】原贴地址&#xff1a;eclipse - 怎么还原原来版本的搜索功能_eclipse打开类型搜索类功能失效-CSDN博客 https://blog.csdn.net/sinat_32238399/article/details/145113105 【2】原文如下&#xff1a; 更新eclipse-24-09版本后之后&#xff0c;新的搜索功能&#xff08;CT…

Django基础之ORM

一.前言 上一节简单的讲了一下orm&#xff0c;主要还是做个了解&#xff0c;这一节将和大家介绍更加细致的orm&#xff0c;以及他们的用法&#xff0c;到最后再和大家说一下cookie和session&#xff0c;就结束了全部的django基础部分 二.orm的基本操作 1.settings.py&#x…

单片机-STM32 IIC通信(OLED屏幕)(十一)

一、屏幕的分类 1、LED屏幕&#xff1a; 由无数个发光的LED灯珠按照一定的顺序排列而成&#xff0c;当需要显示内容的时候&#xff0c;点亮相关的LED灯即可&#xff0c;市场占有率很高&#xff0c;主要是用于户外&#xff0c;广告屏幕&#xff0c;成本低。 LED屏是一种用发光…

纯css实现div宽度可调整

<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>纯css实现div尺寸可调整</title><style…

国产编辑器EverEdit - 输出窗口

1 输出窗口 1.1 应用场景 输出窗口可以显示用户执行某些操作的结果&#xff0c;主要包括&#xff1a; 查找类&#xff1a;查找全部&#xff0c;筛选等待操作&#xff0c;可以把查找结果打印到输出窗口中&#xff1b; 程序类&#xff1a;在执行外部程序时(如&#xff1a;命令窗…

小游戏源码开发搭建技术栈和服务器配置流程

近些年各种场景小游戏开发搭建版本层出不穷,山东布谷科技拥有多年海内外小游戏源码开发经验&#xff0c;现为从事小游戏源码开发或游戏运营的朋友们详细介绍小游戏开发及服务器配置流程。 一、可以对接到app的小游戏是如何开发的 1、小游戏源码开发的需求分析&#xff1a; 明…

Linux C\C++编程-文件位置指针与读写文件数据块

【图书推荐】《Linux C与C一线开发实践&#xff08;第2版&#xff09;》_linux c与c一线开发实践pdf-CSDN博客 《Linux C与C一线开发实践&#xff08;第2版&#xff09;&#xff08;Linux技术丛书&#xff09;》(朱文伟&#xff0c;李建英)【摘要 书评 试读】- 京东图书 Linu…

一文简单回顾复习Java基础概念

还是和往常一样&#xff0c;我以提问的方式回顾复习&#xff0c;今天回顾下Java小白入门应该知道的一些基础知识 Java语言有哪些特点呢&#xff1f; Java语言的特点有&#xff1a; 面向对象&#xff0c;主要是封装、继承、多态&#xff1b;平台无关性&#xff0c;“一次编写…

Redis实战(黑马点评)——关于缓存(缓存更新策略、缓存穿透、缓存雪崩、缓存击穿、Redis工具)

redis实现查询缓存的业务逻辑 service层实现 Overridepublic Result queryById(Long id) {String key CACHE_SHOP_KEY id;// 现查询redis内有没有数据String shopJson (String) redisTemplate.opsForValue().get(key);if(StrUtil.isNotBlank(shopJson)){ // 如果redis的数…

神经网络|(四)概率论基础知识-古典概型

【1】引言 前序学习了线性回归的基础知识&#xff0c;了解到最小二乘法可以做线性回归分析&#xff0c;但为何最小二乘法如此准确&#xff0c;这需要从概率论的角度给出依据。 因此从本文起&#xff0c;需要花一段时间来回顾概率论的基础知识。 【2】古典概型 古典概型是我…

【C++】特殊类设计、单例模式与类型转换

目录 一、设计一个类不能被拷贝 &#xff08;一&#xff09;C98 &#xff08;二&#xff09;C11 二、设计一个类只能在堆上创建对象 &#xff08;一&#xff09;将构造函数私有化&#xff0c;对外提供接口 &#xff08;二&#xff09;将析构函数私有化 三、设计一个类只…

微服务网关鉴权之sa-token

目录 前言 项目描述 使用技术 项目结构 要点 实现 前期准备 依赖准备 统一依赖版本 模块依赖 配置文件准备 登录准备 网关配置token解析拦截器 网关集成sa-token 配置sa-token接口鉴权 配置satoken权限、角色获取 通用模块配置用户拦截器 api模块配置feign…

16.好数python解法——2024年省赛蓝桥杯真题

问题描述 一个整数如果按从低位到高位的顺序,奇数位(个位、百位、万位…)上的数字是奇数,偶数位(十位、千位、十万位…)上的数字是偶数,我们就称之为“好数”。 给定一个正整数N,请计算从1到N一共有多少个好数。 输入格式 一个整数N。 输出格式 一个整数代表答案。 样例输入 1 …

2025年数学建模美赛 A题分析(2)楼梯使用频率数学模型

2025年数学建模美赛 A题分析&#xff08;1&#xff09;Testing Time: The Constant Wear On Stairs 2025年数学建模美赛 A题分析&#xff08;2&#xff09;楼梯磨损分析模型 2025年数学建模美赛 A题分析&#xff08;3&#xff09;楼梯使用方向偏好模型 2025年数学建模美赛 A题分…

Redis实战(黑马点评)——涉及session、redis存储验证码,双拦截器处理请求

项目整体介绍 数据库表介绍 基于session的短信验证码登录与注册 controller层 // 获取验证码PostMapping("code")public Result sendCode(RequestParam("phone") String phone, HttpSession session) {return userService.sendCode(phone, session);}// 获…

Brightness Controller-源码记录

Brightness Controller 亮度控制 一、概述二、ddcutil 与 xrandr1. ddcutil2. xrandr 三、部分代码解析1. icons2. ui3. utilinit.py 一、概述 项目&#xff1a;https://github.com/SunStorm2018/Brightness.git 原理&#xff1a;Brightness Controlle 是我在 Ubuntu 发现上调…

STM32简介

STM32简介 STM32是ST公司基于ARMCortex-M内核开发的32位微控制器 &#xff08;Microcontroller&#xff09; MCU微控制器、MPU微处理器、CPU中央处理器 1.应用领域 STM32常应用于嵌入式领域。 如智能车&#xff1a;循迹小车 读取光电传感器或者摄像头的数据&#xff0c;…

qt-C++笔记之QLine、QRect、QPainterPath、和自定义QGraphicsPathItem、QGraphicsRectItem的区别

qt-C笔记之QLine、QRect、QPainterPath、和自定义QGraphicsPathItem、QGraphicsRectItem的区别 code review! 参考笔记 1.qt-C笔记之重写QGraphicsItem的paint方法(自定义QGraphicsItem) 文章目录 qt-C笔记之QLine、QRect、QPainterPath、和自定义QGraphicsPathItem、QGraphic…

浏览器IndexedDB占用大

使用鲁大师清理后&#xff0c;用 SpaceSniffer 查看C盘占用情况&#xff0c;发现浏览器的 IndexedDB 有3个文件夹占用特别大&#xff0c;从文件名看是 youku&#xff0c;bilibili&#xff0c;v.qq.com&#xff0c;浏览器的数据库并不需要长期保存&#xff0c;删除这3个文件夹&a…

MongoDB部署模式

目录 单节点模式&#xff08;Standalone&#xff09; 副本集模式&#xff08;Replica Set&#xff09; 分片集群模式&#xff08;Sharded Cluster&#xff09; MongoDB有多种部署模式&#xff0c;可以根据业务需求选择适合的架构和部署方式。 单节点模式&#xff08;Standa…