1. 程式人生 > 實用技巧 >華科考研834 2019(二)

華科考研834 2019(二)

華中科技大學計算機考研試卷總結 2019(二) 834

  1. 鄰接表結合了順序儲存和鏈式儲存,有效減少不必要的浪費。

    有向圖中有\(n\)個表頭結點和\(m\) 個表結點,則表示該圖有\(n\)個結點,有\(m\)條邊。儲存結點的順序結構又叫頂點表,儲存邊的鏈式結構又叫邊表。邊表的頭指標和結點資訊,採用順序結構儲存到一個順序表中。鄰接表中存在兩種表結點,頂點表結點邊表結點

    鄰接表的特點是:每一個頂點引出與該頂點相關的所有邊的集合(邊的集合用鏈式儲存連結);而頂點之間用順序錶鏈接

填空題

for(i=1;i<n;i++){
  s=0;
  t=1;
  	for(j=1;j<i;j++){
      t = t*j;
      s=	s+t;
    }
}

時間複雜度:\(O(n^2)\) 因為有兩套for迴圈,第一套for迴圈的起始終止範圍是\(1…n\) ,第二套for迴圈的起始終止範圍是\(1…i\) ,但是 \(i\) 是受n約束,則\(O(n)*O(n)=O(n^2)\) ,若是\(i\) 不受n約束,答案就是\(O(n)*O(i)=O(ni)\) 一般看時間複雜度的題型只需要考慮迴圈,比如\(while \ for\) ,因為採用O標記考慮時間複雜度本來就是理論分析,只有在迴圈中才有可能n趨向於無窮大。

  1. 普通二叉樹中,葉子節點\(n_0\)和度為2的\(n_2\)的節點一定有\(\ n_0=n_2+1\)

    二叉連結串列與二叉線索樹不同,二叉連結串列是最基本的二叉樹連結串列儲存結構;

    作為一顆二叉樹,一共有n個結點,由於每一個結點(除首結點)只有一個直接前驅,因此會有n-1 條邊;這棵二叉樹儲存到二叉連結串列中的時候,每一個節點都會有兩個孩子指標,因此總的鏈域值是\(2*n\) ** ,除首節點外每個結點都有一個前驅,因此用掉了n-1** 個指標,剩下的指標\(2n-(n-1)=n+1\)都是空指標

  2. 迴圈佇列:邏輯上將佇列視為一個環。其實對於佇列,無論是線性佇列,還是迴圈佇列,佇列收尾的兩個指標\(front \ rear\) 都是朝著相同的方向移動

    順序佇列:

    ​ 對於順序佇列,初始時隊首指標front隊尾指標rear都是指向\(Q.rear=Q.front=0\)

    ​ 進隊操作:先將元素填入到佇列末尾,再對指標加一(順序儲存的佇列,要是鏈式佇列則使用next指標進行進出佇列操作,另外這裡的操作和棧的進棧操作執行順序不一樣,務必牢記!!!,棧是先移動指標,再填入元素)

    ​ 出隊操作:先取對頭元素的值,再對指標進行加一 進出佇列操作都在++之下,其實佇列一直朝著佇列序號增大的方向一直"移動" ,這樣也就造成了順序佇列的假溢位現象,序號較小的陣列元素可能已經被釋放空閒

    迴圈佇列:

    ​ 為了解決假溢位現象,引進了迴圈佇列

    ​ 初始時,仍然有\(Q.front=Q.rear=0\)

    ​ 入隊操作 \(Q.rear = (Q.rear+1)/Maxsize\)

    ​ 出隊操作 \(Q.front = (Q.front+1)/Maxsize\)

    由於\(Q.front=Q.rear\) (加入新增元素速度大於刪除元素速度,會有套圈的存在,此時會有會有$Q.rear=Q.front $ )

    不能判斷隊空還是隊滿,處理迴圈佇列隊空、隊滿方法有更改資料型別使得能夠表示資料元素個數、更改資料型別新增tag位,最常用的還是人為邏輯上犧牲一個數據單元,使得迴圈佇列達不到"物理上真正的滿佇列",這種情況下,空佇列判斷標識還是\(Q.rear=Q.front\) ,滿佇列判斷標識變成了\(Q.front=(Q.rear+1)/Maxsize\)

    1. 假設一個二維陣列\(A[5][6]\) ,這個表達形式意味著這個陣列是由5行6列構成,行數範圍\(0,1,2,3,4\),列數範圍\(0,1,2,3,4,5,\) 每一個元素佔4個數據單元,可以將矩陣畫出來。

      \(起始資料塊起點地址+資料塊個數*每一個數據塊資料單元個數=目標數塊起點地址\)

    2. 廣義表的元素可以是廣義表,也可以是單個元素,還可以為空。 表頭可以為表或者是單個元素值,表尾就是除去表頭以外的子表,不可以是單個元素值,而是表,即使是空表,也必須是表,剩下單個元素也必須以表的形式形成子表,這是尾表的定義所形成

    廣義表 {(a,b),(c,d),(e),(f,()),(g,h)}的頭表是(a,b)  //表頭是廣義表的第一個元素,這裡的元素可以直接是原子,也可以是廣義表
    尾表是{(c,d),(e),(f,()),(g,h)}  //表尾是除去第一個元素之外的剩餘元素所組成的子廣義表
    //表頭和表尾的定義區別很大!
    廣義表的長度:廣義表中最上層中,元素的個數
    廣義表的深度:表巢狀的最大層數
    
    1. 帶權路徑長度指的是:從樹中的根節點到任意目標結點的路徑長度(邊數)與該結點(只有一個)的乘積,叫做當前節點的帶權路徑長度(帶權路徑長度只需要考慮當前待研究結點的權和從根節點到當前結點的路徑長度[邊數])。而樹的帶權路徑長度就是所有葉節點的帶權路徑長度之和,記為\(WPL(weighted\ path\ length\ of\ tree )\) ,計算WPL仍然是隻需要考慮葉節點的權值 和葉節點的路徑長度

      帶權路徑WPL最小樹的叫做最優二叉樹 ,也叫做哈弗曼樹

      構造方法:

      1. 先必須有\(n\)個帶權值的節點,這\(n\)個帶權值的結點就是最終最優二叉樹的葉結點
      2. 選出其中權值最小的兩個結點,用著兩個結點向上捧出一個新的結點,新結點的權值是原來兩個結點之和
      3. 不斷重複,一直到最後形成一顆大樹

      特點:

      1. 每個初始結點最終都會變成最優二叉樹的葉子節點,而且權值越小的葉子節點距離根節點越遠
      2. n個結點的Haffman樹的構造過程會形成\(n-1\) 個內部節點,從而總共有\(2n-1\)個節點
      3. Haffman 樹的構造過程,每次會選兩顆子樹作為孩子節點捧成一顆新的子樹,因此haffman 樹不存在度為1的結點

      哈夫曼編碼:

      普通編碼往往是等長編碼,等長編碼往往對編碼空間浪費嚴重,效率不高;於是人們有提出了不等長編碼,不同字元的編碼長度不同,而且使用頻率高的字元支援使用短碼編制,對使用頻率低的字元支援使用長碼編制,這種編碼減少的資料位以及資料空間的浪費,做到了資料的壓縮。哈夫曼編碼就是一種典型的資料壓縮演算法,也是最典型的不等長編碼。

      哈弗曼編碼就是哈弗曼樹的一個具體應用:

      葉結點表示字元,並且葉結點也附上了對應的頻度表示權值,習慣上最優二叉樹左孩子分支為0,右孩子分支是1(並不是規定),每一個字元的二進位制編碼就是從根節點到葉子節點的路徑長度上的序列的連線。在哈弗曼編碼中帶權路徑長度$WPL $又叫二進位制編碼長度

      序列是(67,40,78,15,40,99,12)的序列,採用插入排序,第四趟後的結果是:

      第一趟後(40,67, 78,15,40,99,12)
      第二趟後(40,67,78, 15,40,99,12)
      第三趟後(15,40,67,78, 40,99,12)
      第四趟後(15,40,40,67,78, 99,12)
      
    2. 有向無環圖常常表示事件(結點)之間的驅動依賴關係。有向無環圖的拓撲排序,對有向圖中的邊而言\(<u,v>\) ,總是有\(u\)出現之後才會有\(v\)出現。拓撲排序的目的就是使得雜亂無章的有向圖結點能夠按事件發生順序一字排開。

    實現方式:V :入度表、E:DFS,時間複雜度就是\(O(V+E)\)

    入度表:1.不斷找開始結點,即入度為0的結點,找到後放到佇列(根據輸出情況或者可以用棧)

    ​ 2.找到後,刪除,再繼續找,不斷重複1,即完成拓撲排序。

    上圖就是一個從DAG圖到拓撲排序的例子。這種排序方式的優點是可以根據事件發生的先後順序進行排列。

    1. 對一組初始記錄進行快排(70,71,69,21,91,14,3),以70為基準元素的一趟快排結果
    既然是快排就要想到兩個指標L,R,分別負責把大數運送到右邊,把小數運送到左邊。
    

