找工作再也不愁之面试题全覆盖-设计模式&数据结构

设计模式部分

常见的设计模式说一下

单例模式:一个类只能有一个实例,分为饿汉模式(迫切加载)和懒汉模式(延迟加载)和枚举。

工厂模式:隐藏了产品的复杂创建过程,实现生产功能的复用,让产品生产更加高效。分为简单工厂(需要来回切换生产线),工厂方法(开设新的生产线),抽象工厂(制定创建产品的接口,让子工厂选择创建哪种产品)

在Spring中各种的BeanFactory创建bean都用到了

模板模式:定义一个算法骨架或者算法的流程,而不同的实例实现方式不同,将某个或多个具体的实现延迟到子类中,比如RedisTemplate实现了RedisOperations,ElasticSearchTemplate实现了ElasticsearchOperations

代理模式:不直接使用实际对象,通过调用代理对象间接调用实际对象,主要用作对实际对象的增强,分为静态代理,JDK动态代理,CGLIB动态代理比如Spring的AOP原理就是动态代理,当目标对象实现了接口会使用JDK动态代理,没有实现接口会使用CGLIB动态代理

适配器模式:将不兼容的接口转换为可兼容的接口的中间类,比如HandlerInterceptorAdapter ,我们定义拦截器时不需要覆写HandlerInterceptor中的所有方法,因为适配器类帮我们做了空实现。但JDK1.8之后,给接口中增加了默认方法,可以有方法体,因此这些适配器类已经失去作用了

观察者模式:当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新,比如Spring中的ApplicationListener

什么是单例,如何实现

一个类只能有一个实例,主要用于需要频繁使用的对象避免频繁初始化和销毁来提高性能,或者资源需要相互通信的环境

主要实现方式有,饿汉模式,懒汉模式,枚举,静态内部类

饿汉模式,是在类加载过程中就将这个单例对象实例化,需要将构造方法私有化,定义一个成员变量并new一个该类的实例作为初始值,提供一个公共的静态方法获取这个实例

懒汉模式,是在使用时才创建这个单例对象,需要将构造方法私有化,定义一个该类的成员变量不赋初始值,提供一个获取实例的公共静态方法。特别注意这个方法需要保证多线程环境下的并发安全性,可以通过DCL加volatile关键字来解决

枚举,直接在枚举中定义字段,它就是单例并且线程安全的

静态内部类,在类中搞一个静态内部类,在静态内部类中搞一个目标类的静态成员变量并且new一个实例作为初始值。然后在目标类中定义一个获取实例的静态方法,方法返回的就是静态内部类中的成员变量。这种方式能保证线程安全,也能实现延迟加载。缺点是这种方式传参不太方便

模板模式的作用

定义一个算法骨架或流程,而将某个或多个具体的实现延迟到子类中,使得子类可以在不修改当前算法的结构情况下,重新定义当前算法的某些特定步骤

什么是适配器模式

在计算机编程中,适配器模式,将一个类的接口适配成用户所期待的。一个适配允许通常因为接口不兼容而不能在一起工作的类工作在一起,做法是将类自己的接口包裹在一个已存在的类中。

举例:HandlerInterceptorAdapter ; WebMvcAutoConfigurationAdapter;

什么是观察者模式

在观察者模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。

举例:ApplicationListener ; ServletRequestListener ; HttpSessionListener;ServletContextListener;

什么是策略模式

策略模式作为一种[软件设计模式],指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。比如每个人都要“交个人所得税”,但是“在美国交个人所得税”和“在中国交个人所得税”就有不同的算税方法。

举例:InstantiationStrategy ;

什么是代理模式?有几种代理?

不直接使用实际对象,通过调用代理对象间接调用实际对象,主要用作对实际对象的增强,分为静态代理,JDK动态代理,CGLIB动态代理

JDK动态代理和CGLIB动态代理的区别?

JDK动态代理是jdk提供的,我们可以直接使用,而CGLIB需要导入第三方库

JDK动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用目标方法前调用InvokeHandler来处理

CGLIB动态代理是先加载目标类的class文件,然后修改其字节码生成子类来实现的

数据结构

数据结构有哪几种分类

按照逻辑结构分

  • 集合:没有相互关系的一堆数据
  • 线性结构:元素存在一对一的相互关系
  • 树形结构:元素存在一对多的相互关系
  • 图形结构:元素存在多对多的相互关系

按照物理结构分

  • 顺序存储结构:用一组地址连续的存储空间依次存储线性表的数据元素,也叫顺序存储结构,比如数组
  • 链接存储结构:用一组任意的存储空间来存储线性表中的数据元素,不要求相邻元素在物理位置上也相邻,比如链表
  • 数据索引存储结构:建立附加的索引来标识节点的地址,通过索引,可以很快检索数据
  • 数据散列存储结构:将数据元素的存储位置与关键字之间建立确定的对应关系,加快查找的速度,又叫hash存储
数组和链表在内存中的存储结构有什么区别

数组在内存中是一组连续的存储空间,它随机存取元素性能很高,但是插入和删除操作,需要移动其他元素,因此性能很低

链表在内存中的存储空间可以是不连续的,而在每一个元素中都保存相邻节点的指针,因此它的存储密度相对较小,查找的性能低,因为需要从第一个元素依次遍历,但是它的插入和删除操作性能很高,因为它不需要移动节点,只需要改变相邻节点指针就行了,同时它更容易造成内存的碎片化

