c++筆試題 已遷移完成

轉載css

一、C和C++的特色與區別?html

答:(1)C語言特色:
1.做爲一種面向過程的結構化語言,易於調試和維護;c++

2.表現能力和處理能力極強,能夠直接訪問內存的物理地址;程序員

3.C語言實現了對硬件的編程操做,也適合於應用軟件的開發;算法

4.C語言還具備效率高,可移植性強等特色。數據庫

(2)C++語言特色:編程

1.在C語言的基礎上進行擴充和完善,使C++兼容了C語言的面向過程特色,又成爲了一種面向對象的程序設計語言;數組

2.可使用抽象數據類型進行基於對象的編程;瀏覽器

3.可使用多繼承、多態進行面向對象的編程;安全

4.能夠擔負起以模版爲特徵的泛型化編程。

C++與C語言的本質差異:在於C++是面向對象的,而C語言是面向過程的。或者說C++是在C語言的基礎上增長了面向對象程序設

計的新內容,是對C語言的一次更重要的改革,使得C++成爲軟件開發的重要工具。

 

二、C++的多態

答:C++的多態性用一句話歸納:在基類的函數前加上virtual關鍵字,在派生類中重寫該函數,運行時將會根據對象的實際類型來

調用相應的函數。若是對象類型是派生類,就調用派生類的函數;若是對象類型是基類,就調用基類的函數。

1):用virtual關鍵字申明的函數叫作虛函數,虛函數確定是類的成員函數; 

2):存在虛函數的類都有一個一維的虛函數表叫作虛表,類的對象有一個指向虛表開始的虛指針。虛表是和類對應的,虛表指針是

和對象對應的;

3):多態性是一個接口多種實現,是面向對象的核心,分爲類的多態性和函數的多態性。;

4):多態用虛函數來實現,結合動態綁定.;

5):純虛函數是虛函數再加上 = 0;

6):抽象類是指包括至少一個純虛函數的類;

純虛函數:virtual void fun()=0;即抽象類,必須在子類實現這個函數,即先有名稱,沒有內容,在派生類實現內容。

 

三、虛函數實現

答:簡單地說,每個含有虛函數(不管是其自己的,仍是繼承而來的)的類都至少有一個與之對應的虛函數表,其中存放着該類

全部的虛函數對應的函數指針。例:

 

其中:

B的虛函數表中存放着B::foo和B::bar兩個函數指針。

D的虛函數表中存放的既有繼承自B的虛函數B::foo,又有重寫(override)了基類虛函數B::bar的D::bar,還有新增的虛函數D::quz。

 

虛函數表構造過程:

從編譯器的角度來講,B的虛函數表很好構造,D的虛函數表構造過程相對複雜。下面給出了構造D的虛函數表的一種方式(僅供參考):

 

虛函數調用過程

如下面的程序爲例:

 

 

四、C和C++內存分配問題

答:(1)C語言編程中的內存基本構成

C的內存基本上分爲4部分:靜態存儲區、堆區、棧區以及常量區。他們的功能不一樣,對他們使用方式也就不一樣。

1.棧 ——由編譯器自動分配釋放;

2.堆 ——通常由程序員分配釋放,若程序員不釋放,程序結束時可能由OS回收;

3.全局區(靜態區)——全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量在一塊區域,未初始化的全局變量

和未初始化的靜態變量在相鄰的另外一塊區域(C++中已經再也不這樣劃分),程序結束釋放;

4.另外還有一個專門放常量的地方,程序結束釋放;

(a)函數體中定義的變量一般是在棧上;

(b)用malloc, calloc, realloc等分配內存的函數分配獲得的就是在堆上;

(c)在全部函數體外定義的是全局量;

(d)加了static修飾符後無論在哪裏都存放在全局區(靜態區);

(e)在全部函數體外定義的static變量表示在該文件中有效,不能extern到別的文件用;

(f)在函數體內定義的static表示只在該函數體內有效;

(g)另外,函數中的"adgfdf"這樣的字符串存放在常量區。

 

(2)C++編程中的內存基本構造

在C++中內存分紅5個區,分別是堆、棧、全局/靜態存儲區、常量存儲區和代碼區;

一、棧,就是那些由編譯器在須要的時候分配,在不須要的時候自動清楚的變量的存儲區,裏面的變量一般是局部變量、函數參數等。

二、堆,就是那些由new分配的內存塊,他們的釋放編譯器不去管,由咱們的應用程序去控制,通常一個new就要對應一個delete。如

果程序員沒有釋放掉,那麼在程序結束後,操做系統會自動回收。

三、全局/靜態存儲區,全局變量和靜態變量被分配到同一塊內存中,在之前的C語言中,全局變量又分爲初始化的和未初始化的,在