判斷

  1. 評價演算法優劣不止有演算法的時間複雜度

  2. 迴圈佇列解決的是順序溢位的"假溢位"問題,但是仍然會發生空間溢位即"真溢位"。這個沒辦法解決,凡是順序儲存結構必然會發生空間不足,進而引起溢位,迴圈佇列也不例外。使用指標佇列能夠解決空間溢位

  3. 圖的遍歷演算法可以判斷圖的連通性,但是這也不是必然的,得分情況討論:

    有向圖,無向圖,連通圖,不連通圖,連通分量,強連通分量都有著不同的情況

    對於無向連通圖,可以使用一次圖遍歷演算法(無論是DFS,還是BFS)

    對於無向非連通圖,無法僅用一次就做到遍歷整個圖

    對於強連通有向圖,可以使用一次圖遍歷演算法遍歷整個圖中節點

    對於非強連通有向圖,做不到僅用一次遍歷整個圖

  4. 靜態連結串列和動態連結串列:動態連結串列即是我們傳統意義上認識的連結串列,靈活程度非常高的一種資料結構;靜態連結串列有點類似陣列(順序表)和連結串列的一種結合。

靜態連結串列在設立之初空間大小就已經確定,並且儲存結構是一塊連續的順序結構,這一點和陣列非常像,但是在刪除和插入元素的時候又不像陣列那樣移動大量元素,而是通過修改指標(靜態連結串列中稱作指標)插入和刪除元素。 基本等同於給沒有指標的順序表新增上指標的功能

  1. 二叉排序樹。BST(binary sort tree)

    二叉排序樹滿足以下特徵:要滿足二叉排序樹,這顆二叉樹以及所有的子樹都要滿足\(左子樹<中間節點<右子樹\) 的模式

    左子樹上的所有節點均滿足小於根節點;

    右子樹上的所有節點均滿足大於根節點

    所有的二叉排序樹使用中序遍歷這顆二叉樹一定得到的是一個遞增序列。\(即中序遍歷遞增\iff二叉排序樹\)

    二叉排序樹的插入和查詢過程幾乎一樣,都是從樹的根節點開始操作比較。值得注意的是二叉排序樹的插入一定是插在了葉子節點上,查詢過程中不存在所找元素就會進行插入新元素,這是一個動態樹。

    二叉排序樹的構造:從一顆空樹進行構造,不斷查詢,不斷對當前樹插入

    比如對一顆空樹進行關鍵字序列查詢(空樹查詢關鍵字,能查詢才怪!),查詢序列是{45,24,53,12,24}

