计算机基础-保研笔记分享

前言

更多整理笔记见计算机基础-保研笔记分享

数据结构

插入排序

  • 直接插入排序(稳定)
    • 将序列分为有序部分和无序部分
    • 从无序部分依次选择元素与有序部分比较找到合适的位置,将原来的元素进行移动,将元素插入到相应位置上
    • 时间复杂度: O ( n 2 ) O(n^2) O(n2)
  • 希尔排序(不稳定)
    • 先将序列分为若干个子序列(每个子序列都是以 d d d为增量),对各子序列进行直接插入排序
    • 等到序列基本有序时,再对整个序列进行一次直接插入排序
    • 优点:让关键字值小的元素能够很快移动到前面,且序列基本有序时进行直接插入排序时间效率会提升很多
    • 时间复杂度: O ( n 1.3 ) O(n^{1.3}) O(n1.3) O ( n 1.5 ) O(n^{1.5}) O(n1.5)之间

交换排序

  • 冒泡排序(稳定)
    • 每一趟都将相邻元素两两比较,可以按照“前小后大”的规则进行交换
    • 总共进行 n − 1 n-1 n1趟,每趟比较 n − i n-i ni
    • 优点:每一趟不仅能找到一个最大的元素放到序列后面,而且还把其他元素理顺,并且如果下一趟排序没有发生交换则可以提前结束排序
    • 时间复杂度: O ( n 2 ) O(n^2) O(n2)
  • 快速排序(不稳定)
    • 在序列中任意选择一个元素作为中心(一般选择中间那个元素)
    • 比它大的元素一律放后面,比它小的元素一律放前面,形成左右两个子序列
    • 再把子序列按上述操作进行调整,直到所有的子序列中都只有一个元素,此时序列就是有序的**(逐步二分、二叉排序树的思想,使用递归来实现)**
    • 优点:每一趟不仅能确定一个元素的最终位置,还能对整体的趋势做出调整,时间效率较高
    • 时间复杂度: O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)

选择排序(不稳定)

  • 简单选择排序(不稳定)
    • 将序列分为两部分,第一次从无序部分中选择一个最小值,放到有序部分的第一个位置
    • 第二次从无序部分中再选择一个最小值,放到有序部分的第二个位置
    • 直到全部变为有序序列( n − 1 n-1 n1次选择)
    • 时间复杂度: O ( n 2 ) O(n^2) O(n2)
  • 堆排序(不稳定)
    • 首先将整个序列建立为大根堆(二叉树中的根节点最大)
    • 然后将堆顶元素与最后一个元素进行交换,同时输出堆顶元素
    • 重新建立大根堆,并循环执行元素交换与堆顶元素输出,直至排序完成
    • 优点在于,堆排序记住了先前的排序结果,避免了重复的交换过程
    • 时间复杂度: O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)

归并排序(稳定)

  • 核心是分治思想,归并时用到了双指针操作
  • 首先选取整个序列的中间位置,作为基准位置
  • 接着分别对基准位置的左右序列进行递归
  • 先递归,在归并
  • 合并的时候是按照两个序列各个元素从小到大的顺序进行的归并
  • 直到最后合并成一个有序序列
  • 时间复杂度: O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)

基数排序(稳定)

  • 前提:关键字为数字,才能按照位,进行分配和收集

  • 主要操作步骤

    • 分配:按照位,分配到0~9这十个序列内
    • 收集:将分配完的数据,按顺序重新整合成一个序列
    • 之后继续向高位进行分配和收集,直到分配到最大位
    • 分配和收集的次数:最大关键字的位数 d d d
  • 时间复杂度: O ( d + n ) O(d+n) O(d+n)

内部排序总结