C++裏面沒有這個區分了,他們共同佔用同一塊內存區。

四、常量存儲區,這是一塊比較特殊的存儲區,他們裏面存放的是常量,不容許修改(固然,你要經過非正當手段也能夠修改)。

五、代碼區 (.text段),存放代碼(如函數),不容許修改(相似常量存儲區),但能夠執行(不一樣於常量存儲區)。

 

內存模型組成部分:自由存儲區,動態區、靜態區;

根據c/c++對象生命週期不一樣,c/c++的內存模型有三種不一樣的內存區域,即:自由存儲區,動態區、靜態區。

自由存儲區:局部非靜態變量的存儲區域,即日常所說的棧;

動態區: 用new ,malloc分配的內存,即日常所說的堆;

靜態區:全局變量,靜態變量,字符串常量存在的位置;

注:代碼雖然佔內存,但不屬於c/c++內存模型的一部分;

 

一個正在運行着的C編譯程序佔用的內存分爲5個部分:代碼區、初始化數據區、未初始化數據區、堆區 和棧區;

(1)代碼區(text segment):代碼區指令根據程序設計流程依次執行,對於順序指令,則只會執行一次(每一個進程),若是反覆,則須要使用跳轉指令,若是進行遞歸,則須要藉助棧來實現。注意:代碼區的指令中包括操做碼和要操做的對象(或對象地址引用)。若是是當即數(即具體的數值,如5),將直接包含在代碼中;


(2)全局初始化數據區/靜態數據區(Data Segment):只初始化一次。

(3)未初始化數據區(BSS):在運行時改變其值。

(4)棧區(stack):由編譯器自動分配釋放,存放函數的參數值、局部變量的值等,其操做方式相似於數據結構中的棧。

(5)堆區(heap):用於動態內存分配。

 

爲何分紅這麼多個區域?

主要基於如下考慮:

#代碼是根據流程依次執行的,通常只須要訪問一次,而數據通常都須要訪問屢次,所以單獨開闢空間以方便訪問和節約空間。
#未初始化數據區在運行時放入棧區中,生命週期短。
#全局數據和靜態數據有可能在整個程序執行過程當中都須要訪問,所以單獨存儲管理。
#堆區由用戶自由分配,以便管理。

 

更多內容見:http://www.cnblogs.com/Stultz-Lee/p/6751522.html

 

五、協程

答:定義:協程是一種用戶態的輕量級線程。

協程擁有本身的寄存器上下文和棧。協程調度切換時,將寄存器上下文和棧保存到其餘地方,在切回來的時候,恢復先前保存的寄存器上下文和棧。所以:協程能保留上一次調用時的狀態(即全部局部狀態的一個特定組合),每次過程重入時,就至關於進入上一次調用的狀態,換種說法:進入上一次離開時所處邏輯流的位置;

線程是搶佔式,而協程是協做式;

協程的優勢:

跨平臺
跨體系架構
無需線程上下文切換的開銷
無需原子操做鎖定及同步的開銷
方便切換控制流,簡化編程模型
高併發+高擴展性+低成本:一個CPU支持上萬的協程都不是問題。因此很適合用於高併發處理。

協程的缺點:

沒法利用多核資源:協程的本質是個單線程,它不能同時將 單個CPU 的多個核用上,協程須要和進程配合才能運行在多CPU;
進行阻塞(Blocking)操做(如IO時)會阻塞掉整個程序:這一點和事件驅動同樣,可使用異步IO操做來解決。

 

六、CGI的瞭解

答:CGI:通用網關接口(Common Gateway Interface)是一個Web服務器主機提供信息服務的標準接口。經過CGI接口,Web服務

器就可以獲取客戶端提交的信息,轉交給服務器端的CGI程序進行處理,最後返回結果給客戶端。

CGI通訊系統的組成是兩部分:一部分是html頁面,就是在用戶端瀏覽器上顯示的頁面。另外一部分則是運行在服務器上的Cgi程序。

 

七、進程間通訊方式和線程間通訊方式

答:(1)進程間通訊方式:

# 管道( pipe ):管道是一種半雙工的通訊方式,數據只能單向流動,並且只能在具備親緣關係的進程間使用。進程的親緣關係一般是指父子進程關係。

# 信號量( semophore ) : 信號量是一個計數器,能夠用來控制多個進程對共享資源的訪問。它常做爲一種鎖機制,防止某進程正在訪問共享資源時,其餘進程也訪問該資源。所以,主要做爲進程間以及同一進程內不一樣線程之間的同步手段。


# 消息隊列( message queue ) : 消息隊列是由消息的鏈表,存放在內核中並由消息隊列標識符標識。消息隊列克服了信號傳遞信息少、管道只能承載無格式字節流以及緩衝區大小受限等缺點。