計算題

  1. 使用克魯斯卡爾演算法得到最小生成樹

    生成最小生成樹有兩種演算法prim演算法和克魯斯卡爾演算法

    生成樹是由連通圖得到,包含連通圖的所有頂點,使用最少的邊,這種情況下生成樹並不唯一。若圖中的邊帶有權,得到的一系列生成樹,其中這些生成樹邊上的權值之和是一個常數,將這些生成樹放到一個集合中去,選擇生成樹權值最小的那顆生成樹作為最小生成樹。

    最小生成樹其實也是不唯一的(極端一點,假如所有邊上的權都相等。所有生成樹都是最小生成樹);若生成樹邊上的權值兩兩互不相等,那麼可以唯一確定一個生成樹,特殊的圖-樹(頂點-1=邊數 判定樹的必要條件)本身就是一個最小生成樹

    • 雖然最小生成樹不唯一,但是最小生成樹的權值唯一(實際上還是相同權值和樹形搗的鬼,一旦這兩個條件滿足,最小生成樹就是唯一的)

    生成最小生成樹的演算法有prim演算法和克魯斯卡爾演算法,都是基於貪心演算法所得 (每次新增一條邊以及一個頂點)

    Prim演算法(類似dijkstra演算法)——一定是有權圖 從頂點擴張生成樹

    先構建一個空集T, 最開始的時候,從圖中隨機選一個結點A放到T集合中,然後開始迴圈,查詢與A相鄰的所有結點,選其中權值最小的邊以及其連線的頂點,加入到T中(每次都會加入一條邊和一個頂點);接著選一個距離當前T集合權值最小的邊以及頂點,再次加入到T中,不斷重複一直到結束。就能形成一個最小生成樹

    Kruskal演算法——按照邊權值遞增次序擴張生成樹

    初始時,先保證各節點分別為獨立的連通分量,然後按照權值從小到大新增邊,新增邊不光秉持著權值最小,還要保證新增邊之後連通性發生變化,即邊兩端頂點原來分別屬於不同的連通分量,新增邊之後,合併成一個連通分量,如此反覆,讓最開始的\(n\)個連通分量變成最後一個連通分量

  2. 查詢方法分類:

    常用的查詢方法分為以下幾類:

    • 線性結構:
      • 順序查詢
      • 折半查詢
      • 分塊查詢
    • 樹形查詢
      • 二叉排序樹(也叫二叉查詢樹)
      • 二叉平衡樹
      • B樹、B+樹
    • 雜湊查詢

    衡量查詢效率的指標有平均查詢長度,且是衡量查詢演算法效率最主要的指標。平均查詢長度(ASL,\(average\ search\ length\))指 在一次查詢過程中一次比較關鍵字的次數 。值得注意的是查詢成功和查詢失敗計算平均查詢長度方法相同,只是計算過程稍有不同。線性查詢、樹形查詢、雜湊查詢都有ASL。

    \[\begin{equation} ASL = \sum_{i=1}^n(P_iC_i) \end{equation} \]

    其中\(P_i\)是查詢某個元素的概率,通常各種考試中都是等概率查詢,概率就是\(1/n\),\(C_i\)是查詢某個資料元素的路徑上所比較的次數(查詢成功與查詢失敗在選取查詢路徑上的比較次數是有區別的)

    1. 二分查詢

      首先需要明確二分查詢只適用有序的順序表 ,因為要做到隨機定位查詢位置,比如剛開始就要找到中間位置,這使得二分查詢必須使用順序表,不適合鏈式,有序性非常自然,因為要做到不斷比較,減小查詢範圍。二分查詢的思想是:每次選取序列最中間元素與我們待查詢元素進行比較,並且不斷縮小查詢範圍,直至查詢成功或者失敗返回結果。二分查詢過程可以用一個平衡二叉樹來表示。平衡二叉樹表示:若待查詢序列中有n個元素,那麼二叉平衡樹就有n個非葉結點,由二叉樹的特性,所以葉子結點就有\(n+1\) 個。每一顆子樹的左孩子結點都小於根節點,每一顆子樹的右孩子結點大於根節點。

      構造判定樹遵循不斷選擇序列中間值原則,如果是奇數,中間值唯一;如果是偶數,中間值要麼一致向前,要麼一致向後,考試中往往選一致向前,即\(\lfloor (n_{i}+1)/2 \rfloor\) ,記得最後掛上矩形失敗結點。比較時從耿潔典向下比較,直至命中或不中。

      計算二分查詢的ASL,首當其衝還是要畫出該序列的判定樹,本質是一個平衡二叉樹。

      計算成功查詢:當前結點到根節點的路徑上的所有結點 的累加和,再除以當前成功查詢過程的所有真實結點數(其實就是判定樹的內部結點);

      計算失敗查詢:我們往往會給平衡二叉樹新增一些方形結點作為葉子節點,這些節點就是查詢失敗的結點(結點內容往往是一些區間範圍)。我們選取失敗結點的父節點一直到根節點的個數作為查詢失敗的長度,再把每個失敗結點的查詢長度累加起來,再除以查詢失敗對應的失敗結點數(判定樹的葉結點)得到查詢失敗的ASL。

    2. 雜湊查詢

      又叫雜湊查詢。順序查詢時間複雜度$ O(n)\(、二分查詢時間複雜度\) O(log_2N)$ 、二叉搜尋樹時間複雜度\(O(h)\) ,最好情況\(O(log_2n)\) ,最差是\(O(n)\) 、二叉平衡樹時間複雜度\(O(log_2n )\) 。當資料量非常大的時候,十億,百億,從裡面找資料,即使使用樹形查詢時間複雜度也只能提升到\(O(log_2n)\) 。而使用雜湊查詢的時間複雜度是\(O(1)\) ,效率提升不所謂不大!

      雜湊思想是:給出一個元素,將這個元素經過一個函式計算得到另一個值,把得到的這個值作為儲存地址。這種方式和前面線性、樹形查詢完全不同,不基於比較,而是將關鍵字值的資訊和儲存地址直接聯絡起來。根據選擇的函式,有些函式可能會把不同的值對映到相同的儲存地址

      雜湊函式構造(我們都以數字雜湊值為研究物件,字元雜湊不做研究)

      ​ 雜湊函式構造原則:雜湊函式簡單、對映空間應該分佈均勻

      • 直接定址法

      • 除留餘數法

        最常用方法。

        裝填因子,衡量一個散列表滿的程度。假設記錄是n,裝填因子是\(\alpha\) ,那麼散列表表長就是\(size = n/\alpha\) 。選一個小於表長size的最大質數\(p\) ,然後用元素\(key\)值不斷

        \[\begin{equation} f = key \% p \end{equation} \]

      • 數字分析法

      • 摺疊法

      解決衝突幾乎無法避免。現有的解決衝突思想有兩種

      • 開放地址法 (換個地方放)

        • 線性探測

          順序查看錶中單元,直至查到空閒位置。雜湊地址上會有聚集現象

        • 平方探測

          可以避免聚集,但只能檢測散列表上的一半元素

        • 雙雜湊(再雜湊) 使用兩個雜湊函式。要是第一個雜湊函式發生衝突,使用第二個雜湊函式計算增量 當裝填因子太大,查詢效率會下降,一般裝填因子在\(0.5\leq\alpha\leq0.85\) ,要是再大,可以讓散列表加倍減小\(\alpha\)

      • 鏈地址法(把同一位置的衝突物件組織在一起)

        將相同衝突位置的元素儲存到同一個單鏈表中。形式上有點像鄰接表。一個順序結構結合鏈式結構,連結串列部分儲存和查詢效率低

      雜湊查詢是以較小的\(\alpha\)為前提,用空間換時間,才會讓時間複雜度非常優秀。

      雜湊查詢不便於順序查詢,不便於最大最小值查詢

      開放定址法的散列表是順序結構;

      鏈地址法的散列表是順序結構和連式結構相結合。

      太小的\(\alpha\)導致空間浪費,太大的\(\alpha\)又以時間為代價效率低

      總結:解決雜湊查詢的一般方法:

      考試中求解雜湊平均查詢長度解答步驟:

      1. 使用除留餘數法+開放定址法或者使用除留餘數法+鏈地址法 的組合構造散列表
      2. 每一個關鍵字數值形成比較次數的表格
      3. 根據比較次數算出成功平均查詢長度以及失敗平均查詢長度

      在計算失敗平均查詢長度的時候有些許變化,由於是失敗,比較次數就是從hash(kay)得到的起始位置一直向後一邊比較一遍遍歷直至遇到第一個空位置 的次數;概率也變了,查詢成功時的概率是依據在散列表中的有效記錄數,而查詢失敗時的概率是依據整個散列表的長度。

      雜湊函式的P值,一般並不和記錄數、表長有直接關聯。其只不過是在表長範圍內選取的一個最大素數,並不一定和表長相等。有的題目中表長和雜湊函式中的素數值相等,重屬於巧合

  3. 樹、森林與二叉樹的轉換

    • 樹轉換成二叉樹:遵循當前節點左指標仍然連線左孩子,右指標連線當前節點的相鄰右兄弟。
    • 森林轉換成二叉樹:與數轉換成二叉樹類似。左孩子右兄弟原則,只不過多了 把森林中的每顆子樹連線到前邊樹的右子樹環節(因為每顆樹形成的二叉樹都沒有右子樹,右子樹位置是空著的)
    • 二叉樹轉換成樹:與上面過程相反。對一整顆大樹取左子樹,作為森林中的第一棵樹,拆下來,拆下來的部分再轉成樹(右孩子結點上提升到右兄弟[本應該就是右兄弟]);再對剩下的部分繼續取左子樹,拆分,如此重複。