对数据结构的初步认识

在这里插入图片描述

前言:

牛牛开始更新数据结构的知识了.本专栏后续会分享用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;
	//1
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			++count;
		}
	}
	//2
	for (int k = 0; k < N; k*=2)
	{
		++count;
	}
	//3
	for (int k = 0; k < 2 * N; k++)
	{
		++count;
	}
	//4
	int 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).

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

在这里插入图片描述

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

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

相关文章

使用 vscode 安装配置 clang-format(代码格式化)

目前&#xff0c;网上能找到的配置教程都是乱教的。他们以C为语言讲配置&#xff0c;其实clang-format默认就是C.所以他们在配置时&#xff0c;即是错了。也会以默认C格式化&#xff0c;也不会提示配置错误。结果他们还不知道他们错在哪&#xff1f;如果让他们配置.CS, .json&a…

23种设计模式之观察者模式(黑马程序员)

观察者模式 一、概述二、结构三、实现四、总结在最后 一、概述 观察者模式又被称为发布-订阅模式(Publish/Subscribe)模式&#xff0c;它定义了一种一对多的依赖关系&#xff0c;让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时&#xff0c;会通知所有…

中级软件设计师备考---操作系统和计算机网络

【因为我自己是软件工程专业毕业的学生&#xff0c;所以408里的这两门课都比较熟悉&#xff0c;因此这一部分只放一些我印象不是完全深刻的知识。】 目录 操作系统前驱图与PV操作死锁的预防与避免绝对路径和相对路径缺页中断的某种练习题 计算机网络网络规划与设计特殊含义的I…

【FFTW库】编译生成 x86、arm 环境下的FFTW库

FFTW是一个快速计算离散傅里叶变换的标准C语言程序集&#xff0c;可计算一维或多维实和复数据以及任意规模的DFT。下面主要介绍的是 x86 环境下 FFTW库的编译过程&#xff0c;arm环境下的编译过程和FFTW类似&#xff0c;不同之处在于需要手动指定 编译环境 和 编译器。 FFTW有…

2023年五月份图形化一级打卡试题

活动时间 从2023年5月1日至5月21日&#xff0c;每天一道编程题。 本次打卡的规则如下&#xff1a; 小朋友每天利用10~15分钟做一道编程题&#xff0c;遇到问题就来群内讨论&#xff0c;我来给大家答疑。 小朋友做完题目后&#xff0c;截图到朋友圈打卡并把打卡的截图发到活动群…

OkHttp3源码解析 - 连接机制和缓存机制

系列文章目录 第一章 OkHttp3源码解析 - 请求流程 第二章 OkHttp3源码解析 - 拦截器 第三章 OkHttp3源码解析 - 连接机制和缓存机制 文章目录 系列文章目录前言一、连接机制1.1 创建连接1.2 连接池 二、缓存机制2.1 缓存策略2.2 缓存管理 彩蛋致谢 前言 本文基于okhttp3.12.1…

三大本土化战略支点,大陆集团扩大中国市场生态合作「朋友圈」

“在中国&#xff0c;大陆集团已经走过30余年的发展与耕耘历程&#xff0c;并在过去10年间投资了超过30亿欧元。中国市场也成为了我们重要的‘增长引擎’与‘定海神针’。未来&#xff0c;我们将继续深耕中国这个技术导向的市场。”4月19日上海车展上&#xff0c;大陆集团首席执…

ospf综合实验

目录标题 第一步&#xff1a;网段划分第二步&#xff1a;配置区域0路由器接口和环回第三步&#xff1a;配置区域0缺省第四步&#xff1a;配置MGRE环境第五步&#xff1a;配置区域0用户网段第六步&#xff1a;配置区域1路由器及环回第七步&#xff1a;配置区域2的路由器及环回第…

低代码开发重要工具:jvs-logic(逻辑引擎)基础原理与功能架构

逻辑引擎介绍 逻辑引擎是一种能够处理逻辑表达式的程序&#xff0c;它能够根据用户输入的表达式计算出表达式的值。在实际应用中&#xff0c;逻辑引擎通常被用于处理规则引擎、决策系统、业务规则配置等领域&#xff0c;具有广泛的应用前景。 原理与核心功能描述 基础原理 …

走进社区客户端测试 | 得物技术

