对数据结构的初步认识

news/2024/4/26 16:08:11/文章来源:https://blog.csdn.net/qq_67276605/article/details/130323837

在这里插入图片描述

前言:

牛牛开始更新数据结构的知识了.本专栏后续会分享用c语言实现顺序表,链表,二叉树,队列,排序算法等相关知识,欢迎友友们互相学习,可以私信互相讨论哦!

🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨
🐻推荐专栏: 🍔🍟🌯 c语言初阶
🔑个人信条: 🌵知行合一
🍉本篇简介:>:讲解数据结构的入门知识,时间复杂度与空间复杂度,以及一些对学习数据结构的建议.
金句分享:
✨最快的脚步不是冲刺,而是坚持!✨

目录

  • 前言:
    • 1、数据结构是什么?
    • 2、数据结构应该怎么学呢?
  • 算法效率如何衡量?
    • 一、 时间复杂度
      • 大O的渐进表示法
      • 时间复杂度的练习:
      • 1.1 常见的时间复杂度:
      • 1.2 冒泡排序的时间复杂度
      • 1.3 "二分查找"的时间复杂度
      • 1.4 递归的时间复杂度:
      • 常见量级的比较图
    • 二、空间复杂度

1、数据结构是什么?

数据结构+算法=程序.

数据结构(Data Structure):是计算机存储、组织数据方式,指相互之间存在一种或多种特定关系的数据元素的集合。
例如后面会提到的顺序表,链表这些线性数据结构,还有后面的二叉树树形数据结构等.

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

数据结构与算法对于一个程序员是很重要的,不论对你思考问题的方式还是对你编程的思维都会有很大的好处。同时在找工作时算法也是一个重要考点之一.

2、数据结构应该怎么学呢?

1.多多练习代码.
在这里插入图片描述

数据结构的学习并不简单,需要多锻炼代码能力,最怕偷懒,很多时候头脑虽然理解了,但是动起手来写代码会忽略很多细节,导致程序出错,不能光有思路,而代码能力却实现不了就很尴尬了.

2.多画图(这个强烈推荐)

除了代码能力需要锻炼以外,很重要的一点是要有思路,通过画图辅助,可以很好地帮助我们找到思路和理解数据结构中的很多思想,切忌上来就开始码代码,这样对于简单的问题可能可以解决,但是对于稍微复杂的问题可能会让你头痛(大佬除外😂😂),很容易被绕进去,陷入痛苦的调试找bug环节.
画图会让提供给我们清晰的思路,同时,即使出现了bug,也可以很快的找到,清晰可见.写代码只是用于实现思路,思路清晰,代码写起来并不困难.

3.刷题
刷题会锻炼我们的思考能力,解题是一种很灵活的事情.一方面可以巩固我们学的基础知识,另一方面可以拓展思维.
最后,坚持学习才是最重要的.
在这里插入图片描述

算法效率如何衡量?

对于一个问题,可以有很多解法,那怎样衡量一个算法的好坏呢?
比谁的代码更简洁吗?
算法的效率主要考虑两点:1.时间复杂度. 2.空间复杂度

一个算法在编译生成可执行文件后,运行时会耗费时间资源和空间(内存)资源
从时间和空间两个维度来衡量一个算法的好坏是比较合理的,这就是时间复杂度空间复杂度

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

一、 时间复杂度

时间复杂度的定义:在计算机科学中,算法的时间复杂度是一个函数,它定量描述了该算法的运行时间。一个算法执行所耗费的时间.

但是从理论上说,这个只有将代码进行测试,并统计时间才能知道.并不能通过计算得到.
但对于每一个算法,我们都去跑一下,这未免显得有些麻烦,我们可以通过算法中的代码估计运行大概的时间,看看属于哪一个量级来衡量它的效率.

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

理论不是很理解的话,我们来点实际的,找几段代码算算吧!

🌰小试牛刀
你能算出在test1中++count语句最终被执行了多少次吗?

