算法導論-10.順序統計樹與區間樹習題


順序統計樹和區間樹都是對紅黑樹的擴張:通過在節點添加字段完成其他的功能,如果該字段可以在 $O(1)$ 時間內維護,就能夠不影響紅黑樹本身操作效率漸進量級。

順序統計樹

順序統計樹是紅黑樹的擴展:在紅黑樹的每個節點額外維護一個域size,記錄以該節點為根的子樹中的總結點個數。順序統計數具有這樣的功能:在 $O(\lg n)$ 時間內找到樹中所有元素的第 $i$ 個順序量。以下是一棵順序統計樹:

練習14.1-4 寫出一個遞歸過程OS-KEY-RANK(T,k)使得順序統計樹T和某個關鍵字k為輸入,輸出k的秩(排序)。

思路:簡單的遞歸:

  • 如果關鍵字等於根節點,返回根節點左子樹的size再加上1(這是根節點的秩);
  • 如果關鍵字小於根節點,返回該關鍵字在根節點左子樹中的秩;
  • 如果關鍵字大於根節點,返回該關鍵字在根節點右子樹中的秩加上左子樹的size加上1。
OS-KEY-RANK(r,k)if r = nil
        return 0
    if k < key[r]
        return OS-KEY-RANK(left[r],k)
    if k > key[r]
        return OS-KEY-RANK(right[r],k)+size[left[r]]+1
    if k = key[r]
        return size[left[r]]+1

練習14.1-5 給定含有 $n$ 個元素的順序統計樹中的一個元素 $x$ 和一個自然數 $i$,如何在 $O(\lg n)$ 的時間內找到元素 $x$ 的第 $i$ 個后繼?

思路:就是中序遍歷,但由於每個節點有size域,所以當子樹里不可能符合條件時,可以直接跳過:

  • 如果 $i=0$ 后繼,直接返回 $x$ 本身;
  • 如果 $x$ 右子樹size大於等於 $i$ ,說明需要找的元素在右子樹中,就采取OS-SELECT(題目中沒有,正文中)方法找出右子樹中第 $i$ 順序量。
  • 否則需要找的元素不在右子樹中,就去找最近的祖先節點,且節點x必須在祖先節點的左子樹中。對該祖先節點遞歸調用本方法,但是參數 $i$ 必須減去 $x$ 的右子樹的size。這樣理解:中序遍歷中,會先遍歷 $x$ 的右子樹,再回到祖先節點上。
  • 如果找不到左祖先節點,說明 $i$ 太大了,樹中不存在這樣的后繼。
OS-SUCCESSOR(x,i)
    if i = 0
        return x
    if size[right[x]] < i
        t = size[right[x]]
        while s = father[x]
        if left[s] = x
            return OS-SUCCESSOR(s,i-t)
        if s = nil
            return nil
        x = s
    if size[right[x]] >= i
        return OS-SELECT(right[x],i)

練習14.1-7 說明如何在 $O(n\lg n)$ 時間代價內,利用順序統計樹對大小為 $n$ 的數組中的逆序對計數。 

思路:按照原數組的順序,依次插入元素,構建順序統計樹。每次插入完成一個元素 $x$ 后,通過size域計算出該元素的順序統計量 $i$(如練習14.1-4),進而得到在這棵順序統計樹中,比 $x$ 大的節點有多少個:這部分比 $x$ 大的節點實際上就與 $x$ 構成了逆序對,因為他們在 $x$ 之前插入了順序統計樹,說明在原數組中他們排在 $x$ 的前面。每插入一個元素之后就將該數目累加起來,最后求得逆序對的數目。

練習14.1-8 一個圓上有 $n$ 條弦,每條弦都是按照端點來定義的。給出一個能在 $O(n\lg n)$ 時間內確定圓內相交弦的對數。

思路:如果將圓從某個點剪斷,並拉成直線,,圓上的所有縣都變成了互相平行的線段,那么相交的弦的特點是:有重疊區域。每條弦有2個頂點,左端點和右端點,為每條弦創建一個代號,然后開始遍歷2n個點:

  • 如果是左端點,那么就將該端點對應的弦的代號,以左端點的位置為關鍵字,插入到順序統計樹中;
  • 如果右端點,那么就將該端點對應的弦的代號從順序統計樹中刪除。

