華為一面:
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 等待一段時間就是為了處理這種情況的發生。
- 等待一段時間是為了讓本連接持續時間內所產生的所有報文都從網絡中消失,使得下一個新的連接不會出現舊的連接請求報文。
-
華為二面
人生理想之類的