void test1(int N)
{int count = 0;//1for (int i = 0; i < N; i++){for (int j = 0; j < N; j++){++count;}}//2for (int k = 0; k < N; k*=2){++count;}//3for (int k = 0; k < 2 * N; k++){++count;}//4int a = 100;while (a--){++count;}printf("%d\n", count);
}

答案:
1: N * N
2: log2 N
3. 2*N
4. 100

则我们可以抽象出这样的数学公式:

         test(N)=N2 +log2 N+2N+100

大O的渐进表示法

计算机的运行速度是很快的,对于时间复杂度的计算,没有必要追求那么精确,对于那些对结果影响不大的项,我们可以忽略不计.如果我们只保留N2这一起决定因素的项.

大O阶方法计算方法:

  • 1、用常数1取代运行时间中的所有加法常数
  • 2、在修改后的运行次数函数中,只保留最高阶项
  • 3、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。

使用大O的渐进表示法以后,test1的时间复杂度为:

(O)N ^ 2

即使是100N系数也应当去掉,因为当数据足够大的时候100的影响并不大.
只要是常数,都应当是1.
也许你会认为100很大或者100000很大.但是,要看和谁比,如果是和10亿比呢?一万亿比呢?
那我们打个比方:

你觉得你们学校大吗?还行.
你所在的城市大吗?算大吧!
你觉得我们的祖国大吗?地大物博,确实大.

但是,与太阳系相比呢?与银河系相比呢?这就显得很渺小了,沧海之一粟罢了.
所以当数据量足够大的时候,常数项和那些影响不大的忽略不计.

时间复杂度的练习:

1.1 常见的时间复杂度:

例1:

// 计算Test2的时间复杂度?
void Test2(int N)
{int count = 0;for (int i = 0; i < 2 * N ; i++){++count;}int M = 10;while (M--){++count;}printf("%d\n", count);}

例2:

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

例3:

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

答案:
这三个例子的时间复杂度还是很好计算的.
例1:

2N+10用大O表示法表示时间复杂度为O(N).

例2:

基本操作执行了M+N次,有两个未知数M和N,时间复杂度为 O(N+M)
如果m和n相等则可以表示为O(N),如果一方远大于另一方,则可以用大的一方表示,记住是远大于,即不在一个量级.

例3:

基本操作语句被执行了常数次.这用大O表示法表示时间复杂度为O(1).

那试着分析TargetNum函数的时间复杂度.
TargetNum函数是用于在一个数组中查找目标值的函数,找到了就返回目标值的地址,没找到就返回NULL.

int* TargetNum(int* arr,int n, int num)
{for (int i = 0; i < n; i++){if (arr[i] == num)//找到目标数字则返回数字的地址{return arr + i;}}return NULL;
}
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int sz = sizeof(arr) / sizeof(arr[0]);int num = 0;scanf("%d", &num);int*ret =TargetNum(arr, sz, num);if (ret == NULL){printf("该目标值不存在");}printf("%d ", *(ret));if (ret + 1 <= &arr[sz - 1]){printf("%d ", *(ret + 1));}
}

此时就让人有些疑惑了,这个函数的时间复杂度似乎不是固定的.在1~n的范围之间的那如何确定它的时间复杂度呢?
在这里插入图片描述

分析一下:
最好情况时(第一个数就是目标值): O(1).
平均情况时:O(n/2).
最坏情况时:O(n).

那我们选择哪种情况比较合理呢?
那我们讲一个小故事吧.

假如你是一名高中生,你刚经历期末考试,晚上,老师只公布了部分答案.
你可以确保自己可以拿到60分,有剩余的40分中,你按照以往的每次考试的经验来看,不出意外20分是可以拿到的.
此时回到家中,老爸问你能考多少分?考多少分老爸就奖励你多少钱,嘿嘿.🍭🍭🍭
你会说80(平均情况)分吗?还是会选择100分(最好情况)呢?
万一食言了呢?
咱一般都会选择最坏的情况,那样即使出现了意外,我们也没有说错,而不出意外时,无论是平均还是最好情况,我们都会比较高兴的.

这里牛牛也想告诉大家,结局未定之前,不要过分高看自己,降低期望,当然也不要自卑,继续努力,继续前行,保持对生活的热爱,生活也会拥抱你的!🍭🍭🍭