# 共享內存( shared memory ) :共享內存就是映射一段能被其餘進程所訪問的內存,這段共享內存由一個進程建立,但多個進程均可以訪問。共享內存是最快的 IPC 方式,它是針對其餘進程間通訊方式運行效率低而專門設計的。它每每與其餘通訊機制,如信號兩,配合使用,來實現進程間的同步和通訊。


# 套接字( socket ) : 套解口也是一種進程間通訊機制,與其餘通訊機制不一樣的是,它可用於不一樣及其間的進程通訊。

 

(2)線程間通訊方式:

#全局變量;

#Messages消息機制;

#CEvent對象(MFC中的一種線程通訊對象,經過其觸發狀態的改變實現同步與通訊)。

 

八、TCP握手與釋放

答:(1)握手

#第一次握手:主機A發送握手信號syn=1和seq=x(隨機產生的序列號)的數據包到服務器,主機B由SYN=1知道,A要求創建聯機;
#第二次握手:主機B收到請求後要確認聯機信息,向A發送syn=1,ack=x(x是主機A的Seq)+1,以及隨機產生的確認端序列號

seq=y的包;

#第三次握手:主機A收到後檢查ack是否正確(ack=x+1),即第一次發送的seq+1,若正確,主機A會再發送ack=y+1,以及隨機序

列號seq=z,主機B收到後確認ack值則鏈接創建成功;

#完成三次握手,主機A與主機B開始傳送數據。

 

注:上述步驟中,第二和第三次確認包中都還包含一個標誌位未予以說明,該標誌位爲1表示正常應答;

 

具體可見圖片:

 

 

爲何須要「三次握手」?

「三次握手」的目的是「爲了防止已失效的鏈接請求報文段忽然又傳送到了服務端,於是產生錯誤」。具體例如:client發出的第一個鏈接請求報文段並無丟失,而是在某個網絡結點長時間的滯留了,以至延誤到鏈接釋放之後的某個時間纔到達server。原本這是一個早已失效的報文段。但server收到此失效的鏈接請求報文段後,就誤認爲是client再次發出的一個新的鏈接請求。因而就向client發出確認報文段,贊成創建鏈接。假設不採用「三次握手」,那麼只要server發出確認,新的鏈接就創建了。因爲如今client並無發出創建鏈接的請求,所以不會理睬server的確認,也不會向server發送數據。但server卻覺得新的運輸鏈接已經創建,並一直等待client發來數據。這樣,server的不少資源就白白浪費掉了。採用「三次握手」的辦法能夠防止上述現象發生。例如剛纔那種狀況,client不會向server的確認發出確認。server因爲收不到確認,就知道client並無要求創建鏈接。主要目的防止server端一直等待,浪費資源。

 

(2)揮手

  因爲TCP鏈接是全雙工的,所以每一個方向都必須單獨進行關閉。這原則是當一方完成它的數據發送任務後就能發送一個FIN來終止這個方向的鏈接。收到一個 FIN只意味着這一方向上沒有數據流動,一個TCP鏈接在收到一個FIN後仍能發送數據。首先進行關閉的一方將執行主動關閉,而另外一方執行被動關閉。
  (1) TCP客戶端發送一個FIN,用來關閉客戶到服務器的數據傳送(報文段4);
  (2) 服務器收到這個FIN,發回一個ACK,確認序號爲收到的序號加1(報文段5)。和SYN同樣,一個FIN將佔用一個序號;
  (3) 服務器關閉客戶端的鏈接後,再發送一個FIN給客戶端(報文段6);
  (4) 客戶段收到服務端的FIN後,發回ACK報文確認,並將確認序號設置爲收到序號加1(報文段7);

注意:TCP鏈接的任何一方均可以發起揮手操做,上述步驟只是兩種之一;

具體過程見圖:

 

爲何是「四次揮手」?
由於當收到對方的FIN報文通知時,它僅僅表示對方沒有數據發送給你了;但未必你全部的數據都所有發送給對方了,因此你可能還須要發送一些數據給對方,再發送FIN報文給對方來表示你贊成如今能夠關閉鏈接了,故這裏的ACK報文和FIN報文多數狀況下都是分開發送的,也就形成了4次揮手。

 

握手,揮手過程當中各狀態介紹:
(1)3次握手過程狀態:
  #LISTEN: 這個也是很是容易理解的一個狀態,表示服務器端的某個SOCKET處於監聽狀態,能夠接受鏈接了。