在每條弦被刪除之前,立刻統計一下樹中現存的,關鍵字大於該弦的元素(如練習14.1-4)個數,這就是與待刪除節點相交的弦的個數,因為這些弦:關鍵字值大於待刪除的弦,說明其左端點在待刪除弦的左端點右側;在待刪除弦馬上就要被刪除的時候,讓然還沒被刪除,說明其右端點在待刪除節點的右側。所有而且僅有這樣的弦與待刪除的弦相交。

區間樹

區間樹是紅黑樹的另一種擴展,每個元素表示一個動態區間。紅黑樹用到的關鍵字值是區間樹的區間左端點值。以下是一個區間樹及其所表示的區間:

區間樹的節點還擴展了一個域max,就是以該節點為根的子樹的所有區間元素的右端點的最大值。該域很容易在 $O(1)$ 時間內維護:那就是左子結點的max、右子結點的max和自身區間的右端點三者的最大值。

區間樹提供一些與區間有關的操作,比如判斷一個區間有沒有與區間樹中的任何一個區間元素有交集,判斷一個點是否落在區間樹中的任意一個區間元素中。

練習14.3-6 說明如何維護一個支持操作MIN-GAP的動態數集Q,該操作能夠給出Q中所有元素距離最近的兩個。

思路:擴展紅黑樹,,將Q中的元素值作為關鍵字,在紅黑樹的每個節點上維護如下三個域:

  • min-gap表示子樹中所有元素,每兩個元素中的最小距離;
  • min表示樹中所有元素最小值;
  • max表示樹中所有元素最大值。

問題的重點在min-gap域的維護上。min-gap應當這樣維護:它應當是一下幾個值得最小值:

  • 左節點的min-gap域
  • 右節點的min-gap域
  • 左節點max域與本節點值的差
  • 右節點min域與本節點值的差

練習14.3-7 VLSL數據庫將一塊集成電路表示為一個矩形,每個矩形的兩邊分別平行於x軸和y軸。給出一個算法,在 $O(n\lg n)$ 確定n個矩形中是否有兩個有重疊區域。

思路:將n塊矩形的左邊界,右邊界值排序為具有2n個元素的數組X,類似練習14.1-8,開始遍歷X:

  • 如果遍歷到的元素x為某個矩形的左邊界,那么將該矩形的上下邊界作為一個區間插入到區間樹中;
  • 如果遍歷到的元素x為某個矩形的右邊界,那么將該矩形的上下邊界區間從區間樹中刪除。

在刪除區間之前,判斷一下在區間樹中是否有其他元素和待刪除的區間有重疊區域。如果有,則找出了重疊區域。數組X已排序,並且插入和刪除順序保證了兩個矩形在x軸上有重疊,而區間樹保證了兩個矩形在y軸上有重疊,因此兩個矩陣有重疊區域。

思考題14-1 有一組區間,如何盡可能快地找到最大重疊點:即與該點有重疊區域的區間的數目最多。

思路:直觀上,最大重疊點一定可以是端點,因為最大重疊點和非最大重疊點的分界,一定是某個區間具有端點造成的。這樣考慮:

  1. 將所有端點組織成紅黑樹,增加一個域p,左節點為1,右節點為-1。
  2. 然后在節點中再維護一個域s,表示以該節點為根的子樹中所有元素的p的和。某個節點的重疊數就是該節點左節點的s域:因為s表示,在這個節點上,已經開始(+1)但沒有結束的(-1)的區間的個數。s域的維護也很簡單,就是左子樹的s加上右子樹的s再加上自身的p。
  3. 最大重疊數也維護在節點中,為域m,表示以該節點為根的子樹中所有元素的最大重疊數。m的維護是:m為左節點的最大重疊數、右節點的最大重疊數和自己的最大重疊數三者的最大值。

思考題14-2 Josephus環。假設n個人排成一圈,給定一個正整數m<n,從某人開始報數,遇到第m個人就讓其出圈,並進行下去直到所有人出圈,給出一個算法來獲得這n個人出圈的順序。

  1. 如果m是個常數,那么在$O(n)$內。
    用環形鏈表也好,因為$m=O(1)$,所以直接遍歷每個元素,每m次刪除一個元素,獲得出圈序列的一個值。
  2. 如果m不是常數,那么在$O(n\lg n)$內。
    順序統計樹最重要的意義是,可以在$O(\lg n)$時間內訪問第$i$順序量(注意$i$不是常數)。第1問中,實際上遍歷了mn次,但m是常數,所以效率還是$O(n)$。而在這里,m不是常數,因此可以將所有元素組織成順序統計樹,每次訪問並刪除一個節點的耗費是$O(\lg n)$,總耗費就是$O(n\lg n)$。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM