2015網龍筆試題

網絡2016 校園招聘java 筆試題及答案



作者:張超紅
時間:20150920

說明:本試卷答案爲本人所做,

僅作爲參考,版本歸本人所有,嚴禁隨意外傳。




1.在32 位機器中,一下結構體佔多少字節()
Struct{
Char a;
Double b;
Int c;
Short d;
}
A.24 B.20 C.18 D.以上都不對
解釋:char 1 個字節,double 8 個字節,int 4 個字節,short 2 字節,long 4 個字節,float 4

個字節。


1.網絡協議採用()的方式來傳輸協議,在此字節序下從低地址到高地址0x12345678 的表
示形式爲()
A.big_endian ,0x78 56 34 12 B.big_endiam,0x12 34 56 78
C.little_endian,0x78 56 34 D.little_endian,0x12 34 56 78

解釋:所有網絡協議也都是採用big endian 的方式來傳輸數據的。


2.上網時發現網絡不能訪問,qq 正常,出現此問題的可能原因是()
A.網線問題B.IP 地址衝突C.IP 地址衝突DNS 問題D.網關錯誤
3.某系統中的一個組件的某個函數中,有一個變量沒有正確初始化,在()階段容易發現問

A.單元測試B.集成測試C.確認測試D.系統測試
解釋:單元測試的對象是軟件設計的最小單位——模塊。單元測試的依據是詳細設描述,單
元測試應對模塊內所有重要的控制路徑設計測試用例,以便發現模塊內部的錯誤。單元測試

多采用白盒測試技術,系統內多個模塊可以並行地進行測試。


4.棧的入棧序列是ABCDE,則棧的出棧序列不可能是()
A. DECBA B.ADEBC C.EDCBA D.ABCDE
解釋:棧的數據進出特點是先進後出,假定原先入棧次序爲1,2,3 的話,那麼不會出現出棧順序
爲312 的情況(課本上應該有描述),所以本題中的c 選項eabcd 是不對的.(因爲e a b 這種順

序是不可能的)


5.已知一棵二叉樹,如果先序遍歷的節點順序是ABDCGEF,中序遍歷是DBGAEF,那麼後
序遍歷爲()

A.CFHGEBDA B.CDFEGHBA C.DGCBEFA D.CFHGBA


6.執行以下語句的結果是()
Int a[2][3]={0,1,2,3,4,5};
Int *b=a[1];
*b=6;
B=a[0];
For(int i=0;i<6;++){
Printf(“%d”,b[i]);
}

A.0,1,2,3,4,5 B.0,6,2,3,4,5 C.0,1,2,6,4,5 D.編譯錯誤


7.進程調度是從()選擇一個進程投入運行

A.就緒隊列B.等待隊列C.作業後備隊列D.提交隊列


8.下列關於類和對象的敘述中,錯誤的是()
A.一個類只能有一個對象B.對象是類的具體實例
C.類是對某一類對象的抽象D.類和對象的關係是一種數據類型與變量的關係
解釋:只要類可以聲明對象那他就可以聲明多個對象。而且這些多個對象佔據不同的內存空
間。
另外new 對象就是在內存中分配空間存儲變量的一個過程,不只是你說的初始化,先分配

空間然後初始化,如果空間分配不出來就直接異常了。而且分配內存和賦值是一起完成的。


9.如果存在一個基本有序的序列,按照那種排序方式最快()
A.快速排序B.冒泡排序C.歸併排序D.插入排序
解釋:快速排序在一般情況下的時間複雜度爲O(nlogn),基本有序時,時間複雜度爲O(n*n);
冒泡排序;冒泡排序比較穩定,基本都是n*n(雖然沒有交換但是會比較),歸併排序也是比較

穩定的,時間複雜度爲O(nlogn);插入排序在基本有序的時候時間複雜度爲O(n),一般爲O(n)