#SYN_SENT: 當客戶端SOCKET執行CONNECT鏈接時,它首先發送SYN報文,所以也隨即它會進入到了SYN_SENT狀態,並等待服務端的發送三次握手中的第2個報文。SYN_SENT狀態表示客戶端已發送SYN報文。(發送端)

  #SYN_RCVD: 這個狀態與SYN_SENT遙想呼應這個狀態表示接受到了SYN報文,在正常狀況下,這個狀態是服務器端的SOCKET在創建TCP鏈接時的三次握手會話過程當中的一箇中間狀態,很短暫,基本上用netstat你是很難看到這種狀態的,除非你特地寫了一個客戶端測試程序,故意將三次TCP握手過程當中最後一個ACK報文不予發送。所以這種狀態時,當收到客戶端的ACK報文後,它會進入到ESTABLISHED狀態。(服務器端)

#ESTABLISHED:這個容易理解了,表示鏈接已經創建了。

(2)4次揮手過程狀態:
  #FIN_WAIT_1: 這個狀態要好好解釋一下,其實FIN_WAIT_1和FIN_WAIT_2狀態的真正含義都是表示等待對方的FIN報文。而這兩種狀態的區別是:FIN_WAIT_1狀態其實是當SOCKET在ESTABLISHED狀態時,它想主動關閉鏈接,向對方發送了FIN報文,此時該SOCKET即進入到FIN_WAIT_1狀態。而當對方迴應ACK報文後,則進入到FIN_WAIT_2狀態,固然在實際的正常狀況下,不管對方何種狀況下,都應該立刻迴應ACK報文,因此FIN_WAIT_1狀態通常是比較難見到的,而FIN_WAIT_2狀態還有時經常能夠用netstat看到。(主動方)

#FIN_WAIT_2:上面已經詳細解釋了這種狀態,實際上FIN_WAIT_2狀態下的SOCKET,表示半鏈接,也即有一方要求close鏈接,但另外還告訴對方,我暫時還有點數據須要傳送給你(ACK信息),稍後再關閉鏈接。(主動方)

  #TIME_WAIT: 表示收到了對方的FIN報文,併發送出了ACK報文,就等2MSL後便可回到CLOSED可用狀態了。若是FIN_WAIT_1狀態下,收到了對方同時帶FIN標誌和ACK標誌的報文時,能夠直接進入到TIME_WAIT狀態,而無須通過FIN_WAIT_2狀態。(主動方)

#CLOSING(比較少見): 這種狀態比較特殊,實際狀況中應該是不多見,屬於一種比較罕見的例外狀態。正常狀況下,當你發送FIN報文後,按理來講是應該先收到(或同時收到)對方的ACK報文,再收到對方的FIN報文。可是CLOSING狀態表示你發送FIN報文後,並無收到對方的ACK報文,反而卻也收到了對方的FIN報文。什麼狀況下會出現此種狀況呢?其實細想一下,也不可貴出結論:那就是若是雙方几乎在同時close一個SOCKET的話,那麼就出現了雙方同時發送FIN報文的狀況,也即會出現CLOSING狀態,表示雙方都正在關閉SOCKET鏈接。

  #CLOSE_WAIT: 這種狀態的含義實際上是表示在等待關閉。怎麼理解呢?當對方close一個SOCKET後發送FIN報文給本身,你係統毫無疑問地會迴應一個ACK報文給對方,此時則進入到CLOSE_WAIT狀態。接下來呢,實際上你真正須要考慮的事情是察看你是否還有數據發送給對方,若是沒有的話,那麼你也就能夠close這個SOCKET,發送FIN報文給對方,也即關閉鏈接。因此你在CLOSE_WAIT狀態下,須要完成的事情是等待你去關閉鏈接。(被動方)

#LAST_ACK: 這個狀態仍是比較容易好理解的,它是被動關閉一方在發送FIN報文後,最後等待對方的ACK報文。當收到ACK報文後,也便可以進入到CLOSED可用狀態了。(被動方)

 

九、http和https的區別?

答:HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,要比http協議安全。

HTTPS(Secure Hypertext Transfer Protocol)安全超文本傳輸協議,與http主要區別在於:

#http是超文本傳輸協議,信息是明文傳輸,https 則是具備安全性的ssl加密傳輸協議;

#http和https使用的是徹底不一樣的鏈接方式用的端口也不同,前者是80,後者是443;

 

下面具體介紹一下HTTP和HTTPS協議:

首先說明一下:HTTP和HTTPS協議是應用層協議;

 

上圖充分代表:HTTP是應用層協議,而且HTTPS是在HTTP協議基礎上添加SSL等加密策略後的協議;

TLS/SSL中使用了非對稱加密,對稱加密以及HASH算法。

 

(1)Http協議

1)HTTP協議和TCP協議之間的區別聯繫