回到正题,此时我们会选择最坏的情况作为时间复杂度,即TargetNum函数的时间复杂度是O(n).

1.2 冒泡排序的时间复杂度

大家还记得c语言时学的冒泡排序吗?

// 计算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(0)或者O(1).
首先呢,没有O(0)这一说法,这几乎不可能,其次这里最好的情况也不是O(1),为什么呢?
如果数组有序,那不就不需要排序吗?那不就是O(1)吗?

其实,即使数组有序,我们也需要循环遍历一遍这个数组,才能知道有序,计算机不是人哦,他不能看一眼就知道有序,而且就算是人,当数据量比较大的时候人一眼也看不出来是否有序吧!
总结:
最好情况:O(N)
最坏情况:O(N2)

1.3 "二分查找"的时间复杂度

int BinarySearch(int* a, int n, int x)
{assert(a);int begin = 0;int end = n-1;while (begin <= end){int mid = (begin+end)/2;//找到中间值if (a[mid] < x)//如果该值比中间值大,则直接从中间值的后半部分里面找{begin = mid+1;}else if (a[mid] > x)//如果该值比中间值小,则直接从中间值的前半部分里面找{end = mid-1;}else//找到了return mid;}//没找到返回-1,这里设置为-1也许有些不合理,可以使用逻辑值.return -1;
}

判断一次(与中间值比较),就可以去掉一半的值.即该算法一次N的值就会等于N/2.
不难得出该算法的时间复杂度是O(logn2).

补充知识:logn2经常省略写成log2甚至lg2

"二分查找"看起来平平无奇,但其实是个隐藏的大佬啊!
大家知道这些量级的差距有多大吗?log2是很可怕的量级,速度极快.
看图感受一下吧!

友友们感受到二分查找的厉害了吧!

遗憾的是,二分查找的前提是数据得是有序的,否则他无法实现一次排除一半.而数据往往是无序的,并且有些特殊的数据还不允许排序,排序会破坏数据的.
这也就让二分查找无计可施了,纸老虎罢了.😂😂😂

1.4 递归的时间复杂度:

// 计算阶乘递归Fac的时间复杂度?
int Fac(int N)
{if(0 == N)//递归的结束条件{return 1;}return Fac(N-1)*N;
}

递归的时间复杂度计算主要是根据其递归的层数来决定.
该算法每次递归N就-1,则递归的次数为N.
故算法的时间复杂度为:O(N).

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

此算法,每次经过递归都需要再递归2 * N次.
在这里插入图片描述
则此算法的时间复杂度为O(2n).

常见量级的比较图

大O的渐进表示法:
在这里插入图片描述

二、空间复杂度

空间复杂度并不是重点,现如今,一般情况下我们的时间的价值比空间的价值要高的多.
定义:

空间复杂度也是一个数学表达式,是对一个算法在运行过程中临时占用存储空间大小的量度 。
空间复杂度不是程序占用了多少bytes的空间,因为这个也没太大意义,所以空间复杂度算的是变量的个数。
空间复杂度计算规则基本跟实践复杂度类似,也使用大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 = 0;以及Swap(&a[i-1], &a[i]);函数中的int tmp.
这项常数个临时变量,故空间复杂度为O(1).

例2:

int Fac(int N)
{if(0 == N)//递归的结束条件{return 1;}return Fac(N-1)*N;
}

同样递归的空间复杂度由开辟的栈帧个数(每次递归开辟一次栈帧)决定,开辟了N个栈帧,每个栈帧使用了常数个空间。空间复杂度为O(N).

好了,数据结构的初步认识就到这里啦!后续牛牛会继续更新数据结构的相关知识.
如果文章对大家有用的话记得一键三连哦!💗💗💗
如果文章中有部分错误之处,可以私信牛牛,互相讨论哦!!!

在这里插入图片描述

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

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

相关文章

Allegro PCB后处理

Allegro PCB后处理&#xff0c;主要是完成线路设计以后&#xff0c;输出生产文件之前的处理。这是看教程做的记录&#xff0c;方便以后自己参考。 教程&#xff1a; [小哥Cadence Allegro 132讲字幕版PCB视频教程]_哔哩哔哩_bilibili 感觉关键是多看右边Options菜单&#xff0…

Simulation Extractable Versions of Groth’s zk-SNARK Revisited学习笔记

1. 引言 等人2020年论文《Simulation Extractable Versions of Groth’s zk-SNARK Revisited》&#xff0c;开源代码实现见&#xff1a; https://github.com/Baghery/ABPR22&#xff08;Rust&#xff0c;基于arkworks开发。使用了Multi-Scalar Multiplication (MSM)技术来优化…

linux下使用ftp下载服务器数据

首先确认服务器地址 比如我要从uniprot获取数据&#xff0c;需要先ping服务器地址&#xff1a; 可见&#xff0c;ftp地址不需要前面的https 匿名登录 匿名&#xff1a;anonymous 密码&#xff1a;任意邮箱&#xff0c;如123163.com 这里的传输模式我使用的是二进制&#xff…

Revit进入Unity教程

一、背景 小伙伴们是否有Revit进入Unity交互的需求呢&#xff1f; 二、实现功能 1.Revit进入Unity,包含模型属性&#xff0c;材质&#xff0c;轻量化等 2.实现BIM构件点选&#xff0c;高亮&#xff0c;属性展示 3.实现BIM模型分层显示&#xff0c;爆炸等效果 学习教程&…

xilinx zynq+vitis实现命令行编译输出xsa以及bin文件

执行菜单命令【开始】—【所有程序】—【Xilinx Design Tools】—【Vivado2020.1】—【Vivado2020.1Tcl Shell】,弹出命令界面 或者cmd命令下输入call D:\soft_install\vivado2020.1\Vivado\2020.1\bin\vivado.bat -mode tcl 2.输入打开工程指令&#xff1a; open_project …

SpringBoot整合Redis,一篇带你入门使用Redis

本文介绍如何将Redis整合到SpringBoot项目中&#xff0c;以及如何配置、封装和使用 文章目录 前言环境搭建项目结构添加依赖 Module封装RedisConfig配置封装常见操作为ServiceRedisServiceRedisLockUtil 测试 前言 参考链接&#xff1a; 英文官网链接中文官网链接Redis githu…

【Matlab】基于紧格式动态线性化的无模型自适应控制

例题来源&#xff1a;侯忠生教授的《无模型自适应控制&#xff1a;理论与应用》&#xff08;2013年科学出版社&#xff09;。 对应书本 4.2 单输入单输出系统(SISO)紧格式动态线性化(CFDL)的无模型自适应控制(MFAC) 例题4.1 题目要求 matlab代码 clc; clear all;%% 期望轨迹…

mybatis-plus的代码生成器的应用

目录 1.工程引入mybatis-plus3-generator代码生成器2.只需要关注mybatis-plus-config.properties然后生成代码3.分别添加依赖解决报错4.加入其它配置然后测试效果 3.4版本 1.工程引入mybatis-plus3-generator代码生成器 mybatis-plus3-generator放入项目工程中&#xff0c;父工…

Java8函数式编程(Lambda表达式,Stream流,Optional)

一.函数式编程思想 面向对象思想主要是关注对象能完成什么事情&#xff0c;函数式编程思想就像函数式&#xff0c;主要是针对数据操作&#xff1b;代码简洁容易理解&#xff0c;方便于并发编程&#xff0c;不需要过分关注线程安全问题 二.lambda表达式 1.概念 lambda表达式…

COMSOL锂离子电池仿真技术与应用

背景&#xff1a; 随着各国燃油车禁售时间表的推出&#xff0c;新能源汽车的地位愈发稳固。而锂离子电池作为电动车的核心动力源&#xff0c;也越来越受到市场的追捧。锂离子电池在制作过程中涉及正极、电解液、负极、隔膜等材料的选取与匹配&#xff0c;极片设计参数的选择等…

如何开发一款用户体验优秀的语音交友app?

在数字时代&#xff0c;人们越来越依赖智能手机上的应用程序来与他人进行交流。其中&#xff0c;语音交友app成为了最受欢迎的应用之一。然而&#xff0c;开发一款成功的语音交友app需要深入了解用户需求与体验。本文将探讨如何开发一款用户体验优秀的语音交友app。 着眼于用户…

[oeasy]python0135_变量名与下划线_dunder_声明与赋值

变量定义 回忆上次内容 变量 就是 能变的量上次研究了 变量标识符的 规则 第一个字符 应该是 字母或下划线合法的标识符可以包括 大小写字母数字下划线 还研究了字符串(str)的函数 isidentifier查询字符串 是否为合法标识符 最后发现 这个isidentifier函数有时候不好使&…

记录bingAI解答pyjwt参数和头部的问题

python jwt.encode()函数的参数是哪些 正在搜索: python jwt.encode()函数的参数 正在为你生成答案… 已收到消息. 在Python中&#xff0c;jwt.encode()函数的参数有三个&#xff1a;第一个是payload&#xff0c;主要用来存放有效的信息&#xff0c;例如用户名&#xff0c;过期…

PCL点云库(1) — 简介与数据类型

目录 1.1 简介 1.2 PCL安装 1.2.1 安装方法 1.2.2 测试程序 1.3 PCL数据类型 1.4 PCL中自定义point类型 1.4.1 增加自定义point的步骤 1.4.2 完整代码 1.1 简介 来源&#xff1a;PCL&#xff08;点云库&#xff09;_百度百科 PCL&#xff08;Point Cloud Library&…

ZLMediaKit流媒体服务器 RTSP推流时候的堆栈

先直接看图 这是ffmpeg向流媒体服务器推流时候的堆栈 引入C 11之后 堆栈会显得特别繁复冗余 看起来 也没有 以前没有C11之前那样 简单明了 太复杂了 标记下 很多函数名字被我改了 因为原来的看起来 同名函数太多了 C11 和lambada 匿名函数 让看堆栈 成了地狱模式 断点断在…

Revit中如何绘制轴线?CAD图纸转轴网操作

一、如何用revit来制作这么一个简单的轴线呢? 01 、新建项目 绘制轴线&#xff0c;首先新建项目建筑样板 02 、轴线快捷键 绘制轴线的快捷键需要牢记&#xff0c;因为经常使用GR 03 、编辑轴线类型 当你画好第一条轴线&#xff0c;需要对轴线类型属性进行调节&#xff0c;一般…

基于tensorflow2.x的多GPU并行训练

由于最近训练transformer&#xff0c;在单卡上显存不够&#xff0c;另外一块卡上也无法加载&#xff0c;故尝试使用双卡并行的策略。将基本的流程、遇见的难题汇总在这里。分布策略解释 使用官方给出的tf.distribute.MirroredStrategy作为分布策略。这个策略通过如下的方式运行…

【架构设计】什么是CAP理论?

1、理论 CAP理论是指计算机分布式系统的三个核心特性&#xff1a;一致性&#xff08;Consistency&#xff09;、可用性&#xff08;Availability&#xff09;和分区容错性&#xff08;Partition Tolerance&#xff09;。 在CAP理论中&#xff0c;一致性指的是多个节点上的数据…

宝安日报:联诚发跨界创新“追光”十九载!

世界一流声光电智造一体化服务商、国家级高新技术企业、国家级专精特新“小巨人”企业、博士后创新实践基地、深圳自主创新百强企业……这些熠熠生辉的关键词&#xff0c;是位于宝安区航城街道的深圳市联诚发科技股份有限公司&#xff08;以下简称&#xff1a;联诚发&#xff0…

KingSCADA3.8保姆级安装教程

大家好&#xff0c;我是雷工&#xff01; 最近开始学习KingSCADA&#xff0c;今天这篇详细记录安装KingSCADA3.8的过程。 首先下载需要的安装版本&#xff0c;此处以从官网下载的最新版本KingSCADA3.8为例&#xff0c;双击&#xff1a;Setup.exe ; 一、安装主程序 1、点击“…