说一下散列存储(Hash存储) , 什么是Hash冲突 , 有什么解决方案

散列存储,它通过把关键码的值映射到表中的一个位置,来提高查询的速度。而这个映射函数叫做散列函数。

哈希冲突,也叫哈希碰撞,指的是两个不同的值,计算出了相同的hash,也就是两个不同的数据计算出同一个下标,通常解决方案有:

  • 拉链法,把哈希碰撞的元素指向一个链表
  • 开放寻址法,把产生冲突的哈希值作为值,再进行哈希运算,直到不冲突
  • 再散列法,就是换一种哈希算法重来一次
  • 建立公共溢出区,把哈希表分为基本表和溢出表,将产生哈希冲突的元素移到溢出表
说说 数组,链表,循环,嵌套循环的时间复杂度

时间复杂度是用来度量算法执行的时间长短,通常我们用O(f(n))渐进时间复杂度来衡量,比如说

  • 要在 hash 表中找到一个元素就是 O(1)
  • 要在无序数组中找到一个元素就是 O(n)
  • 访问数组的第 n 个元素是 O(1)
  • 二分搜索的时间复杂度最好的情况是 O(1),最坏情况(平均情况)下 O(log n)
  • 访问链表的第 n 个元素是 O(n)
  • 一个For循环是O(n)
  • 两个For循环嵌套是O(n2)
  • 三个Foreach嵌套是O(n3)
JDK中线性结构的集合有哪些

数组:按照顺序物理结构存储,ArrayList

链表:按照链式物理结构存储,LinkedList

栈:LIFO后进先出的线性存储结构,分为用数组实现的顺序栈,用链表实现的链栈

队列:FIFO先进先出的线性存储结构,分为顺序队列和链式队列串:特殊的线性存储结构,String,StringBuffer,StringBuilder

你说一下树形结构对比线性结构的优势

线性结构,对于大量的输入数据,访问时间很长,效率很低,树形结构的优势在于它查找数据性能很高

说一下树的分类,以及你对它们的理解

树有二叉树,多叉树,他们特点如下

  • 二叉树:树中任意节点最多只有两个分叉的树,它又分为二叉排序树,平衡二叉树,赫夫曼树,红黑树
  • 二叉排序树,它是一个有序的二叉树,优势在于查找插入数据的性能很高,但是可能会出现倾斜而变成数组
  • 平衡二叉树,二叉排序树进化形态,要求任何节点的两颗字数高度差不大于1。它的查询性能很高,但是每次增删元素,会重排序导致性能低
  • 红黑树,自平衡二叉树,要求根节点和叶子节点是黑色,其他节点红黑交替,在任何一个子树中,从根节点向下走到空姐点的路径经过的黑节点数相同。从而保证了平衡。它的查询性能比平衡二叉树稍低,插入和删除元素的性能大幅提高。

多叉树:解决二叉树存储大规模数据时,深度过大而导致IO性能低,查询效率低的问题,常见有B树和B+树,字典树,后缀树等等

  • B树,自平衡的树,一个节点可以存储多个key,和拥有key数量+1个分叉,适用于读写相对大的数据块,比如文件系统,数据库索引。因为相对二叉树来说,节点存储key越多,分叉越多,需要的节点越少,树高越矮,IO次数少,查询效率越高。
  • B+树,B树升级版,它的内部节点只存储key,不存储具体数据,叶子节点存放key和具体数据。这就使得每个节点可以存更多的key,树的高度更低,查询更快,同时它每次查询都会到叶子节点,查询速度更稳定。并且所有的叶子节点会组成一个有序链表,方便区间查询
平衡树和红黑树的区别

平衡二叉树,二叉排序树进化形态,要求任何节点的两颗字数高度差不大于1。它的查询性能很高,但是每次增删元素,会重排序导致性能低

红黑树,自平衡二叉树,要求根节点和叶子节点是黑色,其他节点红黑交替,在任何一个子树中,从根节点向下走到空姐点的路径经过的黑节点数相同。从而保证了平衡。它的查询性能比平衡二叉树稍低,插入和删除元素的性能大幅提高。

多叉树相比二叉树的优势

因为二叉树在大规模的数据存储中,树会高的没谱,这会导致IO读写过于频繁,查询效率低下

多叉树可以解决这个问题,它每层可以存放更多的数据,因此能大幅度降低树的深度,提高查询性能

B-tree和b+tree的区别

一是节点存储内容上的区别:B树每个节点都可以存放key,存放数据,而B+树所有内部节点只存放key,叶子节点存放key和数据,因此它的节点能存放更多数据,降低树高,查询性能更快

二是B+树所有的叶子节点会构成一个链表结构,方便区间查找和排序

说一下ES用到了什么数据结构

ES是使用了数据索引存储结构,它是通过为关键字建立索引,通过索引找到对应的数据,这种索引也叫倒排索引,可以实现快速检索

Mysql索引使用的是什么数据结构

使用的是B+树,B树升级版,它的内部节点只存储key,不存储具体数据,叶子节点存放key和具体数据。这就使得每个节点可以存更多的key,树的高度更低,查询更快,同时它每次查询都会到叶子节点,查询速度更稳定。并且所有的叶子节点会组成一个有序链表,方便区间查询

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

墨家巨子@俏如来

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值