①TPC/IP協議是傳輸層協議,主要解決數據如何在網絡中傳輸,而HTTP是應用層協議,主要解決如何包裝數據;

②HTTP的默認端口號是80,TCP/IP協議通訊編程時端口號須要本身指定(例如socket編程);

③HTTP協議是在TCP/IP協議基礎上實現的,即HTTP數據包是通過TCP/IP協議實現傳輸的;

④HTTP是無狀態的短鏈接協議,TCP是有狀態的長鏈接協議;

 

HTTP是在有狀態長鏈接TCP/IP協議的基礎上實現的,爲何倒是無狀態短鏈接協議?

答:由於HTTP協議每次請求結束就會自動關閉鏈接,這樣就變成了短鏈接;

短鏈接又致使了該次請求相關信息的丟失,也就形成了HTTP協議對於前期事務處理沒有記憶能力,故爲無狀態協議。

 

2)HTTP協議其完整的工做過程可分爲四步:

①鏈接:首先客戶機與服務器須要創建鏈接(由TCP/IP握手鍊接實現)。只要單擊某個超級連接,HTTP的工做開始;

②請求:創建鏈接後,客戶機發送一個請求給服務器,請求方式的格式爲:統一資源標識符(URL)、協議版本號,後邊是MIME信息包括請求修飾符、客戶機信息和可能的內容;

③應答:服務器接到請求後,給予相應的響應信息,其格式爲一個狀態行,包括信息的協議版本號、一個成功或錯誤的代碼,後邊是MIME信息包括服務器信息、實體信息和可能的內容。客戶端接收服務器所返回的信息經過瀏覽器顯示在用戶的顯示屏上;

④關閉:當應答結束後,瀏覽器和服務器關閉鏈接,以保證其餘瀏覽器能夠與服務器進行鏈接。

 

更完整的過程可能以下:

域名解析 --> 發起TCP的3次握手 --> 創建TCP鏈接後發起http請求 --> 服務器響應http請求,瀏覽器獲得html代碼 --> 瀏覽器解析html代碼,並請求html代碼中的資源(如js、css、圖片等) --> 瀏覽器對頁面進行渲染呈現給用戶。

       若是在以上過程當中的某一步出現錯誤,那麼產生錯誤的信息將返回到客戶端,有顯示屏輸出。對於用戶來講,這些過程是由HTTP本身完成的,用戶只要用鼠標點擊,等待信息顯示就能夠了。

 

(2)Https協議

HTTPS握手過程包括五步:

1)瀏覽器請求鏈接;

2)服務器返回證書:證書裏面包含了網站地址,加密公鑰,以及證書的頒發機構等信息。

3)瀏覽器收到證書後做如下工做:

    a) 驗證證書的合法性;

    b) 生成隨機(對稱)密碼,取出證書中提供的公鑰對隨機密碼加密;

    c) 將以前生成的加密隨機密碼等信息發送給網站;

4)服務器收到消息後做如下的操做:

    a) 使用本身的私鑰解密瀏覽器用公鑰加密後的消息,並驗證HASH是否與瀏覽器發來的一致;

    b) 使用加密的隨機對稱密碼加密一段消息,發送給瀏覽器;

5)瀏覽器解密並計算握手消息的HASH:若是與服務端發來的HASH一致,此時握手過程結束,以後全部的通訊數據將由以前瀏覽

器生成的隨機密碼並利用對稱加密算法進行加密。

 

注意:服務器有兩個密鑰,一個公鑰、一個私鑰,只有私鑰才能夠解密公鑰加密的消息;

 

如圖:

 

或者以下圖:

 

 

HTTPS協議、SSL、和數字證書的關係介紹:

概述:對於HTTPS協議,全部的消息都是通過SSL協議方式加密,而支持加密的文件正是數字證書;

(1)SSL

SSL經常使用的加密算法:對稱密碼算法、非對稱密碼算法、散列算法;

SSL的加密過程:須要注意的是非對稱加解密算法的效率要比對稱加解密要低的多。因此SSL在握手過程當中使用非對稱密碼算法來

協商密鑰,實際使用對稱加解密的方法對http內容加密傳輸;

(2)數字證書

數字證書是用於在INTERNET上標識我的或者機構身份的一種技術手段,它經過由一些公認的權威機構所認證,從而能夠保證其

安全地被應用在各類場合。證書裏面包含了網站地址,加密公鑰,以及證書的頒發機構等信息。

 

 

十、虛擬內存的概念與介紹

答:虛擬內存中,容許將一個做業分屢次調入內存,須要時就調入,不須要的就先放在外存。所以,虛擬內存的實須要創建在離散

