Java數據結構面試題

1.棧和隊列的共同特色是(只容許在端點處插入和刪除元素)
4.棧一般採用的兩種存儲結構是(線性存儲結構和鏈表存儲結構)
5.下列關於棧的敘述正確的是(D)
     A.棧是非線性結構B.棧是一種樹狀結構C.棧具備先進先出的特徵D.棧有後進先出的特徵
6.鏈表不具備的特色是(B)A.沒必要事先估計存儲空間       B.可隨機訪問任一元素
C.插入刪除不須要移動元素      D.所需空間與線性表長度成正比
7.用鏈表表示線性表的優勢是(便於插入和刪除操做)
8.在單鏈表中,增長頭結點的目的是(方便運算的實現)
9.循環鏈表的主要優勢是(從表中任一結點出發都能訪問到整個鏈表)
10.線性表L=(a1,a2,a3,……ai,……an),下列說法正確的是(D)
     A.每一個元素都有一個直接前件和直接後件   B.線性表中至少要有一個元素
     C.表中諸元素的排列順序必須是由小到大或由大到小
     D.除第一個和最後一個元素外,其他每一個元素都有一個且只有一個直接前件和直接後件
11.線性表若採用鏈式存儲結構時,要求內存中可用存儲單元的地址(D)
A.必須是連續的 B.部分地址必須是連續的C.必定是不連續的 D.連續不連續均可以
12.線性表的順序存儲結構和線性表的鏈式存儲結構分別是(隨機存取的存儲結構、順序存取的存儲結構)
13.樹是結點的集合,它的根結點數目是(有且只有1)
14.在深度爲5的滿二叉樹中,葉子結點的個數爲(31)
15.具備3個結點的二叉樹有(5種形態)
16.設一棵二叉樹中有3個葉子結點,有8個度爲1的結點,則該二叉樹中總的結點數爲(13)
17.已知二叉樹後序遍歷序列是dabec,中序遍歷序列是debac,它的前序遍歷序列是(cedba)
18.已知一棵二叉樹前序遍歷和中序遍歷分別爲ABDEGCFH和DBGEACHF,則該二叉樹的後序遍歷爲(DGEBHFCA)
19.若某二叉樹的前序遍歷訪問順序是abdgcefh,中序遍歷訪問順序是dgbaechf,則其後序遍歷的結點訪問順序是(gdbehfca)
20.數據庫保護分爲:安全性控制、 完整性控制 、併發性控制和數據的恢復。
1. 在計算機中,算法是指(解題方案的準確而完整的描述)
2.在下列選項中,哪一個不是一個算法通常應該具備的基本特徵(無窮性)
說明:算法的四個基本特徵是:可行性、肯定性、有窮性和擁有足夠的情報。
3. 算法通常均可以用哪幾種控制結構組合而成(順序、選擇、循環)
4.算法的時間複雜度是指(算法執行過程當中所須要的基本運算次數)
5. 算法的空間複雜度是指(執行過程當中所須要的存儲空間)
6. 算法分析的目的是(分析算法的效率以求改進)
7. 下列敘述正確的是(C)
A.算法的執行效率與數據的存儲結構無關
B.算法的空間複雜度是指算法程序中指令(或語句)的條數
C.算法的有窮性是指算法必須能在執行有限個步驟以後終止
D.算法的時間複雜度是指執行算法程序所須要的時間
8.數據結構做爲計算機的一門學科,主要研究數據的邏輯結構、對各類數據結構進行的運算,以及(數據的存儲結構)
9. 數據結構中,與所使用的計算機無關的是數據的(C)
A.存儲結構   B.物理結構     C.邏輯結構     D.物理和存儲結構
10. 下列敘述中,錯誤的是(B)
A.數據的存儲結構與數據處理的效率密切相關
B.數據的存儲結構與數據處理的效率無關
C.數據的存儲結構在計算機中所佔的空間不必定是連續的
D.一種數據的邏輯結構能夠有多種存儲結構
11. 數據的存儲結構是指(數據的邏輯結構在計算機中的表示)
12. 數據的邏輯結構是指(反映數據元素之間邏輯關係的數據結構)
13. 根據數據結構中各數據元素之間先後件關係的複雜程度,通常將數據結構分爲(線性結構和非線性結構)
14. 下列數據結構具備記憶功能的是(C)A.隊列B.循環隊列C.棧D.順序表
15. 下列數據結構中,按先進後出原則組織數據的是(B)
A.線性鏈表   B.棧            C.循環鏈表        D.順序表
16. 遞歸算法通常須要利用(隊列)實現。
17. 下列關於棧的敘述中正確的是(D)A.在棧中只能插入數據B.在棧中只能刪除數據
C.棧是先進先出的線性表            D.棧是先進後出的線性表
20. 由兩個棧共享一個存儲空間的好處是(節省存儲空間,下降上溢發生的機率)
21. 應用程序在執行過程當中,須要經過打印機輸出數據時,通常先造成一個打印做業,將其存放在硬盤中的一個指定(隊列)中,當打印機空閒時,就會按先來先服務的方式從中取出待打印的做業進行打印。
22.下列關於隊列的敘述中正確的是(C)A.在隊列中只能插入數據 B.在隊列中只能刪除數據   C.隊列是先進先出的線性表            D.隊列是先進後出的線性表
23.下列敘述中,正確的是(D)A.線性鏈表中的各元素在存儲空間中的位置必須是連續的
B.線性鏈表中的表頭元素必定存儲在其餘元素的前面 C.線性鏈表中的各元素在存儲空間中的位置不必定是連續的,但表頭元素必定存儲在其餘元素的前面 D.線性鏈表中的各元素在存儲空間中的位置不必定是連續的,且各元素的存儲順序也是任意的
24.下列敘述中正確的是(A)A.線性表是線性結構      B.棧與隊列是非線性結構
C.線性鏈表是非線性結構                                 D.二叉樹是線性結構
25. 線性表L=(a1,a2,a3,……ai,……an),下列說法正確的是(D)
A.每一個元素都有一個直接前件和直接後件      B.線性表中至少要有一個元素
C.表中諸元素的排列順序必須是由小到大或由大到小D.除第一個元素和最後一個元素外,其他每一個元素都有一個且只有一個直接前件和直接後件
26.線性表若採用鏈式存儲結構時,要求內存中可用存儲單元的地址(連續不連續均可以)
27. 鏈表不具備的特色是(B)A.沒必要事先估計存儲空間            B.可隨機訪問任一元素
C.插入刪除不須要移動元素            D.所需空間與線性表長度成正比
28. 非空的循環單鏈表head的尾結點(由p所指向),知足(p->next=head)
29.與單向鏈表相比,雙向鏈表的優勢之一是(更容易訪問相鄰結點)
30. 在(D)中,只要指出表中任何一個結點的位置,就能夠從它出發依次訪問到表中其餘全部結點。A.線性單鏈表            B.雙向鏈表            C.線性鏈表            D.循環鏈表
31. 如下數據結構屬於非線性數據結構的是(C)A.隊列      B.線性表C.二叉樹      D.棧
32.樹是結點的集合,它的根結點數目是(有且只有1)
33.具備3個結點的二叉樹有(5種形態)
34. 在一棵二叉樹上第8層的結點數最可能是(128) 注:2K-1
35. 在深度爲5的滿二叉樹中,葉子結點的個數爲(16) 注:2n-1
36. 在深度爲5的滿二叉樹中,共有(31)個結點。 注:2n-1
37.設一棵徹底二叉樹共有699個結點,則在該二叉樹中的葉子結點數爲(350)
說明:徹底二叉樹總結點數爲N,若N爲奇數,則葉子結點數爲(N+1)/2;若N爲偶數,則葉子結點數爲N/2。
38. 設有下列二叉樹,對此二叉樹中序遍歷的結果是(B)
A.ABCDEF     
B.DBEAFC
C.ABDECF     
D.DEBFCA
39.已知二叉樹後序遍歷序列是dabec,中序遍歷序列debac,它的前序遍歷序列是(cedba)
40. 已知一棵二叉樹前序遍歷和中序遍歷分別爲ABDEGCFH和DBGEACHF,則該二叉樹的後序遍歷爲(DGEBHFCA)
41.若某二叉樹的前序遍歷訪問順序是abdgcefh,中序遍歷訪問順序是dgbaechf,則其後序遍歷的結點訪問順序是(gdbehfca)
42. 串的長度是(串中所含字符的個數) 
43.設有兩個串p和q,求q在p中首次出現位置的運算稱作(模式匹配)
44. N個頂點的連通圖中邊的條數至少爲(N-1)
45.N個頂點的強連通圖的邊數至少有(N)
46.對長度爲n的線性表進行順序查找,在最壞狀況下所須要的比較次數爲(N)
47. 最簡單的交換排序方法是(冒泡排序)
48.假設線性表的長度爲n,則在最壞狀況下,冒泡排序須要的比較次數爲(n(n-1)/2)
49. 在待排序的元素序列基本有序的前提下,效率最高的排序方法是(冒泡排序)
50. 在最壞狀況下,下列順序方法中時間複雜度最小的是(堆排序)
51. 希爾排序法屬於(插入類排序)
52. 堆排序法屬於(選擇類排序)
53. 在下列幾種排序方法中,要求內存量最大的是(歸併排序)
54. 已知數據表A中每一個元素距其最終位置不遠,爲節省時間,應採用(直接插入排序)
55. 算法的基本特徵是可行性、肯定性、 有窮性   和擁有足夠的情報。
1.一個算法一般由兩種基本要素組成:一是對數據對象的運算和操做,二是算法的控制結構。
1. 算法的複雜度主要包括時間複雜度和 空間 複雜度。
2. 實現算法所需的存儲單元多少和算法的工做量大小分別稱爲算法的空間複雜度和時間複雜度 。
3.所謂數據處理是指對數據集合中的各元素以各類方式進行運算,包括插入、刪除、查找、更改等運算,也包括對數據元素進行分析。
4.數據結構是指相互有關聯的 數據元素 的集合。
5.數據結構分爲邏輯結構與存儲結構,線性鏈表屬於 存儲結構 。
6.數據結構包括數據的 邏輯 結構和數據的存儲結構。
7. 數據結構包括數據的邏輯結構、數據的 存儲結構 以及對數據的操做運算。
8.數據元素之間的任何關係均可以用 前趨和後繼 關係來描述。
9.數據的邏輯結構有線性結構和非線性結構兩大類。
10.經常使用的存儲結構有順序、連接、 索引 等存儲結構。
11. 順序存儲方法是把邏輯上相鄰的結點存儲在物理位置   相鄰 的存儲單元中。
12. 棧的基本運算有三種:入棧、退棧與讀棧頂元素 。
13. 隊列主要有兩種基本運算:入隊運算與 退隊運算 。
14. 在實際應用中,帶鏈的棧能夠用來收集計算機存儲空間中全部空閒的存儲結點,這種帶鏈的棧稱爲 可利用棧 。
15.棧和隊列一般採用的存儲結構是 鏈式存儲和順序存儲   。
16.當線性表採用順序存儲結構實現存儲時,其主要特色是 邏輯結構中相鄰的結點在存儲結構中仍相鄰 。
17. 循環隊列主要有兩種基本運算:入隊運算與退隊運算。每進行一次入隊運算,隊尾指針就 進1 。
18.當循環隊列非空且隊尾指針等於對頭指針時,說明循環隊列已滿,不能進行入隊運算。這種狀況稱爲 上溢   。
19.當循環隊列爲空時,不能進行退隊運算,這種狀況稱爲 下溢 。
20. 在一個容量爲25的循環隊列中,若頭指針front=16,尾指針rear=9,則該循環隊列中共有 18 個元素。注:當rear<front時,元素個數=總容量-(front-rear);
當rear>front時,元素個數=rear-front。
1.判斷鏈表是否存在環型鏈表問題:判斷一個鏈表是否存在環,例以下面這個鏈表就存在一個環:
例如N1->N2->N3->N4->N5->N2就是一個有環的鏈表,環的開始結點是N5這裏有一個比較簡單的解法。設置兩個指針p1,p2。每次循環p1向前走一步,p2向前走兩步。直到p2碰到NULL指針或者兩個指針相等結束循環。若是兩個指針相等則說明存在環。
struct link 
{
        int data;
         link* next;
};
 
