基础面经札记1

1.什么时候用链表,什么时候用数组,优缺点?

根据数组和链表的特点,在对数据操作进行查询操作比较多的可以用数组,插入删除操作比较多的可以用链表。
数组
优点:内存为一连续的区域 ,查询效率 比链表高,使用方便 。
缺点:大小固定,不适合动态存储,不方便动态添加。
链表
优点:可动态添加删除 大小可变
缺点:只能通过顺次指针访问,查询效率低

2.递归是什么,讲一讲

程序调用自身的编程技巧称为递归( recursion)
一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。
一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。

3.啥是死锁,怎么解决死锁

一般是指由2个或以上的线程互相持有对方所需要的资源,导致这些线程一折处于等待其他线程释放资源的状态,无法继续执行下去,如果线程都不主动释放所占有的资源,将产生死锁。
死锁发生的条件是:1.互斥;2.占有且等待;3.不可抢占;4.循环等待
除了互斥是不能破坏的,只要破坏其他三个之一,就可以避免死锁。

  1. 一次性申请所有资源
  2. 占有一部分资源时其他资源申请不到就主动释放
  3. 按序申请资源,破坏“循环等待条件”

4.什么是线程的锁,有什么用

当某个资源被多个线程同时访问修改或读取的时候,会出现数据的一致性问题,因此我们需要保证多个线程安全的访问竞争资源(全局内容),所以就引进了锁。锁能保证多个线程安全的访问竞争资源。

5.二叉树和堆有什么区别

二叉树:
二叉树是一种特殊的树。二叉树的特点是每个结点最多有两个子节点,左边的叫做左子节点,右边的叫做右子节点,或者说每个结点最多有两棵子树。更加严格的递归定义是:二叉树要么为空,要么由根结点、左子树和右子树组成,而左子树和右子树分别是一棵二叉树。

堆:堆是一种特殊的完全二叉树。
所有父结点都比子结点要小的完全二叉树我们称为最小堆。反之,如果所有父结点都比子结点要大,这样的完全二叉树称为最大堆。堆是一个完全二叉树,以最大堆为例,每个结点的值都大于或等于其左右孩子结点的值;

二叉树是一种主要用于查询的数据结构
堆是为了实现排序而设计的一种数据结构

6.varchar与char有什么区别?

1.区别一,定长和变长
char 表示定长,长度固定,varchar表示变长,即长度可变。char如果插入的长度小于定义长度时,则用空格填充;varchar小于定义长度时,还是按实际长度存储,插入多长就存多长。
因为其长度固定,char的存取速度还是要比varchar要快得多,方便程序的存储与查找;但是char也为此付出的是空间的代价,因为其长度固定,所以会占据多余的空间,可谓是以空间换取时间效率。varchar则刚好相反,以时间换空间。
2.区别二,存储的容量不同
对 char 来说,最多能存放的字符个数 255,和编码无关。
而 varchar 呢,最多能存放 65532 个字符。varchar的最大有效长度由最大行大小和使用的字符集确定。整体最大长度是 65,532字节。

7.varchar的单位是啥

4.1之前的版本,VARCHAR的单位是字节
4.1及之后的版本,VARCHAR的单位是字符;

8. tcp三次握手

三次握手图片示意的过程是:
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。完成三次握手,客户端与服务器开始传送数据.

9.为什么要三次握手?

第一次握手:客户端发送网络包,服务端收到了。这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。
第二次握手:服务端发包,客户端收到了。这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常。
第三次握手:客户端发包,服务端收到了。这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常。所以三次握手就能确认双发收发功能都正常,缺一不可

10.如何保证redis与数据库的一致性

一般来说我们可以在更新的时候,先删除缓存,然后再更新数据库。
读的时候,先读缓存;如果没有的话,就读数据库,同时将数据放入缓存,并返回响应。
然后当高并发有有多个线程时,为了防止数据在删除缓存后还没更新数据库数据时其他线程就先从数据库读出了旧数据而造成的数据不一致其他问题,可以先把“修改DB”的操作放到一个队列,后面读请求过来之后,“更新缓存”的操作也放进同一个队列,每个队列,对于一个作业线程,按照队列的顺序,依次执行相关操作,这样就可以保证“更新缓存”一定是在DB修改之后,以保证数据一致性。当然读请求过多的时候,队列里面会有多个“更新缓存”操作串在一起,这是没意义的,这时候往队列里面塞数据的时候可以先判断一下,有的话就不用再塞进去了。
(遇到更新DB比较频繁的业务场景时,可能会导致读请求长时间阻塞,这个时候可以通过扩机器增加吞吐量,或者可以先返回一个旧的值。)