分配的內存管理方式的基礎上。虛擬內存的實現有如下三種方式:
#請求分頁存儲管理
#請求分段存儲管理
#請求段頁式存儲管理

 

虛擬內存的意義:

一,虛擬內存可使得物理內存更加高效。虛擬內存使用置換方式,須要的頁就置換進來,不須要的置換出去,使得內存中只保存了須要的頁,提升了利用率,也避免了沒必要要的寫入與擦除;


二,使用虛擬地址可使內存的管理更加便捷。在程序編譯的時候就會生成虛擬地址,該虛擬地址並非對應一個物理地址,使得也就極大地減小了地址被佔用的衝突,減小管理難度;


三,爲了安全性的考慮。在使用虛擬地址的時候,暴露給程序員永遠都是虛擬地址,而具體的物理地址在哪裏,這個只有系統才瞭解。這樣就提

高了系統的封裝性。

 

十一、單鏈表的反轉算法

答:思想:建立3個指針,分別指向上一個節點、當前節點、下一個節點,遍歷整個鏈表的同時,將正在訪問的節點指向上一個節點,當遍歷結束後,就同時完成了鏈表的反轉。

實現代碼:

 ListNode* ReverseList(ListNode* pHead) {
        ListNode *p,*q,*r;
        if(pHead==NULL || pHead->next==NULL){
            return pHead;
        }else{
            p=pHead;
            q=p->next;
            pHead->next=NULL;
            while(q!=NULL){
                r=q->next;
                q->next=p;
                p=q;
                q=r;
            }
            return p;
        }
    }
--------------------- 

 

十二、紅黑樹以及其查找複雜度

答:(1)紅黑樹來源於二叉搜索樹,其在關聯容器如map中應用普遍,主要優點在於其查找、刪除、插入時間複雜度小,但其也有缺點,就是容易偏向一邊而變成一個鏈表。

紅黑樹是一種二叉查找樹,但在每一個結點上增長一個存儲位表示結點的顏色,能夠是Red或Black。也就是說,紅黑樹是在二叉

查找樹基礎上進一步實現的;

紅黑樹的五個性質:

性質1. 節點是紅色或黑色;

性質2. 根節點是黑色;

性質3 每一個葉節點(指樹的末端的NIL指針節點或者空節點)是黑色的;

性質4 每一個紅色節點的兩個子節點都是黑色。(從每一個葉子到根的全部路徑上不能有兩個連續的紅色節點);

性質5. 從任一節點到其每一個尾端NIL節點或者NULL節點的全部路徑都包含相同數目的黑色節點。

(注:上述第三、5點性質中所說的NIL或者NULL結點,並不包含數據,只充當樹的路徑結束的標誌,即此葉結點很是見的葉子結點)。

 

由於一棵由n個結點隨機構造的二叉查找樹的高度爲lgn,因此瓜熟蒂落,二叉查找樹的通常操做的執行時間爲O(lgn)。但二叉查

找樹若退化成了一棵具備n個結點的線性鏈後,則這些操做最壞狀況運行時間爲O(n);

紅黑樹雖然本質上是一棵二叉查找樹,但它在二叉查找樹的基礎上增長以上五個性質使得紅黑樹相對平衡,從而保證了

紅黑樹的查找、插入、刪除的時間複雜度最壞爲O(log n)。

 

(2)左旋右旋

紅黑樹插入或刪除後,通常就會改變紅黑樹的特性,要恢復紅黑樹上述5個性質,通常都要那就要作2方面的工做:

一、部分結點顏色,從新着色
二、調整部分指針的指向,即左旋、右旋。

左選右旋如圖所示:

 

左旋,如圖所示(左->右),以x->y之間的鏈爲「支軸」進行,使y成爲該新子樹的根,x成爲y的左孩子,而y的左孩子則成爲x的右孩

子。算法很簡單,旋轉後各個結點從左往右,仍然都是從小到大。

左旋代碼實現,分三步:
(1) 開始變化,y的左孩子成爲x的右孩子;
(2) y成爲x的父結點;
(3) x成爲y的左孩子;

右旋相似,再也不累述;

 

1三、KPM字符串匹配

(1)KMP匹配算法代碼實現:

int KmpSearch(char* s, char* p)  
{  
    int i = 0;  
    int j = 0;  
    int sLen = strlen(s);  
    int pLen = strlen(p);  
    while (i < sLen && j < pLen)  
    {  
        //①若是j = -1,或者當前字符匹配成功(即S[i] == P[j]),都令i++,j++      
        if (j == -1 || s[i] == p[j])  
        {  
            i++;  
            j++;  
        }  
        else  
        {  
            //②若是j != -1,且當前字符匹配失敗(即S[i] != P[j]),則令 i 不變,j = next[j]      
            //next[j]即爲j所對應的next值        
            j = next[j];  
        }  
    }  
    if (j == pLen)  
        return i - j;  
    else  
        return -1;  
}
--------------------- 
做者:空山明月_Blog 
來源:CSDN 
原文:https://blog.csdn.net/xiongchao99/article/details/73381280 
版權聲明:本文爲博主原創文章,轉載請附上博文連接!

 