10.在一個單鏈表中,已知指針q 指向的節點是指針p 指向的節點的前驅節點,若在q 和p
之間插入s 節點,則執行()
A.s->next=p->next; p->next=s; B.p->next=s->next ;s->next=p

C.q->next=s; s->next=p D.p->next=s; s->next=q


12. 25 匹馬,5 條賽道,一匹馬一個賽道,求決勝跑的最快的1,2,3 名至少需要多少場()

A.9 B.8 C.7 D.6


13.進程間的通信方式有()
A.管道B.信號量C.Socket D.互斥鎖
# 管道( pipe ):管道是一種半雙工的通信方式,數據只能單向流動,而且只能在具有親緣關
系的進程間使用。進程的親緣關係通常是指父子進程關係。
# 有名管道(named pipe) : 有名管道也是半雙工的通信方式,但是它允許無親緣關係進程
間的通信。
# 信號量( semophore ) : 信號量是一個計數器,可以用來控制多個進程對共享資源的訪問。
它常作爲一種鎖機制,防止某進程正在訪問共享資源時,其他進程也訪問該資源。因此,主
要作爲進程間以及同一進程內不同線程之間的同步手段。
# 消息隊列( message queue ) : 消息隊列是由消息的鏈表,存放在內核中並由消息隊列標
識符標識。消息隊列克服了信號傳遞信息少、管道只能承載無格式字節流以及緩衝區大小受
限等缺點。
# 信號( sinal ) : 信號是一種比較複雜的通信方式,用於通知接收進程某個事件已經發生。
# 共享內存( shared memory ) :共享內存就是映射一段能被其他進程所訪問的內存,這段共
享內存由一個進程創建,但多個進程都可以訪問。共享內存是最快的IPC 方式,它是針對
其他進程間通信方式運行效率低而專門設計的。它往往與其他通信機制,如信號兩,配合使
用,來實現進程間的同步和通信。
# 套接字( socket ) : 套解口也是一種進程間通信機制,與其他通信機制不同的是,它可用

於不同及其間的進程通信。


14.下面那些協議屬於TCP/IP 模型的傳輸層()

A.http B.pop3 C.tcp D.ipx E.udp F.hdlc


