数据结构时间复杂度空间复杂度

打印 上一主题 下一主题

主题 838|帖子 838|积分 2514

数据结构媒介

1.什么是数据结构

数据结构(Data Structure)是计算机存储,构造数据的方式,指相互之间存在一种或多种特性关系的数据元素的聚集
2.什么是算法

算法(Algorithm)就是界说良好的计算过程,它取一个或一组的值为输入,并产生出一个或一组的值作为输出,简朴来说算法就是一系列的计算步骤,用来将输入数据转化成输出结果3.数据结构和算法的重要性
3.数据结构和算法的重要性

在校园雇用的笔试中:


  • 目前校园雇用笔试一般采用Online Judge情势, 一般都是20-30道选择题+2道编程题,大概3-4道
    编程题。
    2020奇安秋招C/C++
    美团2021校招
    网易2021校招C++



    可以看出,现在公司对学生代码能力的要求是越来越高了,大厂笔试中险些满是算法题而且难度大,中小长的笔试中才会有算法题。算法不仅笔试中观察,面试中面试官基本都会让现场写代码。而算法能力短期内无法快速进步了,至少需要连续半年以上算法训练积累,否则真正校招时笔试会很艰巨,因此算法要早早准备。
在校园雇用的面试中:


  • CVTE面试1:
    1.怎么计算一个类到底实例化了多少对象?
    2.假如另有一个派生类继承了这个类,那么怎样计算这两个类,各自实例化了多少对象?
    3.相识团结体和结构体吗?
    4.怎样测试一个呆板是大端还是小端?
    5.相识队列和栈吗?
    6.怎么用两个栈实现一个队列。
    7.使用过模版吗?
    8.写一个比较两个数巨细的模板函数。
    9.使用过容器吗?
    10.判断两个链表是否相交。
    11.Vector和数组的区别。
    12.在学校里做的最满意的一个项目是什么?简述一下这个项目。
    腾讯的面试1:
    1、自我先容
    2、学习STL详细是怎么开展的?
    3、假如一款产品给你怎么检测内存泄漏?
    4、进程间通信方式,共享内存是怎么实现的,会出现什么问题,怎么解决?
    5、TCP为什么是可靠的?可靠是怎么包管的?为什么要三次握手?为什么三次握手就可以可靠?
    6、Http数据分包问题;
    7、Vector相关;
    8、Hashmap相关;
    9、红黑树的原理、时间复杂度等;
    10、Memcpy和memmove的区别;
    11、客户端给服务器发送数据,意图发送aaa,然后再发bbb,但是大概会出现aaabbb这种情
    况,怎样处理?
    12、游戏的邮件服务器中每天会有玩家频仍的创建邮件和删除邮件,海量数据、巨细不一,会有
    哪些场景,怎么存储,邮件是怎么到内存的?
    13、写一道算法题
    百度的面试1:
    1.**手写五道题,三道编程题,**一道数据库,一道linux
    2.数据库的题两问
    3.算法相识的怎样,插入排序编程
    4.说一下IP,TCP,ARP
    5.内核是什么
    6.IP层主要功能
    7.map和set底层
    8.bootstrap的用法,html,html的全称
    9.以为框架和库有啥区别
    10.代码优化
    11.哈希表
    12.shell脚本
    13.快速排序思想
    14.递归是什么
    15.分治是什么,与递归区别是什么
    16.web平台是怎么做的
    17.linux命令
    18.相识些什么前沿的技术,英语怎么样,相识过什么英语的文献
