初识数据结构——“数据结构与算法”

news2025/1/17 0:25:07

各位CSDN的uu们你们好呀,今天小雅兰进入一个全新的内容的学习,就是算法和数据结构啦,话不多说,让我们进入数据结构的世界吧


什么是数据结构?

什么是算法?

数据结构和算法的重要性

如何学好数据结构和算法

算法的时间复杂度和空间复杂度

算法效率

时间复杂度

空间复杂度

常见复杂度对比

复杂度的oj练习


什么是数据结构?

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

实现一些项目,需要在内存中将数据存储起来,比如实现一个通讯录,把每个人的信息存储起来,可以使用数组的方式,也可以使用链表,当然,也可以使用树 


什么是算法?

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

 排序、查找、去重


数据结构和算法的重要性  

  • 怎么计算一个类到底实例化了多少对象?
  • 如果还有一个派生类继承了这个类,那么如何计算这两个类,各自实例化了多少对象?
  • 你了解联合体和结构体吗?
  • 如何测试一个机器是大端还是小端?
  • 你了解队列和栈吗?
  • 怎么用两个栈实现一个队列。
  • 你使用过模版吗?
  • 写一个比较两个数大小的模板函数。
  • 你使用过容器吗?
  • 判断两个链表是否相交。
  • Vector和数组的区别。
  • 你在学校里做的最满意的一个项目是什么?简述一下这个项目。
  • 自我介绍
  • 学习STL具体是怎么开展的?
  • 如果一款产品给你怎么检测内存泄露?
  • 进程间通信方式,共享内存是怎么实现的,会出现什么问题,怎么解决?
  • TCP为什么是可靠的?可靠是怎么保证的?为什么要三次握手?为什么三次握手就可以可靠?
  • Http数据分包问题;
  • Vector相关;
  • Hashmap相关;
  • 红黑树的原理、时间复杂度等;
  • Memcpy和memmove的区别;
  • 客户端给服务器发送数据,意图发送aaa,然后再发bbb,但是可能会出现aaabbb这种情 况,如何处理?
  • 游戏的邮件服务器中每天会有玩家频繁的创建邮件和删除邮件,海量数据、大小不一,会有 哪些场景,怎么存储,邮件是怎么到内存的?
  • 写一道算法题
  • 手写五道题,三道编程题,一道数据库,一道linux
  • 数据库的题两问
  • 算法了解的如何,插入排序编程
  • 说一下IP,TCP,ARP
  • 内核是什么
  • IP层主要功能
  • map和set底层
  • bootstrap的用法,html,html的全称
  • 你觉得框架和库有啥区别
  • 代码优化
  • 哈希表
  • shell脚本
  • 快速排序思想
  • 递归是什么
  • 分治是什么,与递归区别是什么
  • web平台是怎么做的
  • linux命令
  • 了解些什么前沿的技术,英语怎么样,了解过什么英语的文献

可见,数据结构与算法确实是非常重要的 


如何学好数据结构和算法

死磕代码,磕成这样就可以了,哈哈哈

 注意画图和思考


算法效率

算法的复杂度

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

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


时间复杂度

时间复杂度的概念

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

此函数表示数学里面带有未知数的函数表达式,和C语言的函数不一样 

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

 

下面,我们来看一个具体的例子:

// 请计算一下Func1中++count语句总共执行了多少次?
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);

}

 Func1 执行的基本操作次数:

  • N = 10 F(N) = 130
  • N = 100 F(N) = 10210
  • N = 1000 F(N) = 1002010  

N越大,后两项对结果的影响是越小的 

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

 大O的渐进表示法

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

推导大O阶方法:

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

下面,还是来先看看题目吧!!!

// 计算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阶方法知道,时间复杂度为 O(N)  

// 计算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,时间复杂度为 O(N+M)

一般情况下时间复杂度计算时都是用的N,但是其他的,比如M、K也是可以的 

如果题目有条件:

  • M远大于N,那么可以认为是O(M)
  • N远大于M,那么可以认为是O(N)
  • M和N差不多大,那么可以认为是O(M),也可以认为是O(N) 
// 计算Func4的时间复杂度?
void Func4(int N)
{
	int count = 0;
	for (int k = 0; k < 100; ++k)
	{
		++count;
	}
	printf("%d\n", count);
}

 基本操作执行了100次,通过推导大O阶方法,时间复杂度为 O(1)

 O(1),不是代表算法运行一次,是常数次

// 计算strchr的时间复杂度?
const char* strchr(const char* str, int character);

 

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

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

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

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

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

 

所以:

基本操作执行最好1次,最坏N次,时间复杂度一般看最坏,时间复杂度为 O(N)  

// 计算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次,最坏执行了(N*(N+1)/2)次,通过推导大O阶方法+时间复杂度一般看最坏,时间复杂度为 O(N^2)

 算时间复杂度不能只去看是几层循环,而是要看它的思想