bool IsLoop(link* head)
{
         link* p1=head, *p2 = head;
          if (head ==NULL || head->next ==NULL) 
          {
                    return false;
          }
         do{
             p1= p1->next;
             p2 = p2->next->next;
         } while(p2 && p2->next && p1!=p2);          
          if(p1 == p2)
                    return true;
          else
                    return false;
}
2,鏈表反轉 單向鏈表的反轉是一個常常被問到的一個面試題,也是一個很是基礎的問題。好比一個鏈表是這樣的: 1->2->3->4->5 經過反轉後成爲5->4->3->2->1。最容易想到的方法遍歷一遍鏈表,利用一個輔助指針,存儲遍歷過程當中當前指針指向的下一個元素,而後將當前節點元素的指針反轉後,利用已經存儲的指針日後面繼續遍歷。源代碼以下: 
struct linka {
          int data;
          linka* next;
};
 
void reverse(linka*& head)
{
          if(head ==NULL)
               return;
          linka*pre, *cur, *ne;
          pre=head;
          cur=head->next;
          while(cur)
          {
               ne = cur->next;
               cur->next = pre;
               pre = cur;
               cur = ne;
          }
          head->next = NULL;
          head = pre;
}
還有一種利用遞歸的方法。這種方法的基本思想是在反轉當前節點以前先調用遞歸函數反轉後續節點。源代碼以下。不過這個方法有一個缺點,就是在反轉後的最後一個結點會造成一個環,因此必須將函數的返回的節點的next域置爲NULL。由於要改變head指針,因此我用了引用。算法的源代碼以下: 
linka* reverse(linka* p,linka*& head)
{
          if(p == NULL || p->next == NULL)
          {
               head=p;
               return p;
          }
          else
          {
               linka* tmp = reverse(p->next,head);
               tmp->next = p;
               return p;
          }
}
3,判斷兩個數組中是否存在相同的數字 給定兩個排好序的數組,怎樣高效得判斷這兩個數組中存在相同的數字?
這個問題首先想到的是一個O(nlogn)的算法。就是任意挑選一個數組,遍歷這個數組的全部元素,遍歷過程當中,在另外一個數組中對第一個數組中的每一個元素進行binary search。用C++實現代碼以下:
bool findcommon(int a[],int size1,int b[],int size2)
{
          int i;
          for(i=0;i<size1;i++)
          {
               int start=0,end=size2-1,mid;
               while(start<=end)
               {
                    mid=(start+end)/2;
                    if(a[i]==b[mid])
                         return true;
                    else if (a[i]<b[mid])
                         end=mid-1;
                    else
                         start=mid+1;
               }
          }
          return false;
}
後來發現有一個 O(n)算法。由於兩個數組都是排好序的。因此只要一次遍歷就好了。首先設兩個下標,分別初始化爲兩個數組的起始地址,依次向前推動。推動的規則是比較兩個數組中的數字,小的那個數組的下標向前推動一步,直到任何一個數組的下標到達數組末尾時,若是這時還沒碰到相同的數字,說明數組中沒有相同的數字。 
bool findcommon2(int a[], int size1, int b[], int size2)
{
          int i=0,j=0;
          while(i<size1 && j<size2)
          {
               if(a[i]==b[j])
                         return true;
               if(a[i]>b[j])
                    j++;
               if(a[i]<b[j])
                    i++;
          }
          return false;
}
4,最大子序列 問題:
給定一整數序列A1, A2,... An (可能有負數),求A1~An的一個子序列Ai~Aj,使得Ai到Aj的和最大
例如:
整數序列-2, 11, -4, 13, -5, 2, -5, -3, 12, -9的最大子序列的和爲21。
對於這個問題,最簡單也是最容易想到的那就是窮舉全部子序列的方法。利用三重循環,依次求出全部子序列的和而後取最大的那個。固然算法複雜度會達到O(n^3)。顯然這種方法不是最優的,下面給出一個算法複雜度爲O(n)的線性算法實現,算法的來源於Programming Pearls一書。 在給出線性算法以前,先來看一個對窮舉算法進行優化的算法,它的算法複雜度爲O(n^2)。其實這個算法只是對對窮舉算法稍微作了一些修改:其實子序列的和咱們並不須要每次都從新計算一遍。假設Sum(i, j)是A[i] ... A[j]的和,那麼Sum(i, j+1) = Sum(i, j) + A[j+1]。利用這一個遞推,咱們就能夠獲得下面這個算法:
int max_sub(int a[],int size)
{
          int i,j,v,max=a[0];
          for(i=0;i<size;i++)
          {
               v=0;
               for(j=i;j<size;j++)
               {
                    v=v+a[j];//Sum(i, j+1) = Sum(i, j) + A[j+1]
                    if(v>max)
                         max=v;
               }
          }
          return max;
}
那怎樣才能達到線性複雜度呢?這裏運用動態規劃的思想。先看一下源代碼實現: 
int max_sub2(int a[], int size)
{
          int i,max=0,temp_sum=0;
          for(i=0;i<size;i++)
          {
               temp_sum+=a[i];
               if(temp_sum>max)
                    max=temp_sum;
               else if(temp_sum<0)
                    temp_sum=0;
          }
          return max;
}
 
