基礎知識:
網絡:
cookie和session的區別:
這兩個都是爲了解決http協議無狀態的問題而提出的,兩者合作共同解決這一個問題
cookie是存放在客戶端的,記錄一個sessionid,是服務器發送給客戶端用來唯一標識一個客戶的
session存放在服務器端,利用sessionid來區分不同的客戶
跳躍表
http://blog.jobbole.com/111731/
https://www.cnblogs.com/George1994/p/7635731.html
跳躍表的性質(空間複雜度是o(n))
由很多層組成,每一層都是一個有序鏈表
每一個節點有兩個指針,一個指向同一層的下一個節點,一個指向下一層的同一個節點
最後一層鏈表包含所有的元素
跳躍表的查找(時間複雜度log(n))
自上而下查找,一直查找到一個節點的值小於給定值並且該節點的下一個節點的值大於給定值,然後進入下一層繼續查找,如果沒有下一層,則查找結束
跳躍表的插入(查找的時間複雜度o(logn)+插入的時間複雜度o(1)=o(logn))
自上而下查找待插入的節點的插入位置,然後插入節點,同時根據拋硬幣的原則決定是否提升當前節點,如果要提升則在其上層節點中插入當前節點,然後對上層中插入的節點做相同的處理,如果不提升則插入結束
跳躍表的刪除(查找的時間複雜度o(logn)+插入的時間複雜度o(1)=o(logn))
自上而下,在各個層中找到指定值的節點並刪除,如果當前層只剩下頭尾兩個節點則刪除這一層
include尖括號和雙引號的區別
尖括號一般默認是庫文件會去系統的include目錄裏去搜索然後再去搜索源代碼目錄
雙引號默認是用戶自定義的頭文件會現在源代碼所在目錄裏搜說然後再去系統目錄裏搜索
兩種事件處理模型
reactor模式(同步I/O):主線程只負責監聽文件描述符上的事件,有的話通知(消息隊列)工作線程,工作線程負責連接,I/O和業務處理。(有點像炒菜,主線程只是報個菜名,然後後面的切菜炒菜都是工作線程負責)
proactor模式(異步I/O(信號)):主線程和內核負責所有的I/O操作,工作線程只負責業務處理部分(主線程負責記菜名,切菜,工作線程只是炒一下就好了)
數組名和指針的區別
兩者都是指針,數組名是數組首元素的指針,但是數組名是一個常量指針,本身不能改變,但是它所指之物的值何以改變
開機流程linux系統
首先開機啓動的第一個程序是bios,bios去讀cmos,裏面是一些系統的硬件的一些基本參數,bios知道了硬件就能找到第一個可開機的設備,然後去讀裏面的第一個分區MBR的boot loarder程序,boot loarder再去加載內核到內存中,內核加載之後啓動的第一個程序是init(systemd)進程
如何判斷一個圖是否連通
dfs,bfs 從任意一點開始遍歷圖,如果圖是連通的那麼就能訪問到所有的節點,否則不是連通圖
如何把一個文件快速下發到100w個服務器上
樹狀:每個服務器接受上層服務器傳來的文件之後像下層服務器轉發
p2p:將文件分塊分發到不同的服務器上,每個服務器可以向其他服務器請求文件的同時向別的服務器也傳輸文件,很快就可以擴散到100w臺服務器
引用和指針的區別?引用佔不佔內存怎麼驗證
- 指針保存的是所指對象的地址,引用是所指對象的別名,指針需要通過解引用間接訪問,而引用是直接訪問;
- 指針可以改變地址,從而改變所指的對象,而引用必須從一而終;
- 引用在定義的時候必須初始化,而指針則不需要;
- 指針更靈活,用的好威力無比,用的不好處處是坑,而引用用起來則安全多了,但是比較死板。
引用在作爲函數參數的時候佔內存,因爲實際上是傳遞了一個指針進去,除此之外不佔內存。
驗證可以通過int a=1;int& b=a; int c=2,查看ac的地址是連續的
菱形繼承存在虛函數的情況下,類的內存分佈?,使用虛繼承不考慮虛函數類的內存分佈?
菱形繼承存在虛函數的情況下,b,c繼承a, d繼承b,c
d的內存佈局首先顯示b的部分,然後是c的部分,最後是d的部分
b的部分中包含了a,如果a中有虛函數,那麼有一個虛指針,這個虛指針是b中的a和b還有d共享的
c的部分中也包含了a,如果a中有虛函數,那麼有一個虛指針,這個虛指針是c中的a和c共享的
使用虛繼承不考慮虛函數類的內存分佈:
d的內存佈局首先是b的部分,然後是c的部分,然後是d的部分,然後是a的部分
b的部分首先是一個虛基類指針,這個指針指向a的部分
c的部分也是最開始是一個虛基類指針,這個指針同樣指向a的部分
epoll兩種工作模式的區別
LT(電平觸發,默認)ET(邊沿觸發,更高效)
LT:應用程序調用epoll_wait,對某一個文件描述符上的時間如果不處理的話,下次epoll_wait還會報告給應用程序知道被處理
,但是ET工作模式只觸發一次,必須立即處理,否則不會再報告。因此ET會避免一個事件被重複多次觸發,會更高效
拷貝構造函數?智能指針的拷貝構造函數和賦值運算重載函數?
拷貝構造函數:
A(const A& x){
this.val=x.val;
}
賦值運算符重載函數:
A& operator=(const A& x){
this.val=x.val;
}
智能指針的實現
https://www.cnblogs.com/lengender-12/p/6658679.html
UDP如果報文太長怎麼辦?
封裝成IP報文的時候,超過了MTU,IP協議會將其分片
堆和棧的區別?爲什麼棧快?(分配1,訪問3)
https://blog.csdn.net/baidu_37964071/article/details/81428139
1.棧是由系統負責分配回收,堆是由程序員負責申請釋放,棧的分配更加快速,堆的更慢,因爲需要遍歷系統的空閒鏈表找到合適大小的空閒塊,同時還有內存碎片的問題
2.棧的大小有限,堆可以分配更大的空間
3.數據的存取效率:棧提供系統級的支持有專門的寄存器(sp存放棧頂地址)還有機器指令,棧的數據訪問可以直接找到數據,而堆的數據訪問需要先讀取堆的地址然後再去讀堆中的數據因此更慢,間接尋址(地址放在寄存器中,先去寄存器中讀取地址,然後再根據地址去讀取數據)
C++和c的區別
c是面向過程的,c++是一個支持多種特性的語言,他兼容c,也有面向過程的部分,同時他還有面向對象的特性,還有模板和泛型編程。
c和c++的內存管理方式也不同,一個是malloc,free 一個是new,delete
爲什麼內存分配採用棧?爲什麼要採用後進先出的形式?
霍夫曼編解碼?
首先先建立霍夫曼樹(根據每個字符出現的頻率,頻率高的編碼的長度比較短),對每個字符進行編碼(左子樹1右子樹0,然後從根節點開始遍歷,路徑上面的所有01串組成一個字符的編碼)
解碼過程就是每次從根節點開始遍歷直到到達葉結點,將該編碼串翻譯成葉結點對應的字符,再從下一個編碼串開始直到翻譯完
如何判斷內存泄露,野指針是什麼,內存泄漏怎麼辦?
野指針:指向已經釋放的內存或者沒有訪問權限的內存指針(感覺空懸指針是野指針的一種?!)
內存泄漏:申請了一塊堆上的內存,但是沒有顯示釋放掉,造成內存泄漏;對象沒有被正確的析構掉(父類析構函數非虛)
指針越界:訪問沒有訪問權限的內存
空懸指針:指針沒有初始化指向一個不確定的地方,或者指針所指的地址釋放掉之後,指針沒有賦空,依然指向已經釋放掉的內存
檢測內存泄漏:檢測malloc和free是否匹配,window下可以利用crt庫跟蹤內存的分配(分配內存的代碼所在的行和文件,第多少次分配,可以通過添加斷點(根據次數)觀察函數調用棧發現內存泄漏的代碼)和釋放。如果沒有正確釋放就會被檢測出來。
內存快照:在有可能發生泄露的地方獲取內存快照進行對比
linux下用valgrind
瀏覽器輸入地址後發生的全過程
涉及到的協議http,dns,tcp,udp,ip,arp
首先需要對輸入的域名進行解析,利用DNS協議,獲得IP地址(DNS需要首先獲取域名服務器的IP地址,然後經過一系列的封裝(將DNS報文封裝成底層的UDP再封裝成IP包,在封裝成幀)發送到DNS服務器,DNS服務器響應並給出IP地址。幀的發送需要用到mac地址,如果arp緩存表裏面沒有對應的mac地址,還需要把IP地址轉換成mac地址,用到arp協議(附加arp請求的過程))
拿到域名對應的IP地址之後,就可以進行http請求了,http協議建立在tcp協議之上,因此需要首先進行三次握手建立連接
建立連接之後就可以進行http請求和響應了
最後客戶端請求結束斷開連接,四次揮手
爲什麼是三次握手,四次揮手
tcp是全雙工通信,因此至少需要三次握手才能確保雙向的連接。三次握手能在一定程度上減少syn攻擊(主動連接端不停的發送syn報文,如果只是兩次握手的話,服務器端的資源會很快被消耗完,導致服務器崩潰,如果是三次握手還需要回復ack報文,增加攻擊的難度),另外就是防止失效的連接造成錯誤,a向b發送的同步報文由於超時,a又重新發送了新的同步報文,並和b建立了連接之後完成通信接着斷開連接,此時超時的同步報文到達b,b以爲a又發起了新的連接,如果沒有三次握手,那麼b就一直等待着a,消耗了資源,如果有三次握手的話,b等不到a的確認報文就不會建立連接
四次揮手:同樣因爲tcp是全雙工的,所以要可靠的關閉兩端的通信最少需要三次,但是有可能被動關閉方還有數據沒有發送完或還沒被全部確認有可能需要重新發送,所以有可能不會立即關閉,因此被動關閉端的fin報文和ack報文會分開發送所以需要四次
c++解決內存泄漏方法
使用智能指針管理內存,只能指針在其析構函數中會自動進行資源的釋放,shareptr首先會判斷引用計數是否爲0.如果不是隻是將引用計數減一,如果是的話就調用delete將內存釋放掉
但是shareptr會存在循環引用的問題,也會造成內存泄漏,解決方法是weakptr,weakptr不會增加引用計數(將一個對像內部的shareptr換成weakptr),因此不會造成循環引用的問題
DNS的底層協議
dns同時佔用tcp和udp的53的端口
區域傳送時使用TCP(輔域名服務器會定時(一般時3小時)向主域名服務器進行查詢以便了解數據是否有變動。如有變動,則會執行一次區域傳送,進行數據同步。區域傳送將使用TCP而不是UDP,因爲數據同步傳送的數據量比一個請求和應答的數據量要多得多)
域名解析時使用UDP協議:
Linux查找特定文件
查找內容中包含某個字符串的文件:find . |xargs grep '字符串'
查找文件名中包含某個字符串的文件:find . -name '字符串'
歷史命令
history(顯示所有的)
history 3(顯示最近的三條)
!command(執行最近一條包含conmmand的命令,相當於補全)
向上的箭頭(表示上一條命令)
Vim命令
複製yy(nyy)
粘貼p(粘貼到光標所在行的下一行) P(上一行)
移動到第一行(gg),移動到最後一行(G,移動到第n行,nG),移動到一行的開頭(0),移動到一行的結尾($) 向下移動n行(n+enter)
刪除光標處的一個字符dl(或者x 向後刪除n個字符nx ) 向前刪除X=backspace 刪除整行dd(ndd)
列選擇 ctrl+v
上下翻頁:ctrl+b(上)ctrl+f (下)
搜索:/word(向下搜索)?word(向上搜索) :1,$s/word1/word2/g (替換) :1,$s/word1/word2/gc(詢問是否替換)
撤銷u(反撤銷ctrl+r)
重複前一個動作 (.)
-------------------
編輯模式 i (插入一個字符) o(插入一行)
--------------------
命令模式:!wq
---------------------
連續選擇多個字符:v (左右鍵) 連續選擇多行V(上下鍵) 選擇一塊,相當於箭頭按住選擇一個矩形區域(ctrl+v)
塊選中之後的操作(複製y 粘貼p 刪除d)
查看系統命令
free
https://www.cnblogs.com/pengdonglin137/p/3315124.html
分total used free cache buffer (total=used+free)
mem是對操作系統而言的,所以cache+buffer被算進了used裏面
但是+、-buffer,cache是對應用程序而言的,認爲cache和buffer總是可用,把cache+buffer被算進了free裏面
top
https://www.cnblogs.com/dragonsuc/p/5512797.html
按數字鍵1可以查看多cpu的狀態。否則一般顯示的是所有cpu的一個平均值
linux中查找命令find、locate、whereis、which、type區別
find可以查找所有類型的文件,會搜索磁盤
locate比find快也是所有類型的文件,因爲他會查詢一個數據庫
whereis 查詢二進制文件,man文件,也是查詢數據庫
which會在path變量指定的路徑中查詢系統命令(系統命令對應的可執行文件)
type也是查詢命令時shell自帶的還是外部的命令
SQL慢查詢:
https://www.cnblogs.com/qmfsun/p/4844472.html
第一步設置慢查詢的日誌(在mysql的配置文件中設置),可以設置日誌的路徑還有日誌文件名,然後設置要記錄的慢於多長時間的語句需要記錄
第二步分析具體的語句,用explain ,可以看到一個查詢的執行計劃,怎麼執行的,用了哪些索引,從而可以進行優化
常量引用(對const的引用)的作用
限定引用所引用的對象不能通過該引用被修改
常量引用可以引用非常量對象,可以引用字面值,可以引用表達式,可以引用類型可引用類型不一致的類型(本質是產生了一個臨時對象)
最優二叉樹(霍夫曼樹)
帶權路徑最短的二叉樹,權值乘以從根節點到葉結點的路徑長度稱爲帶權路徑
Linux擴大分區
第一如果使用的是LVM幾邏輯卷管理就可以動態的擴展分區(擴展原理:首先許多物理的分區或者磁盤(PV)組合成一個大的邏輯的磁盤(VG),然後這個大的邏輯的磁盤進行分塊,每一個小塊就PE,分區的實現是將VG進行分區形成LV,LV的擴大就是增加PE,減小就是刪除PE)
第二刪除老的分區(刪除之前備份數據),重新劃分一塊更大的分區(前提是還有空閒空間)然後文件進行拷貝
第三重新建立一個新的分區(前提是還有空閒空間),然後把新的分區掛在到老的分區下面就可以繼續使用
磁盤陣列
raid-0 有多塊磁盤,每次寫數據的時候數據被分散的寫到各個磁盤上面,因此讀寫性能很好,但是一塊磁盤的數據損壞之後所有的數據就都不能用了
raid-1 (鏡像)每個磁盤上都存相同的數據,讀性能極佳,但是磁盤容量會減半
raid-01 先組裝成raid-0,再組裝成raid-1
raid-5搞不清楚
map用的是紅黑樹,和AVL樹的區別
都是平衡二叉樹,但是紅黑樹的平衡性沒那麼嚴格,AVL是左右子樹的高度相差不超過一,紅黑樹只需要保障對任意一個節點,從這個節點出發到葉結點的所有路徑上面的黑節點的數目一樣即可。因此AVL的平衡性的維護代價也比紅黑樹高,紅黑樹一般不需要自底向上的一個不斷調整的過程(伯父節點是黑節點),如果非要涉及到這樣一個調整的話(伯父節點是紅節點),那麼可以採用自頂向下的一個過程來減少旋轉操作(只需要修改節點的顏色)
map刪除元素要注意什麼?
刪除元素之後原來的迭代器就會失效,一般用這個語句比較好 m.erase(iter++)先返回iter的副本,不會影響iter本身,iter本身已經指向下一個元素了
25u-50結果是多少,u代表unsigned
25+max(unsigned int)+1-50
什麼時候出現段錯誤
指針越界
系統中斷
第一類cpu外部中斷:I/O中斷,時鐘中斷
第二類cpu內部中斷:溢出,越界
第三類系統調用中斷
發生中斷的時候會從用戶態切換到內核態。內核態的優先級高不允許被搶佔,並且處於內核態的時候可以訪問到所有的內存空間,用戶態與之相反
模板類中可以使用虛函數嗎?模板成員函數可以是虛函數嗎?
https://blog.csdn.net/zzuchengming/article/details/51763563
模板類中可以使用虛函數。和普通的類沒有區別。
但是模板成員函數不能是虛函數,因爲類在定義的時候必須確定虛函數表的大小,但是模板成員函數只有在調用的時候才實例化,因此必須知道有多少模板成員虛函數被調用了才能知道有多少虛函數也才能確定虛函數表的大小,但是並不能提前知道有多少函數被調用了。
什麼時候需要自己定義構造函數,拷貝構造函數,賦值運算符,析構函數?編譯器什麼時候需要合成構造函數拷貝構造函數等?
需要定義析構函數的類一般都需要定義拷貝函數和複製運算符函數,一般管理動態內存的類需要定義析構函數(像share_ptr)
四種情況:(一般而言編譯器在有必要的時候纔會爲類合成構造函數等一些函數)有必要的時候是指:含有基類,含有成員對象,含有虛函數,含有虛基類
forward, move,右值引用,移動拷貝
https://www.cnblogs.com/my_life/articles/5995578.html
左值和右值:凡是&操作能夠成功的,都是左值,其餘都是右值
一般的引用時左值引用
右值引用:對右值的引用
移動拷貝函數:( A(A && t) ; A(const A& t))就是避免複製。
move :將左值轉換成右值
forward :一般是一個函數中調用另一個函數,他們的參數又是同一個,希望可以達到第一個函數中的參數是左值那麼第二個函數中的參數也是左值,第一個的是右值第二個的也是右值,一般用在模板函數中
RAII機制
利用類去管理資源(內存,數據庫連接,套接字,互斥鎖),防止資源泄漏。原理是將資源的釋放操作放在管理資源的類的析構函數中,利用析構函數會再對象結束生命週期之後自動調用的原理,將自動的釋放資源,從而避免資源泄漏。
各種排序空間複雜度和時間複雜度,穩定程度
https://blog.csdn.net/yushiyi6453/article/details/76407640
字節序,網絡序是什麼字節序,爲什麼會有不同的字節序
小端:高字節高地址,低字節低地址
大端:高字節低地址,低字節高地址
網絡序是大端
爲了交換數據的方便和統一,不管機器字節序是什麼大家都統一遵循網絡字節序是大端字節序,因此從網上接受到的數據和發送到網絡中的數據都是大端字節
opencv裏面的基本算法(搞一個能講出原理,會做,其他知道名字知道是幹嘛的就行)
開源的視覺庫(圖像處理庫)。
基本的數據結構:cvmat iplimage
圖像處理:平滑(中值平滑),形態學(膨脹,腐蝕,開運算(突出的部分消失),閉運算(凹陷的部分消失)),縮放,閾值化
圖像變換:卷積(圖像中的點的灰度值和核中的值相乘相加作爲核中心元素卷積後的值,實際意義,比如說求均值的時候可以定義一個3*3大小的每個元素都是1/9的核,卷積實際就是在求一個3*3鄰域的均值),梯度,canny,旋轉平移,傅立葉變換(整不明白)
解決hash衝突的幾種方式
第一,開鏈;第二,線性探測(1,2,3),二次探測(1,4,9);第三,再哈希,使用第二個哈希函數,第三個直到不在發生衝突爲止
有哪些方法清除cache中舊的數據
兩種緩存:cache(讀緩存) buffer (寫緩存)
sync命令
echo 1>drop_caches清理頁面緩存
echo 2>drop_caches清理目錄緩存和inode
echo 3>drop_caches清理頁面、目錄緩存和inode
多進程和多線程的使用場景
https://blog.csdn.net/qq_16209077/article/details/52769609
需要使用併發的時候,需要用到多進程和多線程
從數據同步和共享來講,多線程的數據同步比較複雜,數據共享很簡單
創建和切換,多線程是比較快速,因爲沒有自己的資源
編程和調試,多進程簡單一點
可靠性,多進程更可靠一點
分佈式,多進程是多核,多機分佈,多線程是多核分佈
需要頻繁的創建和銷燬,需要大量的計算一般用線程。多機分佈的話用多進程
B+樹,跟B樹有什麼區別?
m階B樹每個節點最多隻有m-1個元素,B+數最多有m個
B+說的所有數據元素都同時存放在葉子節點
查找數據的複雜度,B+樹是穩定的,B樹則跟查找的元素有關係。B+樹的範圍查找很方便
cout和printf有什麼區別?
cout對於類型的控制更加安全(不用指定具體類型,因此也不怕指定錯了之後會有錯誤的後果)智能;擴展性好(可以根據用戶自定義的類型來重載運算符就可以實現用戶自定義類型的輸出,但是printf只能輸出特定的幾種類型)
爲什麼模板類一般都是放在一個h文件中?(不太會)
放在h文件中可以很方便的被包含到其他文件中,這樣在實例化模板的時候就可以找到相應的模板定義。放在h文件中可以不用去處理,也符合模板沒有被實例化就不用被處理,但是放在cpp文件中需要被處理,但是又不知道相應的類型無法處理。
自己設計如何採用單線程的方式處理高併發
異步I/O處理,proactor模式
判斷一個點是不是在三角形內
https://blog.csdn.net/deepseazbw/article/details/75913253
面積法:三個小三角形的面積之和等於大三角形的面積
同向法:該點與任意頂點在其他兩個頂點所形成的直線的同側
講講大量請求時怎麼辦(分佈式集羣,I/O複用,緩存,索引)
說明聯合共用內存的概念
不同數據類型共享同一段內存,同一時刻只有一種數據類型的數據有效。爲了節省內存。
智力:
時針和分針的夾角計算
先計算分針走過的角度x*(360/60) 然後計算時針走過的角度y*(360/12) 然後計算分針帶動時針走過的角度x*(30/60)然後計算時針和分針走過的角度的差的絕對值就是兩者之間的夾角
一副撲克牌,怎麼實現隨機打亂?
https://blog.csdn.net/zly9923218/article/details/51418366
對第一張牌,產生0-n-1的隨機數,並將第一張牌和隨機數代表的牌進行交換
對於第二張牌,產生0-n-2的隨機數,並價格他們交換
這樣可以保障每張牌出現在每個位置上的概率都是1/n
第一張是1/n
第二張是在第一張的基礎上是條件概率 (1-1/n)*(1/(n-1))=1/n
一到一百萬的素數,怎麼快速求
用查表的方法,剛開始用3-一百萬的數除以2,能整除的去掉
然後接着用4-一百萬的數除以第二個質數3,能整出的去掉
一次用質數去除,最後剩下的數就是所有的質數
topk,快排,堆,複雜度
有一堆數,再給你很多對數,每對數都在同一個組,求一共有多少組數
int to string,string to int(string to int的時候,數字越界要拋出異常,要考慮負數,前置0等情況)
刪除單項鍊表中重複的節點 (1 2 2 3 3 9) -> (1 2 3 9)
求二叉樹的深度
單鏈表判環
求一個數組的最長連續子序列(連續,不連續),最長遞增子序列(連續,不連續)
判斷一顆樹是不是二叉搜索樹
之字形打印二叉樹
二分查找中位數
手寫vector<int> 擴容代碼
memcpy 函數 怎麼實現的
求每一個元素右邊第一個最大元素