11.sql优化

1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,
3.应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。
4.应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:
5.不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。
6.在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,

12.大数据高并发情况下如何处理

1,页面静态化- 用户可以直接获取页面,不用走那么多流程,比较适用于页面不频繁更新。
2,使用缓存- 第一次获取数据从数据库准提取,然后保存在缓存中,以后就可以直接从缓存提取数据。不过需要有机制维持缓存和数据库的一致性。
使用储存过程-那些处理一次请求需要多次访问数据库的操作,可以把操作整合到储存过程,这样只要一次数据库访问就可以了。
3,批量读取 - 高并发情况下,可以把多个请求的查询合并到一次进行,以减少数据库的访问次数
4,延迟修改 - 高并发情况下,可以把多次修改请求,先保存在缓存中,然后定时将缓存中的数据保存到数据库中,风险是可能会断电丢失缓存中的数据,

数据库的优化
6.首先sql语句的优化,如数据库字段设置,多表联查等等,,建立数据表可根据业务进行水平、垂直分表,数据库读写分离,主从数据库。
7.使用索引,适当的添加索引对数据库的优化- 索引可以看作是特殊的缓存,尽量使用索引就要求where字句中精确的给出索引列的值。
8.使用集群 - 将并发请求分配到不同的服务器上,可以是业务服务器,也可以是数据库服务器。
9.使用分布式 - 分布式是把单次请求的多项业务逻辑分配到多个服务器上,这样可以同步处理很多逻辑,一般使用与特别复杂的业务请求。

13.栈和堆的运行速度

1.栈是本着LIFO(后进先出)原则的存储机制, 对栈数据的定位相对比较快速, 而堆则是随机分配的空间, 处理的数据比较多, 无论如何, 至少要两次定位.
2.栈是由CPU提供指令支持的, 在指令的处理速度上, 对栈数据进行处理的速度自然要优于由操作系统支持的堆数据.
3.栈是在一级缓存中做缓存的, 而堆则是在二级缓存中, 两者在硬件性能上差异巨大.
4. 堆的内容被操作系统交换到外存的概率比栈大,栈一般是不会被交换出去的。

14.Java垃圾回收

与C/C++相比,java语言不需要程序员直接控制内存回收,java程序的内存分配和回收都是由jvm在后台自动进行,jvm会负责回收那些不再使用的内存,这种机制被称为垃圾回收机制(Garbage Collection,GC):
一、主要负责两件事情:
1.发现无用的对象;
2.回收被无用对象占用的内存空间,使之再次被程序使用(一般是在CPU空闲或者内存不足时)。
二、特点
1.垃圾回收机制的工作目标是回收无用对象的内存空间,这些内存空间都是jvm堆内存(运行时数据区,用以保存类的实例,即对象)里的内存空间,不包含其它物力资源,比如数据库连接、磁盘I/O等;
2.Java语言没有显式的提供分配内存和删除内存的方法,一些开发人员将引用对象设置为null或者调用System.gc()或者Runtime.getRuntime.gc()来释放内存(后两种方法仅是建议,慎重使用);
3.垃圾回收不可预知,不同的jvm采用不同的垃圾回收机制和算法,有可能定时发生,有可能CPU空闲时发生,也有可能内存耗尽时发生

15.交换两个数字,不用第三个数

相加之后再减也可以实现交换
a=1,b=2
a = a + b = 3
b = a – b = 3 – 2 = 1
a = a-b=3-1=2

16.topk问题(堆,排序)