// 计算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次,最坏O(logN)次,时间复杂度为 O(logN)

 

 

logN在算法分析中表示是底数为2,对数为N。有些地方会写成lgN。 

 

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

	return Fac(N - 1) * N;
}

 递归算法:递归次数*每次递归调用的次数

递归次数为O(1),每次递归调用的次数为O(N) 

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

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

	return Fib(N - 1) + Fib(N - 2);
}

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

 

右边一些递归分支会提前结束,那么,就会缺一些递归调用,但是对总体来说影响不大

 

 每次递归调用的次数是O(1)

斐波拉契数列的递归写法完全就是一个实际上没用的算法,因为太慢了 


空间复杂度

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

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

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

下面,还是来看看题目:

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

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

时间复杂度:O(N) 

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

	return Fac(N - 1) * N;
}

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

  • 空间是可以重复利用,不累计的
  • 时间是一去不复返,累计的 

常见复杂度对比

 


 复杂度的oj练习

力扣

 

int missingNumber(int* nums, int numsSize)
{
    int x = 0;
    //跟[0,n]异或
    for (int i = 0; i <= numsSize; i++)
    {
        x ^= i;
    }
    //再跟数组中值异或
    for (int i = 0; i < numsSize; i++)
    {
        x ^= nums[i];
    }
    return x;
}

 好啦,小雅兰今天的内容就到这里啦,数据结构与算法确实是一个难啃的东西,小雅兰加油呀!!!

 

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

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

相关文章

【开发者思维】优秀开发者应该具备的25个思维习惯

目录 1. 认真思考开发软件的目的 2. 明确软件设计的目标 3. 正确理解工作 4. 保持简洁 5. 控制复杂度 6. 软件维护 7. 保持一致 8. 优先级评测 9. 解决问题 10. 追求优秀即可 11. 预测

【MySQL中有哪些存储引擎?请你说说MySQL中innodb和myisam的区别?InnoDB引擎的三大特性?】

一.MySQL中有哪些存储引擎&#xff1f; InnoDB存储引擎 InnoDB是MySQL的默认事务型引擎&#xff0c;也是最重要、使用最广泛的存储引擎。它被设计用来处理大量的短期(short-lived)事务&#xff0c;应该优先考虑InnoDB引擎。MylSAM存储引擎 在MySQL 5.1及之前的版本&#xff0c…

PingCode 第三届开发者大会成功举办

PingCode 开发者大会或许会迟到&#xff0c;但永远不会缺席。原定于2022年10月24日举办的 “PingCode 开发者大会” 因疫情原因推迟&#xff0c;属于2022年 PingCode 开发者们的新知创想&#xff0c;不得不藏器待时。2023新春伊始&#xff0c;万象更新&#xff0c;伴随着万物逐…

不写代码、年薪百万,带你玩赚ChatGPT提示工程-高级提示

文章目录前言一、Zero-Shot提示二、Few-Shot 提示Few-shot Prompting 的局限性三、Chain-of-Thought Prompting四、Zero-Shot CoT五、Self-Consistency六、Generated Knowledge 提示七、Automatic Prompt Engineer (APE)总结前言 随着ChatGPT的大火&#xff0c;提示工程在大模…

按键修改阈值功能、报警功能、空气质量功能实现

按键修改阈值功能 要使用按键&#xff0c;首先要定义按键。通过查阅资料&#xff0c;可知按键的引脚如图所示&#xff1a;按键1&#xff08;S1&#xff09;通过KEY0与PA0连接&#xff0c;按键2&#xff08;S2&#xff09;通过KEY1与PE2连接&#xff0c;按键3&#xff08;S3&…

成本降低90%,OpenAI正式开放ChαtGΡΤ

今天凌晨&#xff0c;OpenAI官方发布ChαtGΡΤ和Whisper的接囗&#xff0c;开发人员现在可以通过API使用最新的文本生成和语音转文本功能。OpenAI称&#xff1a;通过一系列系统级优化&#xff0c;自去年12月以来&#xff0c;ChαtGΡΤ的成本降低了90%&#xff1b;现在OpenAI用…

供应链依赖:您的GitHub连接可能会触发什么?

不祥之兆&#xff0c;在针对 GitHub 存储库的攻击激增之后&#xff0c;很难避免。 最近的CircleCI漏洞&#xff08;客户的机密和加密密钥被盗&#xff09;清楚地表明&#xff0c;攻击者已经了解并利用了这个向量。 现在比以往任何时候都更需要公司保护这些非人类连接&#xf…

记录2023.3.3下午的校招

文章目录一、校招的总览意义&#x1f60e;二、校招时&#xff0c;公司是怎么做的&#xff1f;如何提问的&#xff1f;我又是怎么回答的&#x1f914;2.1 公司最喜欢提问你的问题&#x1f64c;三、校招期间&#xff0c;我应该如何去了解一家企业&#xff1f;&#x1f600;三、建…

LeetCode 982. 按位与为零的三元组 -- 哈希统计

