秋招面經蒐集總結
2018.7.23
下面是個人在秋招過程中搜集的一些面經,分享出來如下:
——————————————————————————————————————————————————————
1.程序和執行緒的區別?(什麼樣資源在兩個執行緒共享)
——程序是資源分配的最小單位,執行緒是cpu排程的最小單元
——一個程序有多個執行緒,多個執行緒可以併發執行
——程序的建立退出作業系統為其分配資源,切換執行緒需要儲存這些資源,程序切換開銷大,同一個程序的執行緒共享該程序的資源,故執行緒僅僅有一些自己獨立的暫存器堆疊資源,執行緒之間切換開銷小
——程序之前有專門的通訊方式:管道、訊號量、訊息佇列、共享記憶體、socket套接字,執行緒之間通訊主要靠鎖和訊號量來完成。
2.c++怎麼寫是分配棧記憶體?
——class node,node a = null; a = b;臨時變數,分配棧記憶體
——class node,nodea = new node(b); 分配堆得記憶體,需要用delete刪除
3.new和malloc區別?(建構函式在什麼時候建立的?回答new和malloc重要區別)
——new分配記憶體的時候可以動態繫結,在程式執行的時候繫結資源,是一種操作符
——malloc不能動態繫結,只能在編譯之前確定記憶體的大小,是一種庫函式
——new分配記憶體之後,建立物件自動執行建構函式,銷燬自動完成析構,malloc則沒有這一過程
——new自動分配物件記憶體空間,進行安全性檢查,malloca指定分配記憶體空間,不進行安全性檢查
4.STL能夠寫new vector這樣操作?(vector resize特點capacity)
——vector建立的時候會建立多的容量,當超過這一部門多的容量的時候,會重新resize分配一個原容量兩倍的容器,然後將原資料拷貝到新分配的容器中。
5.為什麼要用虛擬函式?虛擬函式一般在編譯器怎麼實現多型?
——函式在編譯的時候首先進行命名的檢查,通過命名的檢查詢到函式,然後檢查該函式是否是虛擬函式,如果是非虛擬函式,直接靜態繫結對應的函式指標,是虛擬函式,則為該物件建立虛擬函式表,並建立虛擬函式表的指標,加入該結構體重。等到執行階段,物件繫結的函式不同,將動態將該物件繫結給覆蓋的函式,從而同一個函式實現不同的功能,即為多型。
6.什麼是純虛擬函式?純虛擬函式可以不覆蓋嗎()
——不能,純虛擬函式就是一種介面,沒有實體,在子類中必須覆蓋父類的純虛擬函式,才能呼叫該純虛擬函式。
——————————————————————————————————————————————————————
1.我看你的簡歷上有寫計算機網路相關的,那你能講下tcp/ip,time_wait?
——4次握手,3次揮手,
——timewait為了防止最後一次揮手,伺服器端沒有收到揮手的確定訊號,這個時候伺服器會重新發送揮手資訊,客戶端在timewait的等待時間仍然可以接受到這個揮手,從而保證正常的關閉tcp.
2.字串匹配問題,判斷一個字串有木有在另一個字串裡面出現
——hashmap
3.第二個演算法題 應該是和網路相關的,大概意思是有65535個數據中每次取五個,要求取的不重複,
——為65536個數據建立hashmap表,之前取得資料就在hashmap裡面置true,沒有即為false,每次隨機取資料,如果發現是true則重新取一次即可。
4.一個整數數列,元素取值可能是0~65535中的任意一個數,相同數值不會重複出現。0是例外,可以反覆出現。
請設計一個演算法,當你從該數列中隨意選取5個數值,判斷這5個數值是否連續相鄰
注意:
- 5個數值允許是亂序的。比如: 8 7 5 0 6
- 0可以通配任意數值。比如:8 7 5 0 6 中的0可以通配成9或者4
- 0可以多次出現。
——撲克牌順子問題,首先排序,然後計算每個相鄰元素之間的gap值有多大,然後計算為0的值有多大,然後比較0的個數和gap的
個數的大小,0個數大於等於即可。
4.判斷結構體是否相等
——過載等於號,記住需要判斷指標指向的內容是否相等。
5.位域
——
位域 :
有些資訊在儲存時,並不需要佔用一個完整的位元組, 而只需佔幾個或一個二進位制位。例如在存放一個開關量時,只有0和1 兩種狀態, 用一位二進位即可。為了節省儲存空間,並使處理簡便,C語言又提供了一種資料結構,稱為“位域”或“位段”。所謂“位域”是把一個位元組中的二進位劃分為幾 個不同的區域,並說明每個區域的位數。每個域有一個域名,允許在程式中按域名進行操作。 這樣就可以把幾個不同的物件用一個位元組的二進位制位域來表示。位段成員必須宣告為int、unsigned int或signed int型別(short char long)。
struct bs
{
unsigned a:1;
unsigned b:3;
unsigned c:4;
} bit,*pbit;
bit.a=1;
bit.b=7; //注意:位域的賦值不能超過該域所能表示的最大值,如b只有3位,能表示的最大數7,若賦為8,就會出錯
bit.c=15;
printf("%d,%d,%d/n",bit.a,bit.b,bit.c);
pbit=&bit;
pbit->a=0;
pbit->b&=3;
pbit->c=1;
printf("%d,%d,%d/n",pbit->a,pbit->b,pbit->c);
通過:該位域的大小,例如a是1bit,b是3bit,c是4bit
6.fopen相關的,我記得大概意思是windows下和linux下用法區別
——形式:
windows:
FILE *fp = fopen(“D:\quick_sort.c”, “r”);
linux:
FILE *fp = fopen("/home/quick_sort.c", “r”);
——引數區別:
UNIX/Linux 不分文字檔案和二進位制檔案,而Windows下時區分的。考慮程式平臺相容性,若以二進位制形式開啟,最好加‘b’
windows,一般以二進位制開啟,最好加上b,例如rb
linux,直接r即可,不需要額外指明文字還是二進位制檔案
——————————————————————————————————————————————————————
2018.7.24
1.說一下new和malloc的區別(我:new是分配+構造,malloc只分配不構造;new是操作符,malloc是庫函式)
說一下虛擬地址是怎麼對映到實體地址的,說一下這個過程(作業系統不熟完全記不得這個東西了,我就扯了說有個轉換表這樣的東西,虛擬地址前幾位是找到對應的頁,然後後面幾位對應的就是偏移量這樣子,然後他說這只不過是找到頁表而已。我也不知道是什麼,就說不大清楚了)
——通過NAT頁表或者段表找到虛擬地址對應的表項,表項中存放的就是邏輯地址到實體地址的對映。
2.STL有了解過嗎?裡面空間分配是怎麼樣的?(然後我說了用allocator類來實現空間分配,有一級配置器二級配置器,還沒說完就被打斷了)
——有兩級配置器,第一級是分配大塊記憶體的,第二季是小塊記憶體,16個不同區間的記憶體,最小的8kb,最大的128kb,每個不同記憶體塊掛在對應的空閒連結串列上,分配的時候找空閒連結串列上最小的記憶體塊分配。
3.不是問你這些,我換個說法吧,如果用讓你寫一個STL的空間配置器,這個配置器需要經常分配大量的小記憶體,但大量的分配小記憶體會造成記憶體碎片,你會怎麼解決這個問題?(然後就跟他扯了一些二級配置器是怎麼實現的)
——slab機制,分配一些不同大小的資料塊,同空閒連結串列來組織。
那如果用你實現的配置器分配的空間是怎麼釋放的?(然後我說用allocator分配就用deallocator釋放,然後釋放的記憶體就放回到空閒塊連結串列中)
——用allocator分配就用deallocator釋放,然後釋放的記憶體就放回到空閒塊連結串列中。
我是問這些釋放的記憶體怎麼交回給系統?(我:額。。。這個程式關掉就交回去咯)
——釋放記憶體只有,作業系統負責回收堆裡面開闢的這些記憶體。
4.那假設系統只有100m記憶體你已經用了20m了,這樣下去不是會爆記憶體嗎?(我:這個我不大清楚了)
對c瞭解不?(我:瞭解,但寫的比較少)
那問你個c裡面資料結構體的問題,能不能直接用記憶體比較的方法比較兩個struct物件?(我:不行,struct會有記憶體補齊。然後想舉個例子說明一下為什麼不行,想到一半就卡殼了,對面就直接說行了不用說了。現在想了下應該是補齊之後記憶體地址裡面的垃圾值會造成影響,當時面到後面都有點亂了,腦子宕機了T-T)
——記憶體對齊,後面對齊的記憶體地址裡面的垃圾值會造成影響。
5.網路這一塊有了解過嗎(我:學過計網)
那tcp裡面的time_wait狀態知道吧,說一下(我:保證伺服器重發一個FIN之後,客戶端也能對這個進行應答,然後也保證處理到遲到的資料包)
——防止客戶端重傳,可以接收到。
6.如果有4億個數,你只有1G記憶體,你怎麼判斷某個數已經出現了(我:這個可以用點陣圖來做吧,四億個位,數n出現了第n位就置1,最後判斷某個位是不是1就行)
——bitmap用一個bit來判斷某個數出現或者沒有出現。
——————————————————————————————————————————————————————
1、一個C++原始檔從文字到可執行檔案經歷的過程
——主要經歷的是原始檔,預編譯,編譯,彙編,連結,可執行檔案。
——編譯,將高階語言翻譯成為組合語言,同時進行語法上的優化
——彙編,將組合語言轉換成為計算機能夠識別的機器碼
——連結,將多個檔案彼此關聯起來,形成一個可執行檔案
2、#include 的順序以及尖叫括號和雙引號的區別…
——如果該檔案用到其他的檔案,那麼就需要先引用其他的檔案,在引用自己需要的檔案。
——尖括號一般搜尋預設路徑下的標頭檔案,一般引用庫檔案;雙引號一般搜尋使用者的工作目錄的路徑下的標頭檔案,一般引用自己寫的標頭檔案。
3、程序和執行緒,為什麼要有執行緒
——為了更好的給cpu排程和更好的併發,在傳統的程序中提高了併發量,提出了執行緒,執行緒就是輕量級的程序。
4、C++11有哪些新特性
——語法上:auto,for:,nullptr
——STL容器:unordered_map/set
——多執行緒:thread的使用
——智慧指標:shared_ptr
5、為什麼可變引數模板至關重要,右值引用,完美轉發,lambda
——模板很重要,因為可以不考慮資料的型別,通過模板可以寫出通用的邏輯來,例如STL裡面的容器
——右值引用是為了消除臨時變數之間的拷貝浪費的構造析構的資源,右值引用可以指向臨時變數並且把臨時變數轉移給左值變數。
——lambda表示式:就是內嵌的匿名函式,用以替換獨立函式或者函式物件,並且使程式碼更可讀
6、malloc的原理,brk系統呼叫幹什麼的,mmap呢
——malloc用於分配記憶體,mmap用於將實體記憶體對映到使用者空間的一個檔案
7、C++的記憶體管理方式,STL的allocaotr,最新版本預設使用的分配器
——兩次結構,第一層分配大塊連續資料,第二層slab機制,預先分配小塊記憶體,用空閒連結串列來維護。
8、hash表的實現,包括STL中的雜湊桶長度常數。
——採用的是開放式定址法,雜湊桶為對映單元,桶內部用連結串列來維護。
——開始確定一個素數,根據表的填裝因子,然後表滿了就以兩倍的容量進行擴充套件,移動資料到新的表中。
9、hash表如何rehash,怎麼處理其中儲存的資源
——兩倍的容量進行擴充套件,移動資料到新的表中
18、epoll怎麼實現的
——epoll是通過回撥函式和就緒佇列完成的,當socket監聽到事物的時候,會觸發回撥函式,將這個套接字掛在就緒佇列上,並通知應用層去取資料。
20、手撕程式碼:1)給定一個數字陣列,返回哈夫曼樹的頭指標。2)最長公共連續子序列。
22、單核機器上寫多執行緒程式,是否需要考慮加鎖,為什麼?
——在單核上,多個執行緒執行鎖或者臨界區時,實際上只有一個執行緒在執行臨界區程式碼,而核心也只支援一個執行緒執行,因此不存在衝突。如果某個執行緒持有鎖,那只有其他執行緒不會被排程到CPU上執行,影響的只是持有和釋放鎖的時間,處理器時刻在執行著。但是在多核上執行時,鎖或臨界區會導致其餘處理器空閒而只允許一個處理器執行持有鎖的那個執行緒,這是一個序列的過程,會影響效能。
——不需要加鎖,因為處理器同一個時刻只會有一個執行緒去訪問臨界區,不存在衝突的情況。
23、執行緒需要儲存哪些上下文,SP、PC、EAX這些暫存器是幹嘛用的
——堆疊指標SP
——程式計數器PC
——累加器暫存器EAX
24、HTTP和HTTPS的區別,HTTPS有什麼特點,帶來的好處和壞處,怎麼實現的
——https在http上增加了ssh,提高了安全性的保證。
——好處:安全性,壞處:影響相應延時,證書需要第三方費用
——怎麼實現:加上ssh的證書認證
25、執行緒間的同步方式,最好說出具體的系統呼叫
——生產者消費者模型,例項就是命令佇列,向命令佇列裡面加入命令的時候,給佇列加鎖,同時命令執行執行緒沒有命令的時候進入睡眠狀態,命令新增完成的時候喚醒命令執行執行緒,去命令即可。
26、雜湊表的桶個數為什麼是質數,合數有何不妥?
——取質數更容易減少衝入,取合數衝突較多,這是因為質數只能被本身和1除盡,合數可以被其他數除盡,除盡的數就都是衝突點,衝突明細較多。
——————————————————————————————————————————————————————
1,講專案
2,專案用到了redis,講一下redis的主從複製怎麼做的。。講了挺久的。。
3,寫程式碼,去掉字串中的空格空格,C語言實現(雖然寫出來了,但是面試官說4行程式碼就能寫出來這個。。)(2年沒寫過C和Cpp了崩潰。。)
for(int i=0;i<str.size();i++)
if(str[i] == " ")
str.erase(str.begin()+i);
4,如何把一個檔案快速下發到100w個伺服器
(面試官之後說你可以想想迅雷是怎麼做到下載速度那麼快的)
——
如果集中式地放在一個伺服器或快取上的話,頻寬、連線都會遇到問題。只說idea的話。
樹狀:
1. 每個伺服器既具有檔案儲存能力也應具有檔案分發能力。
2. 每個伺服器接收到檔案之後向較近的伺服器分發,具體類似多叉樹,應該挺快的。
索引狀:
1. 設定1000個快取伺服器,檔案先下發到這些快取上。(具體多少快取、分幾層快取和具體業務有關。)
2. 每個快取伺服器接收1000個伺服器取檔案。
p2p網路:每個節點既能接收也能發出,朝自己近的網路發出。
5,如何判斷一個圖是否連同?(開始說DFS,面試官說不滿意,後來說並查集)
——DFS和BFS有的步驟都是從一個頂點開始,然後判斷該頂點是否被訪問,而且該頂點和其他頂點是否有關係,若有關係並且沒有訪問過,就往下訪問,要是無向圖是連通的,那麼這個過程會依次下去遍歷所有節點。所以通過這個特性,就可以設定一個全域性變數count去記錄,看最後count的值和頂點數是否相同,若相同則說明是無向連通圖
——————————————————————————————————————————————————————
C++/C的記憶體分配,棧和堆的區別,為什麼棧要快
——c++一般對於堆得分配是用new,c對於堆的分配是用malloc
——堆是使用者自己分配和回收資源的,棧由系統自動分配資源並回收
——棧是有作業系統自動分配資源並回收,作業系統底層支援這一類資料結構,其中會為棧分配專門的地址暫存器用來存放棧的地址,壓棧和出棧都有專門的指令,而堆得分配是由cpp的庫函式提供的,會有一定的演算法以及搜尋分配塊的機制,速度相比棧來說肯定是慢了。
C++和C的區別
——面向物件,面向過程
TCP三次握手
——最小可靠性的保證
——客戶端第一次握手,表示能發,伺服器接受,表示能收,然後傳送確認訊號,表示能發,客戶端收到確認資訊,表示能接受,這樣三次握手之後,即保證客戶端伺服器端能夠正常的接收。
給一個座標系和一個矩形,如何判斷矩形在座標系內(當時沒考慮到矩形邊沒平行x,y軸的情況,此時感覺掛了)
——?????判斷點是不是在矩形內部?直接判斷點在不線上的同側或者是異測即可。
如何用一個1立方米的方塊佔滿這個小教室(我:???)
——空間上使用dp,空間上可以從左右上進行塞,這樣使用遞迴可以知道塞滿整個房間的步驟和可能性。
——————————————————————————————————————————————————————
為什麼記憶體分配一定要用棧這個資料結構,先進後出?也就是為什麼棧是棧?
——因為區域性變數分配是按照先後順序的,函式建立先建立,但是函式只能最後釋放,這就是先進後出,有這種操作,所以有了棧這樣的資料結構。
整個面試流程是1.hr面試 2.英文邏輯題 3.結對上機測試(2,3的順序可能變換)
● 結對上機面試就是先問你作業的思想,然後擴充作業題,考察你的程式設計習慣,快捷鍵的使用,中間穿插一下基礎知識考察,難度還行吧
● 英文邏輯題看懂例子就不難,基於保密就不能說了,反正不難吧。
● 除了一張英文邏輯題的測試卷,沒有其他英語考察。
● 問了hr和上機測試的面試官,為什麼他們這麼認同公司。回答是文化和一種使命感,當時心裡想的是和dota2信仰玩家一模一樣。
——————————————————————————————————————————————————————
● 實習經歷
● C++記憶體分配
——常規的是new,delete
——stl是allcoated二級記憶體的分配
● 連結串列合併(leetcode原題)
——遞迴或者非遞迴
● 如何判斷記憶體洩露,野指標是什麼,記憶體洩漏怎麼辦?
——通過工具判斷,vs裡面有cmg監測記憶體洩漏的巨集,或者監控程序的記憶體,觀察是否洩漏,野指標就是指向了不存在的記憶體區域,記憶體洩漏需要找到洩漏的地方,分析原因,正常釋放
——————————————————————————————————————————————————————
3.overload 和overwrite的區別,怎麼實現的?返回值不一樣可以過載嗎?
——第一個是過載,虛擬函式過載
——第二個是重寫,子類就是一個類中的方法同名,但是形參的型別和個數不一樣,這叫做重寫
——————————————————————————————————————————————————————
1面 評估面
面試官:給我講講瀏覽器輸入地址後發生的全過程.(每一個細節都講)
我:http DNS 三次握手 arp rarp
面試官:講講為什麼是三次握手,四次揮手
我:2次握手超時資料包會影響很大,三次握手容易遭到syc攻擊,四次揮手很多情況下是三次(tcpdump抓)以及常見的粘包,資料包安全.滑動視窗.
面試官:記憶體分佈
我:堆.棧.常量區,靜態區
面試官:講講虛擬函式
我:虛擬函式表,以及虛擬函式的記憶體佈局,虛擬函式的侷限,c++11的提供的類似虛擬函式的新函式.兩種動態多型實現的區別以及優缺點
——虛擬函式在編譯階段會生成一個虛擬函式表的指標,這個指標指向虛擬函式表,當過載之後,子類的虛擬函式表指標指向子類的過載的虛擬函式,當呼叫虛擬函式執行的時候會動態繫結到對應的虛擬函式上。
——這要是虛擬函式的侷限,就是虛指標佔用記憶體空間
面試官:講講程序和執行緒
我:常見的一些書本知識,在暫存器和堆疊上的區別,協程的實現,非同步和同步程式設計.
2面
面試官:類什麼時候會析構?
我:區域性類變數彈出棧的時候會呼叫析構,new物件呼叫delete的時候會析構。
面試官:虛擬函式底層機制
我:虛擬函式表,以及虛擬函式的記憶體佈局
面試官:大區間求和
我:只想出歸併
面試官:講講codis和redis原始碼
我:這塊很熟,我也講的很多,包括效能瓶頸,主流公司的網路框架.以及程式碼改進,面試官還算滿意
面試官:講講bigtable mapreduce 以及其他著名開源分散式儲存程式碼
我:只看過kafka和快取
面試官:要多學點
5面(個人感覺最難幾乎社招要求)
首先讓我自己把tcp/ip講個遍。
分散式系統分片的極限在哪,linux系統的極限。redis叢集最大能支撐多少臺物理機,
——資料分片就是講資料打散寫入到不同的機器上,類似於pt,那麼問題在於一個環上到底最多能放多少個pt呢,這個問題之前都沒想到過,這個題目比較難!!
怎麼解決副本一致。
——RSM,catch-up, rebalance
分散式快取怎麼設計,
——memcached的設計思路
配置中心怎麼開發,
——OM模組的開發,負責配置檔案和升級
zookeeper的原理,
——paxos的具體實現,用來持久化元資料和選舉新主節點
二次提交原理。
——先通知,在決策提交。
——————————————————————————————————————————————————————
專案,主題模型
一個數據流,只能訪問一次,如何保證訪問每個資料的頻率相同
——蓄水池抽樣演算法(reservoid sampling)。具體的思路是:先初始化一個集合,集合中有k個元素,將此集合作為蓄水池。然後從第k+1個元素開始遍歷,並且按一定的概率替換掉蓄水池裡面的元素。
——先將前k個數取出來放入結果集中,然後從第k+1個數開始遍歷。假設遍歷到第i個數,以k/i的概率替換掉蓄水池中的某個元素即可。
c++11 future和promise
——不會
epoll,libev優點
——epoll 同步非阻塞的socket監聽
——libev事件驅動的監聽,不阻塞執行緒,可以使用多執行緒完成事件的驅動
建構函式能不能重寫(沒聽清要問什麼)
——不能
面向物件的優點:更易維護,增加程式碼的重用
大文字如何排序
——內部排序,bitmap
——外部排序,桶排序
最優二叉樹(我說資料結構比較熟,他說那我考你一個最優二叉樹。沒答出來,以為是排序二叉樹。。如果問我哈夫曼樹我就會了。。)
——排序,畫出哈夫曼樹,確定0 1 位數
棧和佇列
棧空間,堆空間,靜態區
棧區:有編譯器自動分配釋放,堆區:由程式設計師分配釋放
靜態區:全域性變數和未初始化的靜態變數
kmeans
——聚類的方法
linux如何擴大分割槽
——首先unmount解除安裝盤
——fdisk 檢視盤
——resize2fs /dev/sdb1調整分割槽
——mount重新掛載
——————————————————————————————————————————————————————
map用的是紅黑樹,和AVL樹的區別
——紅黑樹沒有avltree那麼強的平衡條件,它只用通過節點的紅黑來保證,任意一條路徑不能比另外一條路徑長出兩倍,AVLtree在保持平衡上要不斷的旋轉調整,增加了額外開銷,RB樹相對來說,開銷較小
map插入和刪除需要注意什麼
——插入的時候需要先判斷,因為key相同座標插入會覆蓋,呼叫insert會直接返回插入失敗
——刪除同樣,刪除之前需要判斷
mongodb 和 mysql 差別
——不會
IO多路複用方式的區別
——select poll epoll的區別
如何檢視函式所佔用的記憶體
——gdb除錯,一步步走,然後用ps監控程序的記憶體走向
C++多型是怎麼實現的,哪些函式不能是虛擬函式(建構函式,靜態函式,inline函式)
——建構函式,靜態函式,inline函式不能是虛擬函式
malloc(0)返回什麼:
——如果請求的長度為0,則標準C語言函式返回一個null指標或不能用於訪問物件的非null指標。
——————————————————————————————————————————————————————
為什麼解構函式要是虛擬函式,為什麼c++沒有預設解構函式為虛擬函式
——在類的繼承中,如果基類不定義成虛擬函式,當有基類指標指向派生類, 那麼delete基類指標時,只會呼叫基類的解構函式,不會呼叫派生類中派生類的解構函式。
——額,因為不一定有子類???但是c11裡面是建議寫成解構函式的
1.模板成員函式不可以是虛擬函式
https://blog.csdn.net/zzuchengming/article/details/51763563
——完全一樣,
在非模板類裡怎麼用虛擬函式,
就在模板類裡怎麼用
2.C++裡面有很多小類,如果都有虛解構函式,則會對每個類都加一個虛表指標,浪費記憶體
——這要是虛擬函式的侷限,就是虛指標佔用記憶體空間
——————————————————————————————————————————————————————
1.字串去空格
——string型別erase即可
2.十六進位制轉十進位制
——16位基數,power乘方函式呼叫執行
如何求前100大的數
——topk的問題,可以用最大堆,可以用快排思想,當然可以用排序
堆和棧的區別
——系統分配,自動回收
——自己分配,自己回收
全域性的const,在函式裡面改const的值(沒理解面試官問什麼)
——利用const_cast去掉const的屬性
io多路複用,為什麼epoll比較好,什麼時候select比較好
——epoll只用拷貝一次資料,epoll回撥函式等待佇列,不用輪詢套接字,epoll記憶體對映的方法,減少拷貝,epoll支援邊緣觸發
兩種觸發方式
——水平觸發,觸發了之後不斷通知上層應用取資料
——邊緣觸發,只會通知一次,之後不在通知了
程序間通訊
——管道、共享記憶體、訊息佇列、訊號量、套接字
共享單車如何分配
——統計某一段區域的人口密集程度作為優先順序許可權,按照人口的密集程度進行分配。
有一戶家庭,生了兩個娃,其中一個是女孩,另外一個是女孩的概率
——1/2
棧實現佇列,佇列實現棧
STL set用什麼實現,為什麼用紅黑樹實現
——因為是有序的,紅黑樹可以有序,平衡二叉樹導致深度太深,avltree插入較多情況旋轉效率低,heap是連續資料的儲存資料結構。
hash用在什麼地方
——kv儲存
各種排序空間複雜度和時間複雜度,穩定程度
快排什麼時候最不穩定
——以某一個基準交換的時候
linux基本命令
檢視程序,執行緒,函式的cpu佔用
——top ps
gdb
位元組序,網路序是什麼位元組序,為什麼會有不同的位元組序
——位元組序分為大端位元組序和小端位元組序
● 大端位元組序是指一個整數的高位位元組(32-31bit)儲存在記憶體的低地址處,低位位元組(0-7bit)儲存在記憶體的高地址處。
● 小端位元組序是指一個整數的高位位元組(32-31bit)儲存在記憶體的高地址處,低位位元組(0-7bit)儲存在記憶體的低地址處。
——現代PC大多采用小端位元組序,所以小端位元組序又被稱為主機位元組序。
大端位元組序也稱為網路位元組序。
——
只有當傳輸跨越了多個位元組的資料時才存在這個問題,比如TCP報文裡的IP地址、埠,或者你的應用程式本身直接傳數值。
(2)TCP統一規定使用大端方式傳輸資料,稱為網路位元組序。
(3)因此,inet_addr、htonl等這些函式就是把資料的本機位元組序轉化為網路位元組序(即大端),這些函式內部都會自行判斷本機位元組序。
——為什麼
同一個網路程式開發和跨平臺的發展,也應採取措施,確保只有一個位元組順序或雙方的解釋是不一樣的,因為發生錯誤。
——————————————————————————————————————————————————————
解決hash衝突的幾種方式。
——開放式定址法,開鏈法
有哪些方法清除cache中舊的資料。不太清楚,我扯到了作業系統中缺頁中斷的頁面置換原理上,什麼FIFO、最近最少使用、加權重等等。
——替換演算法,LRU LFU FIFO 電梯排程等
程序和執行緒的區別。
多程序和多執行緒的使用場景。多程序答了一個分散式系統,多執行緒沒答上來,後來問了才知道期望I/O密集型和CPU密集型這種答案。
——多線層是CPU密集型操作,例如影象處理,渲染的時候,不同維度由不同執行緒處理
——多程序是IO密集型操作,分散式系統中,不同的io可以使用不同的程序去執行。
死鎖,如何解決死鎖。解決死鎖忘了,我扯到執行緒同步上來。
——死鎖預防
——死鎖監測,使用環路取監測。
瞭解哪些設計模式,裝飾器模式是什麼。
如何保證單例模式只有唯一例項,有哪些方法。
——static提供全域性訪問點
——const提供物件不能被修改
資料庫設計三大正規化。僅答了知道一、二、三正規化,詳細的沒答。
——不會
SQL優化,有哪些優化方法。僅答了查詢優化加索引。
——索引優化,
OSI七層模型和TCP/IP四層模型,每層列舉2個協議。
TCP的三次握手和四次揮手。
C++中類成員的訪問許可權和繼承許可權問題。
——訪問許可權和繼承許可權不一樣
C++中static關鍵字的作用。
——表示靜態函式或者物件,不屬於這個類物件,
——————————————————————————————————————————————————————
1.自我介紹
2.用過linux系統嗎,哪種linux系統,版本呢?
——檢視作業系統的版本,uname -a檢視作業系統使用的核心,lsb_release -a檢視當前是什麼作業系統
3.linux基本命令。怎麼檢視IP;怎麼給檔案改名;怎麼檢視檔案的許可權;修改許可權;怎麼加執行許可權;怎麼檢視當前系統的版本;怎麼檢視當前系統硬碟空間的總量與使用情況;怎麼檢視系統記憶體多少;怎麼檢視某個命令執行的時候需要連結哪些系統庫;怎麼給一個檔案做一個軟連結;
——檢視ip,命令是ifconfig
——給檔案改名,mv命令,類似$ mv test.txt wbk.txt
——檢視檔案的許可權,ll,修改檔案許可權chmod,增加執行許可權,chmod + x,x代表是執行許可權
——怎麼檢視當前系統的版本,uname -a
——怎麼檢視當前硬碟的空間和使用情況,top
——怎麼檢視系統記憶體多少,top
——怎麼檢視某個命令執行的時候需要連結哪些系統庫,ldd 某個命令或者程序
——怎麼給檔案做軟連線,ln -s
4.vector與list的區別
——vector是連續的記憶體分配,list是分連續的記憶體分配
——vector支援隨機訪問,list類似連結串列只支援順序訪問
——vector有初始預分配空間,當超過這個空間的是會進行擴容操作,超過兩倍的擴容操作,list是離散的記憶體分配,沒喲擴容操作
——大量資料的插入,list要優於vector
5.怎麼找某vector或者list的倒數第二個元素
——vector直接通過下標啊哦做,list需要通過迭代器形成快慢指標,從首節點開始遍歷。
6.說一下map和set的區別
——map和set底層都是紅黑樹
——map是儲存鍵值對的關係,key類似索引,value就是索引的關鍵值
——set就是關鍵詞儲存的集合,每個元素就是一個key,一般用於檢查一個關鍵字是否在集合中
7.紅黑樹的原理
——紅黑樹是一種平衡二叉樹,沒有avltree那麼嚴格的平衡條件,主要通過對節點進行紅黑標誌,並設定一定的紅黑條件,以保證任意路徑不會長於另外一條路徑的兩倍,
——紅黑樹對於不平衡或者插入的時間複雜度都是lgn
8.map怎麼插入資料,有幾種方式
——map插入資料,insert還有陣列下標的方式
9.c++11在原來的版本上都加了哪些東西。
——auto for::容器,智慧指標
10.智慧指標,三種指標都介紹一下其特性,作用。
——智慧指標主要有三種:unique_ptr,shared_ptr,weak_ptr
—unique_ptr:unique_ptr拒絕對其拷貝,也就是說同一時刻只能有一個unique_ptr指向給定物件
——shared_ptr: 一個引用計數智慧指標,用於共享物件的所有權也就是說它允許多個指標指向同一個物件。
—weak_ptr:為了解決shared_ptr中出現的另一個問題,那就是當兩個shared_ptr物件互相引用的時候,就會造成兩個物件的引用計數無法到0,所以無法被釋放。
—weak_ptr的設計方案就是使他可以從一個shared_ptr或者weak_ptr中構造,但是這樣並不會使資源的引用計數增加。weak_ptr裡面沒有過載“*”“->”,所以並沒有真正的獲得資源的所有權,只能說是在觀測資源的引用計數(通過use_count()和expired()函式),不過weak_ptr裡有一個非常重要的成員函式lock(),它可以從shared_ptr中獲得一個可用的shared_ptr物件,從而操作資源。當引用計數為空的時候,則會返回一個空指標。
11.程序怎麼同步,執行緒怎麼同步,要說全。
——執行緒同步,互斥鎖,訊號量,讀寫鎖
——程序同步,互斥鎖+訊號量,生產者消費者問題
12.tcp與udp的區別,udp怎麼實現多對多通訊,問的很細,包括tcp的各種機制。
——面對流,一個是面對報文,一個是端對端,一個多對多通訊
13.說一下快排
——————————————————————————————————————————————————————
演算法:
二叉樹遍歷
——使用遞迴的話,前序中序後序都可以遍歷,使用非遞迴的話,需要使用棧,棧的話前序中序比較簡單,後序的話需要額外儲存當前根節點
中序遍歷的下一個節點(劍指offer原題,看了四五遍,還沒記住,該打)
——如果沒有給出指向父節點的指標,那麼需要按照中序遍歷一次二叉樹,在遍歷裡面判斷當前節點的下一個節點
——如果給出了指向父節點的指標,那麼當前節點就有下面兩種情況:
- 該節點存在右子節點,則下一個節點是右子樹的最左節點。
- 該節點不存在右子節點,則下一個節點是該節點的第一個父子關係為左的祖先節點中的父節點, 因為如果遍歷的節點是父節點的右節點說明父節點已遍歷過了
翻轉連結串列
——兩種方法,一種是遞迴的方法,每次遞迴後一個節點,遞迴返回值是後一個節點,最後就是返回尾節點,返回之後需要對頭結點做一個處理,一種是非遞迴的方法,三個指標,依次遍歷更改指標的指向即可
二叉樹深度
——兩種方法,一種是遞迴的方法,當前節點的深度是左右子樹深度最大值+1
——一種是層次遍歷,每個層次就是深度+1
——————————————————————————————————————————————————————
1. 自我介紹(不多說了,基本都是一樣)
2. 面向物件的三大特性
——面向物件的三種特性:抽象,繼承,多型
3. cpp怎麼實現多型的?
——靜態多型(編譯時):主要是有兩種:函式過載和模板
——函式過載:就是具有相同的函式名但是有不同引數列表(引數列表包括引數的型別、引數的個數和引數的順序,只要有一個不同就叫做引數列表不同)的函式,我們叫他們為函式過載。函式過載可以在編譯時候就確定我們應該呼叫哪個函式,所謂我們稱之為編譯期的多型。
——模板:我們定義了模板函式在編譯期就已經確定了T的資料型別,所以我們就可以正確的呼叫恰當的函式
動態多型(執行時):這個就是我們常見的虛擬函式的動態繫結
4. 如果有一個基類A有一個虛擬函式fun,子類B也有實現,基類A有一個函式init,裡面呼叫了fun,A的建構函式有呼叫了init,那麼init呼叫的是哪個fun?(多型實現機制的分析)
——init呼叫的是a的fun,因為a的構造的時候,b還沒有構造,那麼虛擬函式表中沒有b對應重寫的fun,所以init電泳的額就是a的fun。也就是a的虛表中找不到b中fun的函式地址
5. stl瞭解嗎?vector底層實現怎麼樣?vector怎麼擴容的?
——vector底層類似一個動態陣列,首先會設定預分配大小,當預分配大小不夠的時候,會進行擴容,擴容是從其他的記憶體空間在找原vector大小的兩倍進行擴容,然後在把原大小遷移到新擴容空間上。
——————————————————————————————————————————————————————
C++基礎
● 自我介紹
● 平時有用C++寫過專案嗎?(這裡沒讓我展開說專案)
● 對C++的特性有什麼瞭解
——抽象,繼承,多型
● 對封裝、繼承、多型的具體理解
——封裝就是講資料的許多特性請求做一個封裝,多外呈現呼叫介面的而部門
——繼承就是繼承子類繼承父類的一些特性,可以直接拿來用
——多型就是呼叫同一個函式會有不同的執行狀態
● public/protected/private的區別
——這些都是描述類的訪問限制
——public就是自己的類物件可以訪問
——private: 類的成員函式可以訪問這些成員變數或成員函式
——protected: 類自己和子子孫孫可以訪問
● 說一下三種方式繼承對基類的訪問許可權
——publix對基類完全訪問
——private基類都是私有化,只能通過成員函式來訪問
——protected基類的公有成員和保護成員在派生類中的訪問許可權都會變為保護(protected)許可權,私有成員在派生類中的訪問許可權仍然是私有(private)許可權。
● 說說建構函式的執行順序,解構函式呢
——建構函式構造順序是從父類到子類
——解構函式剛好相反,是從子類到父類
● 說一下建構函式內部幹了什麼
——建構函式負責確定物件的初始狀態以及分配必要的資源
——建構函式首先確定物件在記憶體中初始狀態,並且對這個物件分佈必要的一些記憶體資源
● 如何實現多型
——靜態多型(編譯時):主要是有兩種:函式過載和模板
——函式過載:就是具有相同的函式名但是有不同引數列表(引數列表包括引數的型別、引數的個數和引數的順序,只要有一個不同就叫做引數列表不同)的函式,我們叫他們為函式過載。函式過載可以在編譯時候就確定我們應該呼叫哪個函式,所謂我們稱之為編譯期的多型。
——模板:我們定義了模板函式在編譯期就已經確定了T的資料型別,所以我們就可以正確的呼叫恰當的函式
動態多型(執行時):這個就是我們常見的虛擬函式的動態繫結
● 建構函式和解構函式可以呼叫虛擬函式嗎,為什麼
——
● 建構函式跟虛構函式裡面都可以呼叫虛擬函式,編譯器不會報錯。
C++ primer中說到最好別用
由於類的構造次序是由基類到派生類,所以在建構函式中呼叫虛擬函式,虛擬函式是不會呈現出多型的
類的析構是從派生類到基類,當呼叫繼承層次中某一層次的類的解構函式時意味著其派生類部分已經析構掉,所以也不會呈現多型
因此如果在基類中宣告的純虛擬函式並且在基類的解構函式中呼叫之,編譯器會發生錯誤。
● 解構函式一定要是虛擬函式嗎,為什麼
——在實現多型時,當用基類操作派生類,在析構時防止只析構基類而不析構派生類的狀況發生。
● 怎麼理解C++的面向物件和C的面向過程
——面向物件是首先抽象出各種物件(各種類),把資料和方法都封裝在物件中(類),然後各個物件之間發生相互作用。面向過程是將問題分解成若干步驟(動作),每個步驟(動作)用一個函式來實現,在使用的時候,將資料傳遞給這些函式。
——
網上有一個典型的例子:把大象放入冰箱裡面。
C++是這麼做的:涉及到兩個物件:冰箱和大象。三個動作:開啟冰箱,放置大象,關閉冰箱。
首先定義一個冰箱類,他有開啟的方法,放置的方法,關閉的方法。然後再定義一個大象類。接下來構建冰箱和大象的物件,然後冰箱物件呼叫開啟門的方法,冰箱物件再呼叫放置大象物件的方法,最後冰箱物件關門。
當C是這麼做的:首先開啟冰箱門,然後把大象放入進去,最後關閉冰箱門。
● 可以介紹一下new的實現原理嗎
——完成兩件事,先底層呼叫malloc分了配記憶體,然後建立一個物件(呼叫建構函式)
● new和malloc的異同處
——new是呼叫了建構函式,malloc沒有,只完成了記憶體的分配
——new會自動分配物件所佔的記憶體空間大小,malloc需要自己計算出
——new會進行安全性檢查,malloc不會
● C++怎麼為各種變數分配記憶體空間的
——區域性變數分配棧上面的空間
——new的物件分配堆上面的空間
● 引用瞭解吧,介紹一下
——引用就是物件的別名,必須初始化
● 拷貝建構函式內部做了什麼,什麼時候需要重寫
——物件之間的拷貝定義,需要自己定義拷貝建構函式
● 初始化列表瞭解嗎(以為是那個C11特性,沒敢說)
——初始化列表按照物件宣告的順序進行,初始化時候即賦值,沒有額外的拷貝過程
程序執行緒相關
● 瞭解過執行緒嗎,談一下程序和執行緒的聯絡和區別吧
● 對於共享的區域多個程序或執行緒一起訪問會不會出問題,要怎麼解決(同步和互斥)
● 程序通訊有哪幾種方式,介紹一下
網路(專案裡有)
● Socket的流程是什麼樣的(服務端和客戶端兩個)
● 專案裡用的什麼協議(TCP)
● TCP和UDP的區別,優缺點
——1、TCP面向連線(如打電話要先撥號建立連線);UDP是無連線的,即傳送資料之前不需要建立連線
2、TCP提供可靠的服務。也就是說,通過TCP連線傳送的資料,無差錯,不丟失,不重複,且按序到達;UDP盡最大努力交付,即不保證可靠交付
——
UDP具有較好的實時性,工作效率比TCP高,適用於對高速傳輸和實時性有較高的通訊或廣播通訊。
4.每一條TCP連線只能是點到點的;UDP支援一對一,一對多,多對一和多對多的互動通訊
資料結構
● 說說vector和list的不同,優缺點
● 平衡二叉樹瞭解嗎,說說它的特點,時間複雜度(logN)
● 說說二叉樹的三種遍歷(想讓我寫來著,沒帶紙筆,口述了演算法思想和區別,遞迴和非遞迴)
● 圖瞭解嗎,說一說它的遍歷(廣度和深度)
回到C++
● 說說巨集定義和const的區別
——巨集定義是在預編譯階段完成的,不進行安全性檢查,直接替換
——const編譯階段完成,執行時會進行安全性檢查
● 巨集定義和行內函數的區別
——行內函數可以作為某個類的成員函式,這樣可以使用類的保護成員和私有成員。而當一個表示式涉及到類保護成員或私有成員時,巨集就不能實現了(無法將this指標放在合適位置)。
● 行內函數的作用,和普通函式有什麼區別
——
行內函數和普通函式的區別:
1、在編譯過程中,行內函數在函式的呼叫點,把函式程式碼全部展開,所以沒有標準函式的棧幀的開闢和回退。
(如果 呼叫函式的開銷 > 函式執行的開銷,那麼就建議寫為行內函數 )
呼叫的開銷:函式的棧幀的開闢和回退
執行的開銷:函式體內程式碼執行的開銷
2、行內函數只在本檔案可見,編譯階段就進行了替換,所以不產生符號,所以一般在標頭檔案中定義,這樣就可以在其它檔案呼叫。普通函式產生符號,多個檔案引用標頭檔案,會產生符號重定義的錯誤。
.編譯階段不編譯.h檔案,只編譯.c 或.cpp 檔案
● C++有幾種轉換方法,簡單介紹一下
——static_cast:靜態強制轉換,類似傳統c語言裡面括號的強制轉換
——dynamic_cast:動態強制轉換,主要應用於多型,父子類的型別轉換,dynamic_cast和static_cast不同的是,它會檢查型別轉換是否
正確,不能轉換,則會返回null,所以不算是強制轉換。
——const_cast:取出const屬性,比較簡單,可以把const型別轉換為非conse指標型別。
● 過載是什麼,和重寫有什麼區別
方法過載是指同一個類中的多個方法具有相同的名字,但這些方法具有不同的引數列表,即引數的數量或引數型別不能完全相同
方法重寫是存在子父類之間的,子類定義的方法與父類中的方法具有相同的方法名字,相同的引數表和相同的返回型別