堆是一种特殊的二叉树,其堆顶元素是最特殊的元素,对于堆中的任意一个节点,它的值总是不小于或不大于其父节点的值,堆具有这样的特性,究竟有什么用处呢?今天就来看看堆的应用。
1.堆排序
堆排序:利用堆来对一组无序的数据进行排序。
堆排序的原理:利用堆删除的思想来对数据进行排序。堆顶元素是堆中所有元素的最大值或最小值,每次将堆顶元素与堆中的最后一个元素交换,将堆的元素个数减一,然后再将剩余的元素进行堆的调整,重复堆删除的操作,直到堆中剩下一个元素为止,得到的就是一个有序的序列。

TOP K问题就是在一组数据中,取这组数据中前K个最大值或最小值。也就是将一组数据进行排序,然后取前K个元素。但计算机的内存是有限的,也就意味着不能对一组海量数据一次进行排序。
对于N个数据取前K个最大或最小元素:
1.我们可以先取数据的前K个进行建堆
2.再依次将(K+1)到(N)的元素和堆顶元素进行比较,如果满足条件就将堆顶元素进行替换
直到比较完最后一个元素,堆中元素就是我们要求的TOP K。
时间复杂度O(NlogK)

17.堆和分治法的比较,使用场景

分治法,分治法最容易理解,主要思想是:将大问题分解成子问题,求解出不同子问题的解,由各个子问题的解得到最终解。
适用场景:
原问题的计算复杂度随着问题的规模的增加而增加
原问题能够被分解成更小的问题
子问题的结构和性质与原问题一样,并且相互独立,子问题之间不包含公共的子问题。
原问题分解出的子问题的解可以合并为该问题的解。
堆是一种特殊的二叉树,堆排序指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
适合用heap的场合是优先队列,需要在一组不停更新的数据中不停地找最大/小元素

18.进程和线程

进程:
进程是程序执行的的一个实例
每个进程拥有独立内存地址空间
是系统进行资源分配和调度的基本单位

线程:
线程是进程的一个实体,是进程的一个执行路径
CPU调度和分派的基本单位
线程本身不会独立存在
系统不会为线程分配内存,多个线程之间共享所属进程的资源
线程只拥有在运行中必不可少的资源(如程序计数器,栈等)

为什么要有线程?因为每个进程都有自己的地址空间,即进程空间,在并发请求中,如果为每一个请求创建一个进程,系统开销很大,请求响应效率低,因此引进了线程

一个程序至少一个进程,一个进程至少一个线程,进程中多个线程共享进程的资源
进程通信是通过管道,信号量,套接字,消息队列文件等来通信的

19.多线程和多进程
在这里插入图片描述

20.如何判断链表是否有环

1.可以用两个指针,一个走的快一点,一个走的慢一点,假设有环,两个指针先后入环后总会碰到,这时就能判断是否有环了
2.遍历比较,如果值有可能重复的话就可以用地址比较,值不重复可以用值来比较

21.面向对象和面向过程

对象就是类,过程就是顺序,选择,循环,数组,函数:
面向对象是以数据和功能为中心,而面向过程以功能为中心.
面向过程就是分析出解决问题所需要的步骤,然后用函数把这些问题一步一步的实现,然后再使用的时候依次调用就可以了。
面向对象就是把构成问题的事物分解成各个对象,构建对象的目的不是来完成一个步骤的,而是为了描述某个事物在解决整个问题的步骤中的行为。
面向过程:

  1. 优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、 Linux/Unix等一般采用面向过程开发,性能是最重要的因素。
  2. 缺点:没有面向对象易维护、易复用、易扩展

面向对象:

  1. 优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统 更加灵活、更加易于维护
  2. 缺点:性能比面向过程低

22.面向对象3大特性,可不可以用C实现?如何用C实现这些特性?

特性:继承,多态,封装
封装:C语言中有struct结构体类型,能够将多种数据类型封装在一起,再用函数指针对数据的操作一起封装
继承:通过已有类的一些方法去辅助新生成的类,进行组合,即在新类中直接定义已有类的对象,通过该对象的一些方法去辅助新类的操作。
多态:用值的覆盖,去改变函数指针,可以达到多态的效果

23.sql语句如何编写保证安全性

1.防止sql注入,对特殊字符进行转译与过滤,使用sql语句绑定变量
2.最小用户权限设置,最好不要使用root用户连接数据库
3.当sql运行出错的时候,不要将错误信息全部显示给用户

24.解决哈希冲突的方法