0.引言 社区 C 端质量体系建设思考&#xff1f; 询问一下 ChatGPT 1、关于社区客户端 1.1 社区端上功能 得物首页 搜索、发布、关注流、推荐流、沉浸式单列流、活动 tab、其他二级频道 tab 动态详情页 图文、视频、专栏、点评 私域 个人/他人主页、通讯录好友、微博好友…

如何实现电脑通过手机上网?1分钟搞定!

案例&#xff1a;电脑没网时&#xff0c;如何通过手机上网&#xff1f; 【想用电脑看电影&#xff0c;但是附近没有Wi-Fi。朋友说可以说电脑可以通过手机上网&#xff0c;但我们都不知道具体如何操作&#xff0c;有没有小伙伴可以教教我们。】 在没有Wi-Fi或有线网络接入时&a…

服务(第十二篇)LVS-DR模式

数据包流向分析&#xff1a; &#xff08;1&#xff09;客户端发送请求到 Director Server&#xff08;负载均衡器&#xff09;&#xff0c;请求的数据报文&#xff08;源 IP 是 CIP,目标 IP 是 VIP&#xff09;到达内核空间。 &#xff08;2&#xff09;Director Server 和 Re…

无良公司把我从上家挖过来,白嫖了六个月,临近试用期结束才说不合适,催我赶紧找下家!...

职场套路多&#xff0c;一不小心就会掉坑&#xff0c;一位网友讲述了自己的遭遇&#xff1a; 今天被领导催促离职了&#xff0c;当时就是这个领导把他从别的公司挖过来。这家公司催得太急&#xff0c;为了投奔这里&#xff0c;他和上家的HR都闹翻了&#xff0c;上家总监挽留他&…

时隔两个多月,一起来看ChatGPT现况如何?

ChatGPT这股风吹了两个多月&#xff0c;时至今日&#xff0c;各平台上与ChatGPT相关的文章&#xff0c;到现在依旧拥有着不小的流量。三月中旬上线了ChatGPT-4&#xff0c;与我们的文心一言前后脚发布&#xff0c;而后阿里的“通义千问”也展现了不俗的实力&#xff0c;那到现在…

图形界面GUI相关概念GLX/Wayland/X11/DRM/DRI

1. GUI图形界面是什么 GUI是graphical user interface的缩写&#xff0c;图形用户接口&#xff0c;实现了基本的WIMP&#xff08;windows&#xff0c;icons&#xff0c;menus&#xff0c;pointer&#xff09;。一个GUI的基本组成&#xff1a;display server实现windowing syst…

03_线程间通信

面试题&#xff1a;两个线程打印 两个线程&#xff0c;一个线程打印1-52&#xff0c;另一个打印字母A-Z打印顺序为12A34B...5152Z&#xff0c;要求用线程间通信 public class Demo01 {public static void main(String[] args) {ShareData05 shareData05 new ShareData05();new…

分布式事务处理方案及分布式锁相关

​ 本文偏理论 一、事务处理 1、事务处理的四个特性ACID Atomicity 原子性: 对于数据库的修改&#xff0c;全部执行or全部不执行 Consistency 一致性: Isolation 隔离性 : 亦称为串行化&#xff0c;防止事务间操作混淆&#xff0c;需要串行化或者序列化请求&#xff0c;使…

隐私权限是什么

导读&#xff1a; 隐私权在现代社会对于人们而言是重要的人格权&#xff0c;而随着互联网技术的发展&#xff0c;实践中侵犯隐私权的行为很常见。那么隐私权限是什么&#xff1f;侵犯隐私权的行为有哪些&#xff1f;侵犯他人隐私权要负什么法律责任&#xff1f;接下来将由找法…

使用docker搭建RocketMQ(非集群搭建官方镜像)

之前在使用 RocketMQ 官方的包在搭建的时候&#xff0c;发现好多问题&#xff0c;什么修改内存大小&#xff0c;然后启动 broker 报错&#xff0c;类似 service not available now, maybe disk full 等等… 最后决定还是重新用 docker 搭建下&#xff0c;感觉这样子玩坏了&…

微信仿真平台的设计和实现(设计+源码)_kaic

摘要 现如今&#xff0c;科技的发展带动着环保方式的更新&#xff0c;Internet是一个不断的开展和不停的扩充数据潮流&#xff0c;有了它&#xff0c;我们可以快速、容易地在世界的任何角落进行沟通&#xff0c;获取更多的信息与资料。Internet可以提供大量信息资源和文案数据库…