华为一面:
1、图的表示方式?
(1)邻接表法:邻接表的核心思想就是针对每个顶点设置一个邻居表。
以上面的图为例,这是一个有向图,分别有顶点a, b, c, d, e, f, g, h共8个顶点。使用邻接表就是针对这8个顶点分别构建邻居表,从而构成一个8个邻居表组成的结构,这个结构就是我们这个图的表示结构或者叫存储结构。
a, b, c, d, e, f, g, h = range(8)
N = [{b, c, d, e, f}, # a 的邻居表
{c, e}, # b 的邻居表
{d}, # c 的邻居表
{e}, # d 的邻居表
{f}, # e 的邻居表
{c, g, h}, # f 的邻居表
{f, h}, # g 的邻居表
{f, g}] # h 的邻居表
(2)邻接矩阵:邻接矩阵的核心思想是针对每个顶点设置一个表,这个表包含所有顶点,通过True/False来表示是否是邻居顶点。还是针对上面的图,分别有顶点a, b, c, d, e, f, g, h共8个顶点。使用邻接矩阵就是针对这8个顶点构建一个8×8的矩阵组成的结构,这个结构就是我们这个图的表示结构或存储结构。
a, b, c, d, e, f, g, h = range(8)
N = [[0, 1, 1, 1, 1, 1, 0, 0], # a的邻接情况
[0, 0, 1, 0, 1, 0, 0, 0], # b 的邻居表
[0, 0, 0, 1, 0, 0, 0, 0], # c 的邻居表
[0, 0, 0, 0, 1, 0, 0, 0], # d 的邻居表
[0, 0, 0, 0, 0, 1, 0, 0], # e 的邻居表
[0, 0, 1, 0, 0, 0, 1, 1], # f 的邻居表
[0, 0, 0, 0, 0, 1, 0, 1], # g 的邻居表
[0, 0, 0, 0, 0, 1, 1, 0]] # h 的邻居表
2、图的遍历方式?
通常有两种遍历图的方法:深度优先遍历和广度优先遍历。它们对无向图和有向图都适用。图的遍历算法是求解图的连通性问题、拓扑排序和求关键路径等算法的基础。
1) 深度优先遍历: 从图中某个顶点v出发,访问该顶点,然后依次从v的未被访问的邻接点出发继续深度优先遍历图中的其余顶点,直至图中所有与v有路径相通的顶点都被访问完为止;若此时尚有顶点未被访问,则选择一个顶点作为起始点,重复上述过程,直到所有的顶点都被访问。深度优先遍历是一个递归的过程。
2) 广度优先遍历:首先,从图的某个顶点v出发,依次访问与v相邻的未被访问的顶点,然后分别从这些顶点出发,广度优先遍历,直至所有的顶点都被访问完。
如上图中,广度优先遍历得到的序列为:
0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 ->7
3、进程的通信方式?
进程间通信(IPC,InterProcess Communication)是指在不同进程之间传播或交换信息。IPC的方式通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享存储、Socket、Streams等。其中 Socket和Streams支持不同主机上的两个进程IPC。
以Linux中的C语言编程为例。
一、管道:管道,通常指无名管道,是 UNIX 系统IPC最古老的形式。
特点:它是半双工的(即数据只能在一个方向上流动),具有固定的读端和写端;它只能用于具有亲缘关系的进程之间的通信(也是父子进程或者兄弟进程之间);它可以看成是一种特殊的文件,对于它的读写也可以使用普通的read、write 等函数;但是它不是普通的文件,并不属于其他任何文件系统,并且只存在于内存中。
二、FIFO:也称为命名管道,它是一种文件类型。
特点:FIFO可以在无关的进程之间交换数据,与无名管道不同;FIFO有路径名与之相关联,它以一种特殊设备文件形式存在于文件系统中。
三、消息队列:是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。
特点:消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级;消息队列独立于发送与接收进程,进程终止时,消息队列及其内容并不会被删除;消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。
四、信号量:信号量(semaphore)与已经介绍过的 IPC 结构不同,它是一个计数器。信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。
特点:信号量用于进程间同步,若要在进程间传递数据需要结合共享内存;信号量基于操作系统的 PV 操作,程序对信号量的操作都是原子操作;每次对信号量的 PV 操作不仅限于对信号量值加 1 或减 1,而且可以加减任意正整数;支持信号量组。
五、共享内存:共享内存(Shared Memory),指两个或多个进程共享一个给定的存储区。
特点:共享内存是最快的一种 IPC,因为进程是直接对内存进行存取;因为多个进程可以同时操作,所以需要进行同步;信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问。
五种通讯方式总结
管道:速度慢,容量有限,只有父子进程能通讯
FIFO:任何进程间都能通讯,但速度慢
消息队列:容量受到系统限制,且要注意第一次读的时候,要考虑上一次没有读完数据的问题
信号量:不能传递复杂消息,只能用来同步
共享内存区:能够很容易控制容量,速度快,但要保持同步,比如一个进程在写的时候,另一个进程要注意读写的问题,相当于线程中的线程安全,当然,共享内存区同样可以用作线程间通讯,不过没这个必要,线程间本来就已经共享了同一进程内的一块内存
4、java判断可回收的垃圾对象?
1. 引用计数算法
为对象添加一个引用计数器,当对象增加一个引用时计数器加 1,引用失效时计数器减 1。引用计数为 0 的对象可被回收。 在两个对象出现循环引用的情况下,此时引用计数器永远不为 0,导致无法对它们进行回收。正是因为循环引用的存在,因此 Java 虚拟机不使用引用计数算法
2. 可达性分析算法
以 GC Roots 为起始点进行搜索,可达的对象都是存活的,不可达的对象可被回收。
Java 虚拟机使用该算法来判断对象是否可被回收,GC Roots 一般包含以下内容:
-
-
- 虚拟机栈中局部变量表中引用的对象
- 本地方法栈中 JNI 中引用的对象
- 方法区中类静态属性引用的对象
- 方法区中的常量引用的对象
-
5、实现线程同步的方法?
1.同步方法
即有synchronized关键字修饰的方法(所有访问状态变量的方法都必须进行同步),此时充当锁的对象为调用同步方法的对象。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。
2.同步代码块
即有synchronized关键字修饰的语句块。锁的粒度更细,并且充当锁的对象不一定是this,也可以是其它对象,使用起来更加灵活。
3.使用特殊域变量(volatile—不能保证原子性)实现线程同步
(1).volatile关键字为域变量的访问提供了一种免锁机制;
(2).使用volatile修饰域相当于告诉虚拟机该域可能会被其他线程更新;
(3).因此每次使用该域就要重新计算,而不是使用寄存器中的值;
(4).volatile不会提供任何原子操作,它也不能用来修饰final类型的变量;
4.使用重入锁实现线程同步
ReentrantLock类是可重入、互斥、实现了Lock接口的锁,它拥有synchronized相同的并发性和内存语义,此外还多了锁投票,定时锁等候和中断锁等候。
线程A和B都要获取对象O的锁定,假设A获取了对象O锁,B将等待A释放对O的锁定;
如果使用synchronized,如果A不释放,B将一直等下去,不能被中断;
如果使用ReentrantLock,如果A不释放,可以使B在等待了足够长的时间以后,中断等待,而干别的事情
5.使用局部变量实现线程同步
如果使用ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本,副本之间相互独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。
6、双向链表中删除一个节点:假设需要被删除的节点称之为delNode?
p->prior->next=p->next;
p->next->prior->p=p->prior;
7、项目介绍。。。。。blablabla
8、TCP三次握手
假设 A 为客户端,B 为服务器端。
-
-
- 首先 B 处于 LISTEN(监听)状态,等待客户的连接请求。
- A 向 B 发送连接请求报文,SYN=1,ACK=0,选择一个初始的序号 x。
- B 收到连接请求报文,如果同意建立连接,则向 A 发送连接确认报文,SYN=1,ACK=1,确认号为 x+1,同时也选择一个初始的序号 y。
- A 收到 B 的连接确认报文后,还要向 B 发出确认,确认号为 y+1,序号为 x+1。
- B 收到 A 的确认后,连接建立。
-
三次握手的原因
第三次握手是为了防止失效的连接请求到达服务器,让服务器错误打开连接。
客户端发送的连接请求如果在网络中滞留,那么就会隔很长一段时间才能收到服务器端发回的连接确认。客户端等待一个超时重传时间之后,就会重新请求连接。但是这个滞留的连接请求最后还是会到达服务器,如果不进行三次握手,那么服务器就会打开两个连接。如果有第三次握手,客户端会忽略服务器之后发送的对滞留连接请求的连接确认,不进行第三次握手,因此就不会再次打开连接。
9、四次挥手
以下描述不讨论序号和确认号,因为序号和确认号的规则比较简单。并且不讨论 ACK,因为 ACK 在连接建立之后都为 1。
-
-
- A 发送连接释放报文,FIN=1。
- B 收到之后发出确认,此时 TCP 属于半关闭状态,B 能向 A 发送数据但是 A 不能向 B 发送数据。
- 当 B 不再需要连接时,发送连接释放报文,FIN=1。
- A 收到后发出确认,进入 TIME-WAIT 状态,等待 2 MSL(最大报文存活时间)后释放连接。
- B 收到 A 的确认后释放连接。
-
四次挥手的原因
客户端发送了 FIN 连接释放报文之后,服务器收到了这个报文,就进入了 CLOSE-WAIT 状态。这个状态是为了让服务器端发送还未传送完毕的数据,传送完毕之后,服务器会发送 FIN 连接释放报文。
客户端接收到服务器端的 FIN 报文后进入此状态,此时并不是直接进入 CLOSED 状态,还需要等待一个时间计时器设置的时间 2MSL。这么做有两个理由:
-
-
- 确保最后一个确认报文能够到达。如果 B 没收到 A 发送来的确认报文,那么就会重新发送连接释放请求报文,A 等待一段时间就是为了处理这种情况的发生。
- 等待一段时间是为了让本连接持续时间内所产生的所有报文都从网络中消失,使得下一个新的连接不会出现旧的连接请求报文。
-
华为二面
人生理想之类的