6,按單詞反轉字符串  並非簡單的字符串反轉,而是按給定字符串裏的單詞將字符串倒轉過來,就是說字符串裏面的單詞仍是保持原來的順序,這裏的每一個單詞用空格分開。例如:

Here is www.fishksy.com.cn

通過反轉後變爲:

www.fishksy.com.cn is Here

若是隻是簡單的將全部字符串翻轉的話,能夠遍歷字符串,將第一個字符和最後一個交換,第二個和倒數第二個交換,依次循環。其實按照單詞反轉的話能夠在第一遍遍歷的基礎上,再遍歷一遍字符串,對每個單詞再反轉一次。這樣每一個單詞又恢復了原來的順序。
char* reverse_word(const char* str)
{
           int len = strlen(str);
           char* restr = new char[len+1];
           strcpy(restr,str);
           int i,j;
           for(i=0,j=len-1;i<j;i++,j--)
           {
                char temp=restr[i];
                restr[i]=restr[j];
                restr[j]=temp;
           }
           int k=0;
           while(k<len)
           {
                i=j=k;
                while(restr[j]!=' ' && restr[j]!='' )
                     j++;
                k=j+1;
                j--;
                for(;i<j;i++,j--)
                {
                     char temp=restr[i];
                     restr[i]=restr[j];
                     restr[j]=temp;
                }
           }
           return restr;
}
若是考慮空間和時間的優化的話,固然能夠將上面代碼裏兩個字符串交換部分改成異或實現。