在这里插入图片描述

  • 对于数据规模较小的情况,直接插入排序、冒泡排序、简单选择排序( O ( n 2 ) O(n^2) O(n2)
  • 对于数据规模中等的情况,希尔排序( O ( n 1.3 − n 1.5 ) O(n^{1.3}-n^{1.5}) O(n1.3n1.5)
  • 对于数据规模较大的情况,快速排序、堆排序、归并排序、基数排序,其中快排和堆排序都是不稳定的,而归并排序和基数排序是稳定的

面试真题

  • 点操作和箭头操作的区别
    • **相同点:**两个都是二元操作符,其右操作符是成员的名称
    • 区别
      • 简单来说,结构体用点,结构体指针用箭头
      • 点操作".",左边的操作数是一个“结果为结构体”的表达式,用结构体名加“.”加成员名就可以引用成员了,就如同int a一样
      • 箭头操作"->",则要声明一个结构体的指针,还要手动开辟一个该结构体的内存,然后把返回的指针给声明的结构体指针,才能使用"->"
      • 此外,(*a).b 等价于 a->b
  • 循环和递归的区别
    • 循环:反复执行某一段代码,如果不加控制,就会形成死循环
      • 优点是时空效率高,运行时间只因循环次数增加而增加,没什么额外开销,空间上也没有什么增加
      • 缺点就是不容易理解,编写复杂问题时困难
    • 递归:函数体中调用自己,如果不加控制,将无休止的调用自己,直到堆栈溢出
      • 优点就是代码简单,易理解,容易编程
      • 缺点是递归用栈机制实现的(本质上是后进先出),每深入一层,都要占去一块栈数据区域,而且递归也带来了大量的函数调用,这也有许多额外的时间开销,所以在深度大时,它的时空性就不好了
  • C++中new和malloc的区别
    • 最大的区别:new在申请空间时,会调用构造函数,而malloc则不会调用
    • 在属性上,new是C++的一个关键字,需要编译器的支持,而malloc是库函数,需要添加头文件(stdlib.h)
    • 使用的参数方面,new在申请内存分配时不需要指定内存块大小,编译器会根据申请的类型计算出大小,而malloc需要指定所需内存的大小
  • 如何判断图里有环?
    • 拓扑排序(有环图一定无拓扑排序)
      • 主要思想就是根据每个结点的度,删除度小于等于1的结点及其相邻的边
      • 然后看是不是还有度小于等于1的结点,如果有的话,就继续删除,要不然就有环了
    • DFS(深度优先搜索)
      • 如果在遍历的过程中,发现某个结点有一条边指向已访问过的结点
      • 并且这个已访问过的结点不是上一步访问的结点,则表示存在环
  • Java和C++区别
    • Java是纯面向对象的语言,C++既有面向对象又有面向过程的部分
    • C++运行速度比Java快,Java具有比C++更好的跨平台性
    • Java没有指针,C++有
  • 内联函数定义及作用
    • 如果想把一个函数定义为内联函数,则需要在函数名前面放置关键字 inline
    • 在类定义中的定义的函数都是内联函数,即使没有使用 inline 说明符
    • 引入内联函数的目的是为了提高函数调用的效率
    • 一般的调用函数流程为:当前调用命令的地址被保存下来,程序流跳转到所调用的函数并执行该函数,最后跳转回之前所保存的命令地址,继续执行原来的程序
    • 调用内联函数时就直接把该函数的机器码插入到调用它的地方。提高了程序执行的效率
  • 面向对象和面向过程的区别
    • 面向对象:把整个需求按照特点、功能划分,将这些存在共性的部分封装成对象
      • 优点:容易维护、方便代码复用和应用扩展
      • 缺点:消耗资源,运行性能低
    • 面向过程:分析出实现需求所需的步骤,通过函数一步一步实现这些步骤,接着依次调用
      • 优点:运行性能好,且容易理解
      • 缺点:不易维护、复用和扩展
  • 重载和重写的区别
    • 重载是在一个类中,定义相同的方法名,不同的参数列表,对返回类型和访问权限没有要求
      • 体现的是编译时的多态性
    • 重写是在子类与父类之间,定义相同的方法名,参数列表、返回类型必须相同,且重写的访问权限不能低于被重写的访问权限
      • 体现的是运行时的多态性
  • 树和图的区别
    • 树是分层结构,图是网络模型结构
    • 树有根节点,图没有根节点的概念
    • 树的边数为节点数减一,图的边数没有限制
    • 树不能有环,图可以有
  • 函数复用
    • 其实就是将代码封装成一个函数,体现的是函数模块化设计
    • 在C++中可以使用多态来实现
  • C++命名规则
    • 以字母 A-Z 或 a-z 或下划线 _ 开始,后跟零个或多个字母、下划线和数字(0-9)
  • 递推的本质
    • 寻找相邻两项之间的某种关系,通过一个公式或者一个规则来建立联系,从而实现递推(例如斐波那契数列1 1 2 3 5 8 13 … )
    • 从n开始递推,从n推到n-1,一直推到比较小的数,就可以直接计算了
  • 快速幂
    • 一种快速计算整数幂的小算法
    • 如果采用递归快速幂,本质是二分思想
    • 计算 a n a^n an,如果 n n n是偶数(不为0),那么就先计算 a n / 2 a^{n/2} an/2,然后平方
    • 如果 n n n是奇数,那么就先计算 a n − 1 a^{n-1} an1,再乘上a;递归出口是** a 0 = 1 a^0=1 a0=1**
  • 编译型和解释型语言区别
    • 编译型语言:在程序执行之前,有一个单独的编译过程,将程序翻译成机器语言,以后执行这个程序的时候,就不用再进行翻译了
    • 要求必须提前将所有源代码一次性转换成二进制指令,也就是生成一个可执行程序
    • 使用的转换工具称为编译器
      • C/C++ 、汇编语言
    • 解释型语言:是在运行的时候将程序翻译成机器语言,所以运行速度相对于编译型语言要慢
    • 一边执行一边转换,需要哪些源代码就转换哪些源代码不会生成可执行程序
    • 使用的转换工具称为解释器
      • Python,MATLAB,Java,C#
  • C语言的main函数参数列表有哪些?
    • main (int argc, char *argv[])
    • argc(第一个形参)必须是整型变量,参数的个数
    • argv(第二个形参)必须是指向字符串的指针数组,参数的值,以字符串的格式存储
  • 内存对齐
    • 计算机中的内存空间都是按照byte划分的
    • 系统对基本数据在内存中的存放位置会有限制,要求这些数据的首地址是某个数的倍数(通常为4或8),这就是所谓的内存对齐
    • 举例:int占4byte,char占1byte,那么将它们放到一个结构体中应该占4+1=5byte;但是实际上,通过运行程序得到的结果是8 byte

猜你喜欢

转载自blog.csdn.net/weixin_43799388/article/details/123882682