华为一面:java
一、图的表示方式?算法
(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 的邻居表this
{f}, # e 的邻居表spa
{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 的邻居表
二、图的遍历方式?
一般有两种遍历图的方法:深度优先遍历和广度优先遍历。它们对无向图和有向图都适用。图的遍历算法是求解图的连通性问题、拓扑排序和求关键路径等算法的基础。
1) 深度优先遍历: 从图中某个顶点v出发,访问该顶点,而后依次从v的未被访问的邻接点出发继续深度优先遍历图中的其他顶点,直至图中全部与v有路径相通的顶点都被访问完为止;若此时尚有顶点未被访问,则选择一个顶点做为起始点,重复上述过程,直到全部的顶点都被访问。深度优先遍历是一个递归的过程。
2) 广度优先遍历:首先,从图的某个顶点v出发,依次访问与v相邻的未被访问的顶点,而后分别从这些顶点出发,广度优先遍历,直至全部的顶点都被访问完。
如上图中,广度优先遍历获得的序列为:
0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 ->7
三、进程的通讯方式?
进程间通讯(IPC,InterProcess Communication)是指在不一样进程之间传播或交换信息。IPC的方式一般有管道(包括无名管道和命名管道)、消息队列、信号量、共享存储、Socket、Streams等。其中 Socket和Streams支持不一样主机上的两个进程IPC。
以Linux中的C语言编程为例。
1、管道:管道,一般指无名管道,是 UNIX 系统IPC最古老的形式。
特色:它是半双工的(即数据只能在一个方向上流动),具备固定的读端和写端;它只能用于具备亲缘关系的进程之间的通讯(也是父子进程或者兄弟进程之间);它能够当作是一种特殊的文件,对于它的读写也可使用普通的read、write 等函数;可是它不是普通的文件,并不属于其余任何文件系统,而且只存在于内存中。
2、FIFO:也称为命名管道,它是一种文件类型。
特色:FIFO能够在无关的进程之间交换数据,与无名管道不一样;FIFO有路径名与之相关联,它以一种特殊设备文件形式存在于文件系统中。
3、消息队列:是消息的连接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。
特色:消息队列是面向记录的,其中的消息具备特定的格式以及特定的优先级;消息队列独立于发送与接收进程,进程终止时,消息队列及其内容并不会被删除;消息队列能够实现消息的随机查询,消息不必定要以先进先出的次序读取,也能够按消息的类型读取。
4、信号量:信号量(semaphore)与已经介绍过的 IPC 结构不一样,它是一个计数器。信号量用于实现进程间的互斥与同步,而不是用于存储进程间通讯数据。
特色:信号量用于进程间同步,若要在进程间传递数据须要结合共享内存;信号量基于操做系统的 PV 操做,程序对信号量的操做都是原子操做;每次对信号量的 PV 操做不只限于对信号量值加 1 或减 1,并且能够加减任意正整数;支持信号量组。
5、共享内存:共享内存(Shared Memory),指两个或多个进程共享一个给定的存储区。
特色:共享内存是最快的一种 IPC,由于进程是直接对内存进行存取;由于多个进程能够同时操做,因此须要进行同步;信号量+共享内存一般结合在一块儿使用,信号量用来同步对共享内存的访问。
五种通信方式总结
管道:速度慢,容量有限,只有父子进程能通信
FIFO:任何进程间都能通信,但速度慢
消息队列:容量受到系统限制,且要注意第一次读的时候,要考虑上一次没有读完数据的问题
信号量:不能传递复杂消息,只能用来同步
共享内存区:可以很容易控制容量,速度快,但要保持同步,好比一个进程在写的时候,另外一个进程要注意读写的问题,至关于线程中的线程安全,固然,共享内存区一样能够用做线程间通信,不过没这个必要,线程间原本就已经共享了同一进程内的一块内存
4、java判断可回收的垃圾对象?
1. 引用计数算法
为对象添加一个引用计数器,当对象增长一个引用时计数器加 1,引用失效时计数器减 1。引用计数为 0 的对象可被回收。 在两个对象出现循环引用的状况下,此时引用计数器永远不为 0,致使没法对它们进行回收。正是由于循环引用的存在,所以 Java 虚拟机不使用引用计数算法
2. 可达性分析算法
以 GC Roots 为起始点进行搜索,可达的对象都是存活的,不可达的对象可被回收。
Java 虚拟机使用该算法来判断对象是否可被回收,GC Roots 通常包含如下内容:
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 为服务器端。
三次握手的缘由
第三次握手是为了防止失效的链接请求到达服务器,让服务器错误打开链接。
客户端发送的链接请求若是在网络中滞留,那么就会隔很长一段时间才能收到服务器端发回的链接确认。客户端等待一个超时重传时间以后,就会从新请求链接。可是这个滞留的链接请求最后仍是会到达服务器,若是不进行三次握手,那么服务器就会打开两个链接。若是有第三次握手,客户端会忽略服务器以后发送的对滞留链接请求的链接确认,不进行第三次握手,所以就不会再次打开链接。
9、四次挥手
如下描述不讨论序号和确认号,由于序号和确认号的规则比较简单。而且不讨论 ACK,由于 ACK 在链接创建以后都为 1。
四次挥手的缘由
客户端发送了 FIN 链接释放报文以后,服务器收到了这个报文,就进入了 CLOSE-WAIT 状态。这个状态是为了让服务器端发送还未传送完毕的数据,传送完毕以后,服务器会发送 FIN 链接释放报文。
客户端接收到服务器端的 FIN 报文后进入此状态,此时并非直接进入 CLOSED 状态,还须要等待一个时间计时器设置的时间 2MSL。这么作有两个理由:
华为二面
人生理想之类的