例如將
                char temp=restr[i];
                restr[i]=restr[j];
                restr[j]=temp;
改成
                restr[i]^=restr[j];
                      restr[j]^=restr[i];
                restr[i]^=restr[j];
 
7,字符串反轉  我沒有記錯的話是一道MSN的筆試題,網上無心中看到的,拿來作了一下。題目是這樣的,給定一個字符串,一個這個字符串的子串,將第一個字符串反轉,但保留子串的順序不變。例如:

輸入:第一個字符串: "This is fishsky 's Chinese site: http://www.fishsky.com.cn/cn"

子串: "fishsky"

輸出: "nc/nc.moc.fishsky.www//:ptth :etis esenihC s'fishsky si sihT"

通常的方法是先掃描一邊第一個字符串,而後用stack把它反轉,同時記錄下子串出現的位置。而後再掃描一遍把記錄下來的子串再用stack反轉。我用的方法是用一遍掃描數組的方法。掃描中若是發現子串,就將子串倒過來壓入堆棧。

最後再將堆棧裏的字符彈出,這樣子串又恢復了原來的順序。源代碼以下:
#include <iostream>
#include <cassert>
#include <stack>
using namespace std;
//reverse the string 's1' except the substring 'token'.
const char* reverse(const char* s1, const char* token)
{
             assert(s1 && token);
             stack<char> stack1;
             const char* ptoken = token, *head = s1, *rear = s1;
             while (*head != '')
             {
                          while(*head!= '' && *ptoken == *head)
                          {
                             ptoken++;
                             head++;
                          }
                          if(*ptoken == '')//contain the token
                          {
                             const char* p;
                             for(p=head-1;p>=rear;p--)
                                          stack1.push(*p);
 
                             ptoken = token;
                             rear = head;
                          }
                          else
                          {
                             stack1.push(*rear);
                                   head=++rear;
                             ptoken = token;
                          }
             }
             char * return_v = new char[strlen(s1)+1];
             int i=0;
             while(!stack1.empty())
             {
                          return_v[i++] = stack1.top();
                          stack1.pop();
             }
             return_v[i]='';
             return return_v;
}
int main(int argc, char* argv[])
{cout<<"This is fishsky 's Chinese site: http://www.fishsky.com.cn/cn
";
             cout<<reverse("This is fishsky's Chinese site: http://www. fishsky.com.cn/cn"," fishsky ");
             return 0;
}
 8, 刪除數組中重複的數字  問題:一個動態長度可變的數字序列,以數字0爲結束標誌,要求將重複的數字用一個數字代替,例如:

將數組 1,1,1,2,2,2,2,2,7,7,1,5,5,5,0 轉變成1,2,7,1,5,0 問題比較簡單,要注意的是這個數組是動態的。因此避免麻煩我仍是用了STL的vector。
#include <iostream>
#include <vector>
using namespace std;
//remove the duplicated numbers in an intger array, the array was end with 0;
//e.g. 1,1,1,2,2,5,4,4,4,4,1,0 --->1,2,5,4,1,0
void static remove_duplicated(int a[], vector<int>& _st)
{
             _st.push_back(a[0]);
             for(int i=1;_st[_st.size()-1]!=0;i++)
             {
                          if(a[i-1]!=a[i])
                             _st.push_back(a[i]);
             }
}
固然若是能夠改變原來的數組的話,能夠不用STL,僅須要指針操做就能夠了。下面這個程序將修改原來數組的內容。
void static remove_duplicated2(int a[])
{
             if(a[0]==0 || a==NULL)
                          return;
             int insert=1,current=1;
             while(a[current]!=0)
             {
                          if(a[current]!=a[current-1])
                          {
                             a[insert]=a[current];
                             insert++;
                             current++;
                          }
                          else
                             current++;
             }
             a[insert]=0;
}
 
9,如何判斷一棵二叉樹是不是平衡二叉樹  問題:判斷一個二叉排序樹是不是平衡二叉樹 解決方案:
根據平衡二叉樹的定義,若是任意節點的左右子樹的深度相差不超過1,那這棵樹就是平衡二叉樹。
首先編寫一個計算二叉樹深度的函數,利用遞歸實現。
template<typename T>
static int Depth(BSTreeNode<T>* pbs)
{
             if (pbs==NULL)
                          return 0;
             else
             {
                          int ld = Depth(pbs->left);
                          int rd = Depth(pbs->right);
                          return 1 + (ld >rd ? ld : rd);
             }
}
下面是利用遞歸判斷左右子樹的深度是否相差1來判斷是不是平衡二叉樹的函數:
template<typename T>
static bool isBalance(BSTreeNode<T>* pbs)
{
             if (pbs==NULL)
                          return true;
             int dis = Depth(pbs->left) - Depth(pbs->right);
             if (dis>1 || dis<-1 )
                          return false;
             else
                          return isBalance(pbs->left) && isBalance(pbs->right);

4.abstract class Something {
   private abstract String doSomething ();
}

該段代碼有錯嗎?

答案: 錯。abstractmethods不能以private修飾。abstract的methods就是讓子類implement(實現)具體細節的,怎麼能夠用private把abstract method封鎖起來呢? (同理,abstract method前不能加final)。

5.看看下面的代碼段錯在哪裏?

public class Something {
   void doSomething () {
       private String s = "";
       int l = s.length();
   }
}

答案: 錯。局部變量前不能放置任何訪問修飾符 (private,public,和protected)。final能夠用來修飾局部變量
(final如同abstract和strictfp,都是非訪問修飾符,strictfp只能修飾class和method而非variable)。

6. 下面該段代碼是否有錯,如果有錯錯在哪裏?
abstract class Name {
   private String name;
   public abstract boolean isStupidName(String name) {}
}
答案: 錯。abstract method必須以分號結尾,且不帶花括號。ios

相關文章
相關標籤/搜索