哈希冲突的产生原因
哈希是通过对数据进行再压缩,提高效率的一种解决方法。但由于通过哈希函数产生的哈希值是有限的,而数据可能比较多,导致经过哈希函数处理后仍然有不同的数据对应相同的值。这时候就产生了哈希冲突。

1.开放地址方法
 (1)线性探测
  按顺序决定值时,如果某数据的值已经存在,则在原来值的基础上往后加一个单位,直至不发生哈希冲突。 
 (2)再平方探测
  按顺序决定值时,如果某数据的值已经存在,则在原来值的基础上先加1的平方个单位,若仍然存在则减1的平方个单位。随之是2的平方,3的平方等等。直至不发生哈希冲突。
 (3)伪随机探测
  按顺序决定值时,如果某数据已经存在,通过随机函数随机生成一个数,在原来值的基础上加上随机数,直至不发生哈希冲突。
2.链式地址法(HashMap的哈希冲突解决方法)
对于相同的值,使用链表进行连接。使用数组存储每一个链表。
优点:
 (1)拉链法处理冲突简单,且无堆积现象,即非同义词决不会发生冲突,因此平均查找长度较短;
 (2)由于拉链法中各链表上的结点空间是动态申请的,故它更适合于造表前无法确定表长的情况;
 (3)开放定址法为减少冲突,要求装填因子α较小,故当结点规模较大时会浪费很多空间。而拉链法中可取α≥1,且结点较大时,拉链法中增加的指针域可忽略不计,因此节省空间;
 (4)在用拉链法构造的散列表中,删除结点的操作易于实现。只要简单地删去链表上相应的结点即可。
缺点:指针占用较大空间时,会造成空间浪费,若空间用于增大散列表规模进而提高开放地址法的效率。
3.建立公共溢出区
  建立公共溢出区存储所有哈希冲突的数据。
4.再哈希法
  对于冲突的哈希值再次进行哈希处理,直至没有哈希冲突。

25 JVM运行时内存结构

1、The pc Register(PC 寄存器、程序计数器)
2、Java Virtual Machine Stacks(Java 虚拟机栈、Java 栈)
3、Native Method Stacks(本地方法栈,C栈)
4、Heap(堆)
5、Method Area(方法区,JDK8 中的实现叫元数据区(本地内存中),JDK7 中的实现叫永久代(JVM中))
6、Run-Time Constant Pool(运行时常量池,方法区的一部分)

26.Java代码从编写完成到运行经历了什么?

在这里插入图片描述

27.深搜和广搜区别

BFS(广): 常用于找单一的最短路线,它的特点是 “搜到就是最优解”,而 DFS 用于找所有解的问题,它的空间效率高,而且找到的不一定是最优解,必须记录并完成整个搜索,故一般情况下,深搜需要非常高效的剪枝。
BFS:对于解决最短或最少问题特别有效,而且寻找深度小,但缺点是内存耗费量大(需要开大量的数组单元用来存储状态)。

DFS(深):对于解决遍历和求所有问题有效,对于问题搜索深度小的时候处理速度迅速,然而在深度很大的情况下效率不高。

28.GC原理解析

在合适的时间触发垃圾回收,将不需要的内存空间回收释放,避免无限制的内存增长导致的OOM。
当一个对象地址没有变量去引用的时候,该对象就会成为垃圾对象,垃圾回收器在空闲时就会去对齐进行内存清理回收
怎么知道可回收?
GC Roots Analysis:主流用这个判断
基本思路就是通过一系列名为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的
即使在可达性分析算法中不可达的对象,也并非是“非死不可”的,这时候它们暂时处于“缓刑”阶段,要真正宣告一个对象死亡,至少要经历两次标记过程:如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,那它将会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,虚拟机将这两种情况都视为“没有必要执行”。(即意味着直接回收)
如果这个对象被判定为有必要执行finalize()方法,那么这个对象将会放置在一个叫做F-Queue的队列之中,并在稍后由一个由虚拟机自动建立的、低优先级的Finalizer线程去执行它。
GC Root 引用点
虚拟机栈(栈帧中的本地变量表)中引用的对象;
方法区中类静态属性引用的对象;
方法区中常量引用的对象;
本地方法栈中JNI(即一般说的Native方法)引用的对象;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值