在未来工作中:
[数据结构与算法对一个步伐员来说的重要性?
优化步伐性能
1.进步运行服从:


  • 数据结构与算法能够资助步伐员设计出高效的步伐。例如,在搜刮数据时,使用二分查找算法(基于有序数组的数据结构)比线性查找算法的时间复杂度更低。对于一个包含 n​ 个元素的数组,线性查找的时间复杂度为 O(n)​,而二分查找的时间复杂度为 O(logn)​。当 n​ 很大时,二分查找的服从会明显高于线性查找。再如,在处理图数据时,使用迪杰斯特拉算法(Dijkstra’s algorithm)可以高效地找到从一个极点到其他所有极点的最短路径。假如没有合适的算法,大概需要遍历所有大概的路径,这在大规模图数据中是非常耗时的。
2.优化资源利用


  • 公道的数据结构可以减少内存的占用。例如,使用哈希表(Hash Table)可以在常数时间内举行数据的插入、删除和查找操作,相比于使用数组或链表,哈希表在处理大规模数据时可以更有效地利用内存空间。另外,一些动态数据结构(如动态数组、链表等)可以根据实际数据量自动调解巨细,克制了静态数据结构大概导致的内存浪费或溢出问题。
解决复杂问题
1.提供问题解决思路


  • 很多复杂的编程问题可以通过选择合适的数据结构和算法来解决。例如,在处理任务调度问题时,可以使用优先级队列(Priority Queue)来按照任务的优先级举行排序,确保高优先级的任务先被执行。在解决字符串匹配问题时,KMP算法(Knuth-Morris-Pratt algorithm)可以高效地在文本中查找模式串的出现位置,克制了暴力匹配算法的低效性。
2.应对大规模数据处理


  • 在大数据期间,步伐员需要处理海量的数据。数据结构与算法可以资助步伐员设计出能够处理大规模数据的高效算法。例如,在处理海量数据的排序问题时,外部排序算法(External Sorting Algorithm)可以将数据分成多个小块,分别在内存中举行排序,然后再合并结果,从而克制了一次性将所有数据加载到内存中导致的内存不足问题。
提拔代码质量
1.加强代码可读性和可维护性


  • 使用合适的数据结构和算法可以使代码的逻辑更加清楚。例如,使用栈(Stack)来实现函数调用栈、表达式求值等功能,代码的逻辑会更加直观易懂。良好的数据结构和算法设计可以使代码的结构更加公道,易于维护和扩展。例如,在设计一个软件系统时,使用面向对象的设计模式(如工厂模式、单例模式等)联合合适的数据结构和算法,可以使代码的结构更加清楚,各个模块之间的耦合度更低,便于后续的维护和扩展。
2.遵循编程规范和最佳实践


  • 数据结构与算法是编程领域的基础知识,掌握它们可以资助步伐员遵循编程规范和最佳实践。例如,在编写代码时,应该选择合适的数据结构来存储和操作数据,克制使用过于复杂或低效的数据结构。同时,应该选择合适的算法来解决问题,克制使用暴力算法或低效的算法。
职业发展和竞争力提拔
1.面试和求职必备


  • 在步伐员的面试过程中,数据结构与算法是必考的内容之一。面试官通常会通过观察候选人对数据结构和算法的掌握水平来评估其编程能力和问题解决能力。例如,在面试中,大概会要求候选人实现一个特定的数据结构(如二叉树、哈希表等),大概解决一个算法问题(如排序、查找等)。
    掌握数据结构与算法可以增加步伐员在求职市场上的竞争力,使他们更轻易获得抱负的工作机会。
2.技术进阶的基础


  • 对于想要在编程领域深入发展的步伐员来说,数据结构与算法是必不可少的基础知识。例如,在学习计算机图形学、人工智能、呆板学习等高级领域时,需要掌握复杂的数据结构和算法。只有具备扎实的数据结构和算法基础,才气更好地理解和应用这些高级技术。
4.怎样学好数据结构和算法

1死磕代码
2画图和思考
5.数据结构和算法册本及资料保举

剑指offerOJ
LeetCode OJ
算法的时间复杂度和空间复杂度

1.算法服从

1.1怎样衡量一个算法的好坏

  1. long long Fib(int N)
  2. {
  3.         if(N < 3)
  4.                 return 1;
  5.         return Fib(N-1) + Fib(N-2);
  6. }
复制代码
1.2算法的复杂度

算法在编写可执行步伐后,运行时需要耗费时间资源和空间(内存)资源,因此衡量一个算法的好坏,一般是从时间和空间两个维度来衡量的,实时间复杂度和空间复杂度
**时间复杂度主要衡量一个算法的运行快慢,而空间复杂度主要衡量一个算法运行所需要的额外空间,**在计算机发展早期,计算机的存储容量很小我,以是对空间复杂度很是在乎,但是颠末计算机行业的迅速发展,计算机的存储容量已经达到了很高的高度,以是已经不再需要特别关注一个算法的空间复杂度
1.3 复杂度在校招中的观察


2.时间复杂度

2.1时间复杂度的概念

时间复杂度的界说:在计算机科学中,算法的时间复杂度是一个函数,它定量描述了该算法的运行时间,一个算法执行所耗费的时间,从理论上说,是不能推算出来的晚,只有把步伐放在呆板上跑起来,才气知道,但是不需要每个算法都上机测试,很麻烦我,以是才有时间复杂度的分析方式,一个算法所花费的时间与其中语句的执行次数成正比例,算法中的基本操作的执行次数,为算法的复杂度
即:找到了某条基本语句与问题规模N之间的数学表达式,就是算出了该算法的时间复杂度
  1. // 请计算一下Func1中++count语句总共执行了多少次?
  2. void Func1(int N)
  3. {
  4. int count = 0;
  5. for (int i = 0; i < N ; ++ i)
  6. {
  7.         for (int j = 0; j < N ; ++ j)
  8.         {
  9.                 ++count;
  10.         }
  11. }
  12. for (int k = 0; k < 2 * N ; ++ k)
  13. {
  14.         ++count;
  15. }
  16. int M = 10;
  17. while (M--)
  18. {
  19.         ++count;
  20. }
  21. printf("%d\n", count);
  22. }
复制代码


  • Func1执行的基本操作次数:
    F(N)=N²+2*N+10
  • N=10 F(N)=130
    N=100 F(N)=10210
    N=1000 F(N)=1002010
  • 实际中我们计算时间复杂度时,我们其实并不一定要计算准确的执行次数,而只需要大概执行次数,那么这
    里我们使用大O的渐进表示法。
2.2大O的渐进表示法

大O符号(Big O notation):是用于描述函数渐举行为的数字符号
推导大O阶方法:
1.用常数1取代运行时间中的所有加法常数
2.在修改后的运行次数函数中,只保存最高阶项
3.假如最高阶项存在且不是1,Func1的时间复杂度为


  • O(N²)
  • N = 10 F(N) = 100
  • N = 100 F(N) = 10000
  • N = 1000 F(N) = 1000000
通过上面发现大O的渐进表示法去掉了那些对结果影响不大的项,简介明了的表示出路了执行次数
另外有些算法的时间复杂度存在最好,平均和最坏情况
最坏情况:恣意输入规模的最大运行次数(上界)
平均情况:恣意输入规模的渴望运行次数
最好情况:恣意输入规模的最小运行次数(下界)
例如:在一个长度为N数组中搜刮一个数据x
最好情况:一次找到
最坏情况:N次找到
平均情况:N/2次找到
在实际中一般情况只关注算法的最坏运行情况,以是在数组中搜刮数据的时间复杂度为O(N)
2.3常见时间复杂度计算举例

实例1:
  1. // 计算Func2的时间复杂度?
  2. void Func2(int N)
  3. {
  4.         int count = 0;
  5.         for (int k = 0; k < 2 * N ; ++ k)
  6.         {
  7.                 ++count;
  8.         }
  9.         int M = 10;
  10.         while (M--)
  11.         {
  12.                 ++count;
  13.         }
  14.         printf("%d\n", count);
  15. }
复制代码
实例2:
  1. // 计算Func3的时间复杂度?
  2. void Func3(int N, int M)
  3. {
  4.         int count = 0;
  5.         for (int k = 0; k < M; ++ k)
  6.         {
  7.                 ++count;
  8.         }
  9.         for (int k = 0; k < N ; ++ k)
  10.         {
  11.                 ++count;
  12.         }
  13.         printf("%d\n", count);
  14. }
复制代码
实例3:
  1. // 计算Func4的时间复杂度?
  2. void Func4(int N)
  3. {
  4.         int count = 0;
  5.         for (int k = 0; k < 100; ++ k)
  6.         {
  7.                 ++count;
  8.         }
  9.         printf("%d\n", count);
  10. }
复制代码
实际4:
  1. // 计算strchr的时间复杂度?
  2. const char * strchr ( const char * str, int character );
复制代码
实例5:
  1. // 计算BubbleSort的时间复杂度?
  2. void BubbleSort(int* a, int n)
  3. {
  4.         assert(a);
  5.         for (size_t end = n; end > 0; --end)
  6.         {
  7.                 int exchange = 0;
  8.                 for (size_t i = 1; i < end; ++i)
  9.                 {
  10.                         if (a[i-1] > a[i])
  11.                         {
  12.                                 Swap(&a[i-1], &a[i]);
  13.                                 exchange = 1;
  14.                         }
  15.                 }
  16.                 if (exchange == 0)
  17.                         break;
  18.         }
  19. }
复制代码
实例6:
  1. // 计算BinarySearch的时间复杂度?
  2. int BinarySearch(int* a, int n, int x)
  3. {
  4.         assert(a);
  5.         int begin = 0;
  6.         int end = n-1;
  7.         // [begin, end]:begin和end是左闭右闭区间,因此有=号
  8.         while (begin <= end)
  9.         {
  10.                 int mid = begin + ((end-begin)>>1);
  11.                 if (a[mid] < x)
  12.                         begin = mid+1;
  13.                 else if (a[mid] > x)
  14.                         end = mid-1;
  15.                 else
  16.                         return mid;
  17.         }
  18.         return -1;
  19. }
复制代码
实例7:
  1. // 计算阶乘递归Fac的时间复杂度?
  2. long long Fac(size_t N)
  3. {
  4.         if(0 == N)
  5.                 return 1;
  6.         return Fac(N-1)*N;
  7. }
复制代码
实例8:
  1. // 计算斐波那契递归Fib的时间复杂度?
  2. long long Fib(size_t N)
  3. {
  4.         if(N < 3)
  5.                 return 1;
  6.         return Fib(N-1) + Fib(N-2);
  7. }
复制代码
实例答案及分析:


  • 1.实例1基本操作执行了2N+10次,通过推导大O阶方法知道,时间复杂度为O(N)
    2实例2基本操作执行了M+N次,有两个未知数,时间复杂度为O(M+N)
    3.实例3基本操作执行了100次,通过推导大O阶方法,时间复杂度为O(1)
    4.实例4基本操作执行了最好1次,最坏N次,时间复杂度一般看最坏,时间复杂度为O(N)
    5.实例5基本操作执行了最好N次,最坏执行了(N*(N+1)/2)次,大O阶推导+时间复杂度一般看最坏,时间复杂度为O(N²)
    6.实例6基本操作执行了最好1次,最坏O(logN)次,时间复杂度为O(logN)ps:logN在算法中表示底数为2,对数为N,有些地方会写成lgN(发起通过折纸查找方法理解logN)
    7.实例7通过计算分析发现基本操作递归了N次,时间复杂度为O(N)
    8.实例8通过计算分析发现基本操作递归了2N次,时间复杂度为O(2N)(发起画图递归栈桢的二叉树)
3.空间复杂度

空间复杂度也是一个数学表达式,是对一个算法在运行过程中临时占用存储空间巨细的亮度
空间复杂度不是步伐占用了多少bytes的空间,因为这个没太大意义,以是空间复杂度算的是变量的个数
空间复杂度计算规则基本跟时间复杂度雷同,也使用大O渐进表示法
注:函数运行时所需要的栈空间(存储参数,局部变量,一些寄存器信息等)在编译期间已经确定好了,因此空间复杂度主要通过函数在运行时表现申请的额外空间来确定
实例1:
  1. // 计算BubbleSort的空间复杂度?
  2. void BubbleSort(int* a, int n)
  3. {
  4.         assert(a);
  5.         for (size_t end = n; end > 0; --end)
  6.         {
  7.                 int exchange = 0;
  8.                 for (size_t i = 1; i < end; ++i)
  9.                 {
  10.                         if (a[i-1] > a[i])
  11.                         {
  12.                                 Swap(&a[i-1], &a[i]);
  13.                                 exchange = 1;
  14.                         }
  15.                  }
  16.                 if (exchange == 0)
  17.                         break;
  18.         }
  19. }
复制代码
实例2:
  1. // 计算Fibonacci的空间复杂度?
  2. // 返回斐波那契数列的前n项
  3. long long* Fibonacci(size_t n)
  4. {
  5.         if(n==0)
  6.                 return NULL;
  7.         long long * fibArray = (long long *)malloc((n+1) * sizeof(long long));
  8.         fibArray[0] = 0;
  9.         fibArray[1] = 1;
  10.         for (int i = 2; i <= n ; ++i)
  11.         {
  12.                 fibArray[i] = fibArray[i - 1] + fibArray [i - 2];
  13.         }
  14.         return fibArray;
  15. }
复制代码
实例3:
  1. // 计算阶乘递归Fac的空间复杂度?
  2. long long Fac(size_t N)
  3. {
  4.         if(N == 0)
  5.                  return 1;
  6.         return Fac(N-1)*N;
  7. }
复制代码
实例答案及分析:


  • 1.实例1使用了常数个额外空间,空间复杂度为O(1)
    2.实例2开辟了N个空间,空间复杂度为O(N)
    3.实例3递归调用了N次,开辟了N个栈桢,每个栈桢使用了常数个空间,空间复杂度为O(N)
4.常见复杂度对比

一般算法的复杂度

5.复杂度的oj练习

消失的数字OJ链接

旋转数组OJ链接


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

络腮胡菲菲

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表