(2)next數組求取
上述(1)中最重要的就是:一旦不匹配,模式串不是向後移動一位,而是根據前面匹配信息移動多位。而這個多位得到就是根據next數組,下面有next數組的求取方式:
Next數組是根據模式串的前綴後綴獲取的,以下:
①尋找前綴後綴最長公共元素長度
舉個例子,若是給定的模式串爲「abab」,那麼它的各個子串的前綴後綴的公共元素的最大長度以下表格所示:

好比對於字符串aba來講,它有長度爲1的相同前綴後綴a;而對於字符串abab來講,它有長度爲2的相同前綴後綴ab(相同前綴後綴的長度爲k + 1,k + 1 = 2)。


②求next數組
next 數組考慮的是除當前字符外的最長相同前綴後綴,因此經過第①步驟求得各個前綴後綴的公共元素的最大長度後,只要稍做變形便可:將第①步驟中求得的數組總體右移一位,而後第一個元素賦爲-1便可(注意:字符串下標須要從0開始),以下表格所示:

 

好比對於aba來講,第3個字符a以前的字符串ab中有長度爲0的相同前綴後綴,因此第3個字符a對應的next值爲0;而對於abab來講,第4個字符b以前的字符串aba中有長度爲1的相同前綴後綴a,因此第4個字符b對應的next值爲1(相同前綴後綴的長度爲k,k = 1)。

KMP的next 數組至關於告訴咱們:當模式串中的某個字符跟文本串中的某個字符匹配失配時,模式串下一步應該跳到哪一個位置(具體:保持測試串的下標i不變,使得匹配串的下標j=next[j])。

 

前綴後綴長度求取以及next數組獲取:

若是給定的模式串是:「ABCDABD」,從左至右遍歷整個模式串,其各個子串的前綴後綴分別以下表格所示: 


也就是說,原模式串子串對應的各個前綴後綴的公共元素的最大長度表爲:

0 0 0 0 1 2 0;

故對應的next數組爲:-1 0 0 0 0 1 2;

(注意:這裏的字符串下標是從0開始的,若從1開始,next數組全部元素都對應要加1。)

 

求取next的實現代碼:

string T;  //T爲模式串
		cin>>T;
		int len=T.size();
		queue<int> MaxLen;
		vector<int> next;
		MaxLen.push(0);  //第一個元素都設爲0
		for(int i=1;i<len;i++)
		{
			int k=1,maxLen=0;
			while(k<=i)
			{
				if(T.substr(0,k)==T.substr(i-k+1,k))
				{
					maxLen=k;
				}
				k++;
			}
			MaxLen.push(maxLen);
		}
		cout<<endl;
 
		next.push_back(-1); //第一個元素都設爲-1
		while(MaxLen.size()>1)
		{
			int temp=MaxLen.front();
			next.push_back(temp);
			MaxLen.pop();
			cout<<temp<<' ';
		}
--------------------- 
做者:空山明月_Blog 
來源:CSDN 
原文:https://blog.csdn.net/xiongchao99/article/details/73381280 
版權聲明:本文爲博主原創文章,轉載請附上博文連接!

 

1四、TCP超時等待、重傳以及流量控制

答:TCP等待時間須要設定,超過了就認爲丟包,須要重傳;

爲了防止擁塞狀況,通常會採用流量控制,其實現手段是用滑動窗口限制客戶端發送分組數量;

 

1五、數據庫引擎

答:數據庫引擎是用於存儲、處理和保護數據的核心服務。利用數據庫引擎可控制訪問權限並快速處理事務,從而知足企業內大多

數須要處理大量數據的應用程序的要求。

簡言之,數據庫引擎就是一段用於支撐全部數據庫操做的核心程序,就如名稱同樣,是一個車的引擎功能;

 

常見的數據庫引擎有:

(1)Microsoft JET (Joint Engineering Technologe) 用於Access和VB的內嵌數據庫功能的核心元素;

(2)ODBC(Open DataBase Connectivity,開放數據庫互連)是由Microsoft定義的一種數據庫訪問標準,它提供一種標準的數據

庫訪問方法以訪問不一樣平臺的數據庫。一個ODBC應用程序既能夠訪問在本地PC機上的數據庫,也能夠訪問多種異構平臺上的數據

庫,例如SQL Server、Oracle或者DB2;