按位与为零的三元组 困难 101 相关企业 给你一个整数数组 nums &#xff0c;返回其中 按位与三元组 的数目。 按位与三元组 是由下标 (i, j, k) 组成的三元组&#xff0c;并满足下述全部条件&#xff1a; 0 < i < nums.length 0 < j < nums.length 0 < k <…

【C++笔记】异常处理

C语言处理错误的方式 传统的错误处理机制&#xff1a; 1.终止程序缺陷&#xff1a;用户难以接受。 2.返回错误码&#xff1a;缺陷&#xff1a;需要自己去查错误码对应的解释。 C语言一般使用错误码来处理错误&#xff0c;部分情况下才会用终止情况处理处理严重的错误。 C异常…

初识Liunx下的进程状态和环境变量以及进程优先级

文章目录前言1.进程状态1.阻塞与挂起2.Linux下的进程状态1.概念知识2.R状态2.休眠状态(S/D&#xff09;3.T状态4.Z状态(僵尸进程)和X状态5.孤儿进程3.环境变量1.概念2.获取环境变量1.环境变量表2.函数获取环境变量3.关于环境变量的理解和main函数中的两个参数1.环境变量的理解2…

学习笔记--目标检测基础知识大全

来源&#xff1a;投稿 作者&#xff1a;LSC 编辑&#xff1a;学姐 目录 1.特点 2.数据集 2.1 VOCS数据集 2.2 COCO数据集 3.评价指标 3.1 GroundTruth 3.2 IOU(交并比&#xff0c;Intersection over Union) 3.3 基本指标 3.4 AP与mAp 3.5 案例演示 4. 脑图&#xff…

代码规范----编程规约(下)

目录 四、OOP规约 五、日期时间 六、集合处理 四、OOP规约 &#xff08;1&#xff09;、避免通过一个类的对象引用访问此类的静态变量或静态方法&#xff0c;无谓增加编译器解析成本&#xff0c;直接用类名来访问即可 &#xff08;2&#xff09;、所有的覆写方法&#xff0…

【C语言学习笔记】:二级指针

指针可以指向一个普通类型的数据&#xff0c;例如 int、double、char 等&#xff0c;也可以指向一个指针类型的数据&#xff0c;例如 int *、double *、char * 等。 如果一个指针指向的是另外一个指针&#xff0c;我们就称它为二级指针&#xff0c;或者指向指针的指针。 假设…

Leetcode.2017 网格游戏

题目链接 Leetcode.2017 网格游戏 Rating &#xff1a; 1719 题目描述 给你一个下标从 0 开始的二维数组 grid&#xff0c;数组大小为 2 x n&#xff0c;其中 grid[r][c]表示矩阵中 (r, c)位置上的点数。现在有两个机器人正在矩阵上参与一场游戏。 两个机器人初始位置都是 (0…

带你看懂RuoYi动态数据源切换

文章目录数据源是什么一、spring中是如何处理各种数据源的&#xff1f;1.开搞springboot2.创建一个测试类二、有了如上的理论,那么想想动态切换数据源吧参考若依的动态数据源配置总结数据源是什么 数据源,对于java来说,就是可用的数据库,那么我平时开发的springboot springclo…

算机网络安全基础知识5:sql注入漏洞攻击,DVWA演示sql注入漏洞,如何利用sql注入查看数据库信息,sqlmap,sql注入漏洞的防御

算机网络安全基础知识5:sql注入漏洞攻击&#xff0c;DVWA演示sql注入漏洞&#xff0c;如何利用sql注入查看数据库信息&#xff0c;sqlmap&#xff0c;sql注入漏洞的防御 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能…

Unity/C#------委托与事件(一篇文章彻底搞懂...)

一&#xff1a;委托 所有的代码语言创造者母语都是英语&#xff0c;我们从英语翻译到中文的过程中难免会存在一些不太能还原本意的词&#xff0c;比如我之前一直不理解构造函数和析构函数&#xff0c;只知道这俩货作用相反&#xff0c;直到我看到了它的英文意思&#xff0c;Con…

spring重点整理篇--springMVC(嘿嘿,开心哟)

Spring MVC是的基于JavaWeb的MVC框架&#xff0c;是Spring框架中的一个组成部分(WEB模块) MVC设计模式&#xff1a; Controller&#xff08;控制器&#xff09; Model&#xff08;模型&#xff09; View&#xff08;视图&#xff09; 重点来了&#x1f604; SpringMVC的工作机制…

Nginx+Tomcat实现负载均衡、动静分离(脚本方法)

一、Nginx 负载均衡实现原理1、Nginx 实现负载均衡是通过反向代理实现反向代理&#xff08;Reverse Proxy&#xff09; 是指以 代理服务器&#xff08;例&#xff1a;Nginx&#xff09; 来接受 internet 上的连接请求&#xff0c;然后将请求转发给内部网络上的服务器&#xff0…