15.多線程同步機制包括()
A.Critical Section B.Semaphore C.Pipe D.Mutex
事件
1、Event
用事件(Event)來同步線程是最具彈性的了。一個事件有兩種狀態:激發狀態和未激
髮狀態。也稱有信號狀態和無信號狀態。事件又分兩種類型:手動重置事件和自動重置事件。
手動重置事件被設置爲激發狀態後,會喚醒所有等待的線程,而且一直保持爲激發狀態,直
到程序重新把它設置爲未激發狀態。自動重置事件被設置爲激發狀態後,會喚醒“一個”等待
中的線程,然後自動恢復爲未激發狀態。所以用自動重置事件來同步兩個線程比較理想。
MFC 中對應的類爲CEvent.。CEvent 的構造函數默認創建一個自動重置的事件,而且處於
未激發狀態。共有三個函數來改變事件的狀態:SetEvent,ResetEvent 和PulseEvent。用事
件來同步線程是一種比較理想的做法,但在實際的使用過程中要注意的是,對自動重置事件
調用SetEvent 和PulseEvent 有可能會引起死鎖,必須小心。
多線程同步-event
在所有的內核對象中,事件內核對象是個最基本的。它包含一個使用計數(與所有內核
對象一樣),一個BOOL 值(用於指明該事件是個自動重置的事件還是一個人工重置的事件),
還有一個BOOL 值(用於指明該事件處於已通知狀態還是未通知狀態)。事件能夠通知一個線
程的操作已經完成。有兩種類型的事件對象。一種是人工重置事件,另一種是自動重置事件。
他們不同的地方在於:當人工重置的事件得到通知時,等待該事件的所有線程均變爲可調度
線程。當一個自動重置的事件得到通知時,等待該事件的線程中只有一個線程變爲可調度線
程。
當一個線程執行初始化操作,然後通知另一個線程執行剩餘的操作時,事件使用得最頻
繁。在這種情況下,事件初始化爲未通知狀態,然後,當該線程完成它的初始化操作後,它
就將事件設置爲已通知狀態,而一直在等待該事件的另一個線程在事件已經被通知後,就變
成可調度線程。
當這個進程啓動時,它創建一個人工重置的未通知狀態的事件,並且將句柄保存在一個
全局變量中。這使得該進程中的其他線程能夠非常容易地訪問同一個事件對象。程序一開始
創建了三個線程,這些線程在初始化後就被掛起,等待事件。這些線程要等待文件的內容讀
入內存,然後每個線程都會訪問這段文件內容。一個線程進行單詞計數,另一個線程運行拼
寫檢查,第三個線程運行語法檢查。這3 個線程函數的代碼的開始部分都相同,每個函數
都調用WaitForSingleObject.,這將使線程暫停運行,直到文件的內容由主線程讀入內存爲
止。一旦主線程將數據準備好,它就調用SetEvent,給事件發出通知信號。這時,系統就
使所有這3 個輔助線程進入可調度狀態,它們都獲得了C P U 時間,並且可以訪問內存塊。
這3 個線程都必須以只讀方式訪問內存,否則會出現內存錯誤。這就是所有3 個線程能夠同
時運行的唯一原因。如果計算機上配有三個以上CPU,理論上這個3 個線程能夠真正地同
時運行,從而可以在很短的時間內完成大量的操作
如果你使用自動重置的事件而不是人工重置的事件,那麼應用程序的行爲特性就有很大
的差別。當主線程調用S e t E v e n t 之後,系統只允許一個輔助線程變成可調度狀態。同
樣,也無法保證系統將使哪個線程變爲可調度狀態。其餘兩個輔助線程將繼續等待。已經變
爲可調度狀態的線程擁有對內存塊的獨佔訪問權。
讓我們重新編寫線程的函數,使得每個函數在返回前調用S e t E v e n t 函數(就像
Wi n M a i n 函數所做的那樣)。
當主線程將文件內容讀入內存後,它就調用SetEvent 函數,這樣操作系統就會使這三
個在等待的線程中的一個成爲可調度線程。我們不知道系統將首先選擇哪個線程作爲可調度
線程。當該線程完成操作時,它也將調用S e t E v e n t 函數,使下一個被調度。這樣,三
個線程會以先後順序執行,至於什麼順序,那是操作系統決定的。所以,就算每個輔助線程
均以讀/寫方式訪問內存塊,也不會產生任何問題,這些線程將不再被要求將數據視爲只讀
數據。
這個例子清楚地展示出使用人工重置事件與自動重置事件之間的差別。
P u l s e E v e n t 函數使得事件變爲已通知狀態,然後立即又變爲未通知狀態,這就像
在調用S e t E v e n t 後又立即調用R e s e t E v e n t 函數一樣。如果在人工重置的事件上
調用P u l s e E v e n t 函數,那麼在發出該事件時,等待該事件的任何一個線程或所有線
程將變爲可調度線程。如果在自動重置事件上調用P u l s e E v e n t 函數,那麼只有一個
等待該事件的線程變爲可調度線程。如果在發出事件時沒有任何線程在等待該事件,那麼將
不起任何作用[2] 。
臨界區
2、Critical Section
使用臨界區域的第一個忠告就是不要長時間鎖住一份資源。這裏的長時間是相對的,視
不同程序而定。對一些控制軟件來說,可能是數毫秒,但是對另外一些程序來說,可以長達
數分鐘。但進入臨界區後必須儘快地離開,釋放資源。如果不釋放的話,會如何?答案是不
會怎樣。如果是主線程(GUI 線程)要進入一個沒有被釋放的臨界區,呵呵,程序就會掛了!
臨界區域的一個缺點就是:Critical Section 不是一個核心對象,無法獲知進入臨界區的線程
是生是死,如果進入臨界區的線程掛了,沒有釋放臨界資源,系統無法獲知,而且沒有辦法
釋放該臨界資源。這個缺點在互斥器(Mutex)中得到了彌補。Critical Section 在MFC 中的相
應實現類是CcriticalSection。CcriticalSection::Lock()進入臨界區,CcriticalSection::
UnLock()離開臨界區。
互斥器
3、Mutex
互斥器的功能和臨界區域很相似。區別是:Mutex 所花費的時間比Critical Section 多
的多,但是Mutex 是核心對象(Event、Semaphore 也是),可以跨進程使用,而且等待一個
被鎖住的Mutex 可以設定TIMEOUT,不會像Critical Section 那樣無法得知臨界區域的情
況,而一直死等。MFC 中的對應類爲CMutex。Win32 函數有:創建互斥體CreateMutex() ,
打開互斥體OpenMutex(),釋放互斥體ReleaseMutex()。Mutex 的擁有權並非屬於那個產
生它的線程,而是最後那個對此Mutex 進行等待操作(WaitForSingleObject 等等)並且尚
未進行ReleaseMutex()操作的線程。線程擁有Mutex 就好像進入Critical Section 一樣,一
次只能有一個線程擁有該Mutex。如果一個擁有Mutex 的線程在返回之前沒有調用
ReleaseMutex(),那麼這個Mutex 就被捨棄了,但是當其他線程等待(WaitForSingleObject
等)這個Mutex 時,仍能返回,並得到一個WAIT_ABANDONED_0 返回值。能夠知道一個
Mutex 被捨棄是Mutex 特有的。
信號量
4、Semaphore
信號量是最具歷史的同步機制。信號量是解決producer/consumer 問題的關鍵要素。
對應的MFC 類是Csemaphore。Win32 函數CreateSemaphore()用來產生信號量。
ReleaseSemaphore()用來解除鎖定。Semaphore 的現值代表的意義是可用的資源數,
如果Semaphore 的現值爲1,表示還有一個鎖定動作可以成功。如果現值爲5,就表示還
有五個鎖定動作可以成功。當調用Wait…等函數要求鎖定,如果Semaphore 現值不爲0,
Wait…馬上返回,資源數減1。當調用ReleaseSemaphore()資源數加1,當然不會超過

