1. 程式人生 > >今日頭條C++後臺開發實習面試總結

今日頭條C++後臺開發實習面試總結

一. 旋轉陣列中尋找某個target,leetcode原題。

二. 一個數組建立堆。

堆排序中,最初的步驟就是建立一個堆。之前在一些公司的筆試題上面見到一些與建堆過程相關的題目,因為當時對建堆過程有個誤解,所以經常選錯。之前一直以為是在完全二叉樹中依次插入序列中的元素,每插入一個元素,就呼叫siftup操作;而實際的建堆操作是序列中元素首先就全部填入一個完全二叉樹,然後從第一個非終端節點開始,呼叫siftdown操作,依次調整。

以下是一篇關於建堆過程的文章,轉載自:http://www.cnblogs.com/zabery/archive/2011/07/26/2117103.html

堆排序過程

堆分為大根堆和小根堆,是完全二叉樹

。大根堆的要求是每個節點的值都不大於其父節點的值,即A[PARENT[i]] >= A[i]。在陣列的非降序排序中,需要使用的就是大根堆,因為根據大根堆的要求可知,最大的值一定在堆頂。

既然是堆排序,自然需要先建立一個堆,而建堆的核心內容是調整堆,使二叉樹滿足堆的定義(每個節點的值都不大於其父節點的值)。調堆的過程應該從最後一個非葉子節點開始,假設有陣列A = {1, 3, 4, 5, 7, 2, 6, 8, 0}。那麼調堆的過程如下圖,陣列下標從0開始,A[3] = 5開始。分別與左孩子和右孩子比較大小,如果A[3]最大,則不用調整,否則和孩子中的值最大的一個交換位置,在圖1中是A[7] > A[3] > A[8],所以A[3]與A[7]對換,從圖1.1轉到圖1.2。

http://images.cnblogs.com/cnblogs_com/zabery/201107/201107261321543165.png

以上便是建堆的完整過程,主要總結有以下幾點需要注意:

1.首先將所有元素按照初始順序填充到一個完全二叉樹中

2.從“最後一個非終端節點”開始,呼叫siftdown方法,調整堆的結構,直到根節點為止

三. TCP/IP close_wait狀態和time_wait狀態。

TIME_WAIT 表示主動關閉,CLOSE_WAIT 表示被動關閉。

CLOSE_WAIT狀態的生成原因
首先我們知道,如果我們的伺服器程式APACHE處於CLOSE_WAIT狀態的話,說明套接字是被動關閉的!

因為如果是CLIENT端主動斷掉當前連線的話,那麼雙方關閉這個TCP連線共需要四個packet:

      Client --->  FIN  --->  Server 



      Client <---  ACK  <---  Server 

 這時候Client端處於FIN_WAIT_2狀態;而Server 程式處於CLOSE_WAIT狀態。

      Client <---  FIN  <---  Server 

這時Server 傳送FIN給Client,Server 就置為LAST_ACK狀態。

       Client --->  ACK  --->  Server 

Client迴應了ACK,那麼Server 的套接字才會真正置為CLOSED狀態。

Server 程式處於CLOSE_WAIT狀態,而不是LAST_ACK狀態,說明還沒有發FIN給Client,那麼可能是在關閉連線之前還有許多資料要傳送或者其他事要做,導致沒有發這個FIN packet。

客戶端主動關閉時,發出FIN包,收到伺服器的ACK,客戶端停留在FIN_WAIT2狀態。而服務端收到FIN,發出ACK後,停留在COLSE_WAIT狀態。     這個CLOSE_WAIT狀態非常討厭,它持續的時間非常長,伺服器端如果積攢大量的COLSE_WAIT狀態的socket,有可能將伺服器資源(套接字描述符耗盡)耗盡,進而無法提供服務。     那麼,伺服器上是怎麼產生大量的失去控制的COLSE_WAIT狀態的socket呢?我們來追蹤一下。     一個很淺顯的原因是,伺服器沒有繼續發FIN包給客戶端。     伺服器為什麼不發FIN,可能是業務實現上的需要,現在不是傳送FIN的時機,因為伺服器還有資料要發往客戶端,傳送完了自然就要通過系統呼叫發FIN了,這個場景並不是上面我們提到的持續的COLSE_WAIT狀態,這個在受控範圍之內。     那麼究竟是什麼原因呢,咱們引入兩個系統呼叫close(sockfd)和shutdown(sockfd,how)接著往下分析。     在這兒,需要明確的一個概念---- 一個程序開啟一個socket,然後此程序再派生子程序的時候,此socket的sockfd會被繼承。socket是系統級的物件,現在的結果是,此socket被兩個程序開啟,此socket的引用計數會變成2。     繼續說上述兩個系統呼叫對socket的關閉情況。     呼叫close(sockfd)時,核心檢查此fd對應的socket上的引用計數。如果引用計數大於1,那麼將這個引用計數減1,然後返回。如果引用計數等於1,那麼核心會真正通過發FIN來關閉TCP連線。     呼叫shutdown(sockfd,SHUT_RDWR)時,核心不會檢查此fd對應的socket上的引用計數,直接通過發FIN來關閉TCP連線。      現在應該真相大白了,可能是伺服器的實現有點問題,父程序打開了socket,然後用派生子程序來處理業務,父程序繼續對網路請求進行監聽,永遠不會終止。客戶端發FIN過來的時候,處理業務的子程序的read返回0,子程序發現對端已經關閉了,直接呼叫close()對本端進行關閉。實際上,僅僅使socket的引用計數減1,socket並沒關閉。從而導致系統中又多了一個CLOSE_WAIT的socket。。。 如何避免這樣的情況發生? 子程序的關閉處理應該是這樣的: shutdown(sockfd, SHUT_RDWR); close(sockfd); 這樣處理,伺服器的FIN會被髮出,socket進入LAST_ACK狀態,等待最後的ACK到來,就能進入初始狀態CLOSED。

四. nginx的程序模型。

五. redis的記憶體分配。

六.MySQL  引擎 Innodb 聚簇索引與非聚簇索引,B+樹與B樹的區別。