(3)OLE DB是Microsoft開發的最新數據庫訪問接口,Microsoft將其定義爲ODBC接班人;

(4)MYSQL支持三個引擎:ISAM、MYISAM和HEAP。另外兩種類型INNODB和BERKLEY(BDB)也經常可使用;

①ISAM執行讀取操做的速度很快,並且不佔用大量的內存和存儲資源。ISAM的兩個主要不足之處在於,它不 支持事務處理,也不可以容錯;

②MyISAM是MySQL的ISAM擴展格式和缺省的數據庫引擎MYISAM。除了提供ISAM裏所沒有的索引和字段管理的大量功能,

MyISAM還使用一種表格鎖定的機制,來優化多個併發的讀寫操做,其代價是你須要常常運行OPTIMIZE TABLE命令,來恢復被更新

機制所浪費的空間;

③HEAP容許只駐留在內存裏的臨時表格。駐留在內存裏讓HEAP要比ISAM和MYISAM都快,可是它所管理的數據是不穩定的,

並且若是在關機以前沒有進行保存,那麼全部的數據都會丟失。

 

 

1六、數據庫索引

答:定義:數據庫索引是對數據庫表中一列或多列的值進行排序的一種結構,使用索引可快速訪問數據庫表中的特定信息;

舉例:employee 表的人員編號列(id)就是數據庫索引,select * from employee where id=10000便可查找編號10000的人員信息。若是沒有索引,必須遍歷整個表直到id=10000;

數據庫索引做用:

一,大大加快 數據的檢索速度,這也是建立索引的最主要的緣由;
二,保證數據庫表中每一行數據的惟一性;
三,能夠加速表和表之間的鏈接,特別是在實現數據的參考完整性方面特別有意義; 
四,在使用分組和排序子句進行數據檢索時,一樣能夠顯著減小查詢中分組和排序的時間; 
五,經過使用索引,能夠在查詢的過程當中,使用優化隱藏器,提升系統的性能。

 

數據庫索引缺陷:

一,表的增刪改查、建立索引和維護索引要耗費時間;
二,索引須要佔物理空間;

 

數據庫索引的兩個特徵:索引有兩個特徵,即惟一性索引和複合索引;

①惟一 性索引保證在索引列中的所有數據是惟一的,不會包含冗餘數據;

②複合索引就是一個索引建立在兩個列或者多個列上,搜索時須要兩個或者多個索引列做爲一個關鍵值;

 

數據庫索引比如是一本書前面的目錄,索引分爲聚簇索引和非聚簇索引兩類:

1)聚簇索引是按照數據存放的物理位置爲順序的,其多個連續行的訪問速度更快;

2)非聚簇索引是按照數據存放的邏輯位置爲順序的,其單行訪問速度更快;

 

局部性原理與磁盤預讀

局部性原理:當一個數據被用到時,其附近的數據也一般會立刻被使用。程序運行期間所須要的數據一般比較集中;

磁盤預讀:正是因爲局部性原理以及數據存儲磁盤的讀寫速度慢的緣由,每次對數據庫進行讀取都不是按需讀取,而是讀取多

於需求數據區域內的數據到內存,用於後續使用,提升寫讀取數據速度;

注:磁盤預讀通常都是每次讀取邏輯上的一頁,或物理上的一塊,無論實際需求是多少;

 

數據庫索引的實現一般使用B樹及其變種B+樹,下面進行B-/+Tree結構的數據庫索引的性能分析:

(1)B樹索引結構:

數據庫系統的設計者巧妙利用了磁盤預讀原理,將B樹的一個節點的大小設爲等於一個頁,這樣每一個節點只須要一次I/O就能夠

徹底載入。爲了達到這個目的,在實際實現B-Tree還須要使用以下技巧:

——每次新建節點時,直接申請一個頁的空間,這樣就保證一個節點物理上也存儲在一個頁;

B-Tree中一次檢索最多須要h-1次I/O(磁盤IO不包括根節點,由於根節點常駐內存),漸進複雜度爲O(h)=O(logdN)。一

般實際應用中,出度d是很是大的數字,一般超過100,所以h很是小(一般不超過3)。

而紅黑樹這種結構,h明顯要深的多。因爲邏輯上很近的節點(父子)物理上可能很遠,沒法利用局部性,因此紅黑樹的I/O漸進

複雜度也爲O(h),效率明顯比B-Tree差不少。

因此,B樹結構的數據庫索引,在元素查找上效率很高;

 

(2)B+樹的索引結構:

B+樹則適當犧牲檢索的時間複雜度(都必須檢索到葉子結點),但改善了節點插入和刪除的時間複雜度(相似用鏈表改善數組的效

相關文章
相關標籤/搜索