初始設定的資源總數。


16.請寫出下面二叉樹的後序遍歷節點順序:DFGEBIHCA


17.linux 進程的三種狀態(可執行狀態)(可中斷的睡眠狀態)(不可中斷的睡眠狀態)
1.R (TASK_RUNNING)狀態,可執行狀態。
只有在該狀態的進程纔可能在CPU 上運行。而同一時刻可能有多個進程處於可執行狀態,這
些進程的task_struct 結構(進程控制塊)被放入對應CPU 的可執行隊列中(一個進程最多
只能出現在一個CPU 的可執行隊列中)。進程調度器的任務就是從各個CPU 的可執行隊列中
分別選擇一個進程在該CPU 上運行。
很多操作系統教科書將正在CPU 上執行的進程定義爲RUNNING 狀態、而將可執行但是尚未被
調度執行的進程定義爲READY 狀態,這兩種狀態在linux 下統一爲TASK_RUNNING 狀態。
2.S (TASK_INTERRUPTIBLE)狀態,可中斷的睡眠狀態。
處於這個狀態的進程因爲等待某某事件的發生(比如等待socket 連接、等待信號量),而
被掛起。這些進程的task_struct 結構被放入對應事件的等待隊列中。當這些事件發生時(由
外部中斷觸發、或由其他進程觸發),對應的等待隊列中的一個或多個進程將被喚醒。
通過ps 命令我們會看到,一般情況下,進程列表中的絕大多數進程都處於
TASK_INTERRUPTIBLE 狀態(除非機器的負載很高)。畢竟CPU 就這麼一兩個,進程動輒幾
十上百個,如果不是絕大多數進程都在睡眠,CPU 又怎麼響應得過來。
3.D (TASK_UNINTERRUPTIBLE)狀態,不可中斷的睡眠狀態。
與TASK_INTERRUPTIBLE 狀態類似,進程處於睡眠狀態,但是此刻進程是不可中斷的。不可
中斷,指的並不是CPU 不響應外部硬件的中斷,而是指進程不響應異步信號。
絕大多數情況下,進程處在睡眠狀態時,總是應該能夠響應異步信號的。否則你將驚奇的發
現,kill -9 竟然殺不死一個正在睡眠的進程了!於是我們也很好理解,爲什麼ps 命令看
到的進程幾乎不會出現TASK_UNINTERRUPTIBLE 狀態,而總是TASK_INTERRUPTIBLE 狀態。
而TASK_UNINTERRUPTIBLE 狀態存在的意義就在於,內核的某些處理流程是不能被打斷的。
如果響應異步信號,程序的執行流程中就會被插入一段用於處理異步信號的流程(這個插入
的流程可能只存在於內核態,也可能延伸到用戶態),於是原有的流程就被中斷了。在進程
對某些硬件進行操作時(比如進程調用read 系統調用對某個設備文件進行讀操作,而read
系統調用最終執行到對應設備驅動的代碼,並與對應的物理設備進行交互),可能需要使用
TASK_UNINTERRUPTIBLE 狀態對進程進行保護,以避免進程與設備交互的過程被打斷,造成
設備陷入不可控的狀態。這種情況下的TASK_UNINTERRUPTIBLE 狀態總是非常短暫的,通過
ps 命令基本上不可能捕捉到。
linux 系統中也存在容易捕捉的TASK_UNINTERRUPTIBLE 狀態。執行vfork 系統調用後,父

進程將進入TASK_UNINTERRUPTIBLE 狀態,直到子進程調用exit 或exec


18.瀏覽器訪問某頁面,http 返回狀態碼爲403 表示(資源不可用。服務器理解客戶的請求,
但拒絕處理它。通常由於服務器上文件或目錄的權限設置導致。禁止訪問:IIS 定義了許多

不同的403 錯誤,它們指明更爲具體的錯誤原因)


19.快速排序法在序列已經有序的情況下的複雜度是(O(n*n))
編程題
1.給定一個序列,取出其中第二大的數,要求不對整個序列排序
package JAVA 語言基礎筆試題3;
/**
*
* @author 超紅謹防假冒
*/
public class 找出第二大的數{
public static void main(String[] args) {
int arr[] = { 1, 12, 32, 423, 1, 232, 111 };
GetSecondMaxNumber(arr, 7);
}
/**
* 思路:如果當前元素大於最大數max,則讓第二大數等於原來的最大數max,
* 再把當前元素的值賦給
* max。如果當前的元素大於等於第二大數secondMax 的值而小於最大數max 的
* 值,則要把當前元素的值賦給secondMax。
*
* @param arr
* @param n
*/
static void GetSecondMaxNumber(int[] arr, int n) {
int i, max, second_max;
max = arr[0];
second_max = 0x80000000;
System.out.println("start");
for (i = 1; i < n; ++i) {
if (arr[i] > max) {
second_max = max;
max = arr[i];
} else if (arr[i] <= max && arr[i] >= second_max) {
second_max = arr[i];
}
}
System.out.println("第二大的數:" + second_max);
}
}
2.太簡單的題目,在此不屑
3.給你一個單詞a,如果通過交換單詞中字母的順序可以得到另外的單詞b,那麼單詞a 是單
詞b 的兄弟單詞,現在給你一個字典,用戶輸入一個單詞,讓你根據字典找出有多少個兄弟
單詞。請給出算法思路和代碼實現。
思路:首先用全排列方法寫出該單詞的所有可能兄弟單詞。如army 有4×3×2×1=24 種結
果(還沒有優化有相同字符或大寫字母的情況),然後用每一個'兄弟單詞'去和字典中的單詞匹
配,找到即爲兄弟單詞。下面給出全排列算法的代碼,最直接的就是用遞歸了:
將字典中的和‘比較單詞’首字母相同的單詞取出存放到一個數組中,將每一個組合和字典
中的單詞比較。首先比較單詞長度,長度相同,則繼續比較;否則,比較下一個單詞。算法
如下:
package JAVA 語言基礎筆試題3;
/**
*
* @author 超紅謹防假冒
* :首先用全排列方法寫出該單詞的所有可能兄弟單詞。
* 如army 有4×3×2×1=24 種結果(還沒有優化有相同字符或大寫字母的情況
* ),然後用每一個'兄弟單詞'去和字典中的單詞匹配,找到即爲兄弟單詞。
* 下面給出全排列算法的代碼,最直接的就是用遞歸了:
*
* 將字典中的和‘比較單詞’首字母相同的單詞取出存放到一個數組中,
* 將每一個組合和字典中的單詞比較。首先比較單詞長度,長度相同,則繼
續比較;否則
* ,比較下一個單詞。算法
*/
public class 查找兄弟單詞{
/**
* @param src
* @param start
* 起始位置索引
* @param end
* 結束位置索引
*/
public static void perm(String[] src, int start, int end) {
if (start == end) {
// 當只要求對數組中一個字母進行全排列時,只要按該數組輸出即可
for (int i = 0; i <= end; i++) {
System.out.print(src[i]);
}
System.out.println();
} else {
// 多個字母全排列
for (int i = start; i <= end; i++) {
String temp = src[start];
// 交換數組第一個元素與後續的元素
src[start] = src[i];
src[i] = temp;
perm(src, start + 1, end);
// 後續元素遞歸全排列
temp = src[start];
// 將交換後的數組還原
src[start] = src[i];
src[i] = temp;
}
}
}
/**
* @param src
* 字典中的單詞
* @param des
* 要比較的單詞,因爲要做大量比較,所以轉化爲字符數組
* @return
*/
public static boolean compare(String src, String[] des) {
int len = src.length();
if (len != des.length) {
// 如果長度不相等,肯定不是兄弟單詞,則無需比較
return false;
}
int i = 1;
// i 等於1 是因爲首字符已經相同,無需比較
while (i < len) {
if (des[i].equals(String.valueOf(src.charAt(i)))) {
i++;
continue;
}
return false;
}
return true;
}
}
4.通過鍵盤輸入一串小寫字母(a~z)組成的字符串。請編寫一個字符串壓縮程序,將字符串中
連續出席的重複字母進行壓縮,並輸出壓縮後的字符串。
壓縮規則:
1、僅壓縮連續重複出現的字符。比如字符串"abcbc"由於無連續重複字符,壓縮後的字符串
還是"abcbc"。
2、壓縮字段的格式爲"字符重複的次數+字符"。例如:字符串"xxxyyyyyyz"壓縮後就成爲
"3x6yz"。
package JAVA 語言基礎筆試題3;
/**
*
* @author 超紅
* 謹防假冒
*/
public class 字符串壓縮{
public static void main(String[] args) {
String str="xxxyyyyyyz";
System.out.println(condense(str));
}
public static String condense(String str) {
char[] c = str.toCharArray();
//形成新的字符串
StringBuilder res = new StringBuilder();
int count = 1;// 記錄重複的次數
char c1;
int length = c.length;
for (int i = 0; i < length; i++) {
c1 = c[i];
if (i < length - 1) {
if (c[i + 1] == c[i]) {
count++;
if (i != length - 2) {
continue;
}
}
if (count > 1) {
res.append(count).append(c1);
count = 1;// 上一次重複字母統計結束,計數器歸爲初始值
} else {
res.append(c[i]);
}
} else {
if (c[i] != c[i - 1]) {
res.append(c[i]);
}
}
}
return res.toString();
}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章