日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

c语言判断一个已知的二叉树是否是二叉排序树_10584 二叉树怎样序列化才能重建...

發布時間:2024/1/23 编程问答 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c语言判断一个已知的二叉树是否是二叉排序树_10584 二叉树怎样序列化才能重建... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  「序列化」(serialization),指的是把復雜的數據結構轉化為線性結構,以方便存儲的過程。序列化得到的線性結構必須能重建出原有的結構,才有意義。

  對于二叉樹,常用的序列化方法是在樹上進行某種遍歷(如先序、中序、后序、層序),用一種或兩種遍歷結果作為序列化結果。但并不是隨便選一種或兩種遍歷結果,都能把二叉樹重建出來。本文將給出二叉樹序列化能夠重建的一個充分條件,并且在實用中,這個條件也可以認為是必要的。

一、幾種常見的序列化方法

1.1 僅使用一種遍歷的序列化方法

  這是最常見的序列化方法。可以采用的遍歷順序包括先序、后序、層序。在遍歷時,要把空指針也包含在遍歷的結果中。例如,對下圖的二叉樹,進行先序、后序、層序遍歷的結果分別為 12##3#4##、##2###431、123###4##(# 表示空指針)。

  從這幾種遍歷的結果重建二叉樹的過程是顯然的,程序從略。其時間復雜度為 O(n),n 為樹中的結點數。

  而僅根據(帶空指針的)中序遍歷,是不能重建二叉樹的。比如,上面這棵樹的中序遍歷為 #2#1#3#4#。事實上可以證明,任何一棵二叉樹的中序遍歷結果,都會是空指針與樹中結點交替出現的形式,所以空指針沒有提供任何額外的信息。

1.2 使用兩種遍歷的序列化方法

  這是學習二叉樹時的常見思考題:如何根據兩種遍歷結果(不含空指針)重建二叉樹。并不是任意兩種遍歷結果都能重建二叉樹,我們先考慮一種可行的情況:已知先序和中序遍歷。

  以上圖中的二叉樹為例,它的先序遍歷為 124536,中序遍歷為 425136。先序遍歷的第一個元素 1 一定是根,以這個元素為分界點把中序遍歷結果分成兩半,可以得到 425 和 36,這就是左子樹和右子樹各自的中序遍歷。在先序遍歷中取同樣長度的兩個子序列,得到 245 和 36,這就是兩個子樹的先序遍歷了。由此可以遞歸地重建出整棵二叉樹。Python 代碼如下(Node 類的定義從略):

def

  我們注意到,程序正常運行的一個條件是樹中沒有重復的元素。否則,在中序遍歷中就不一定能確定根的位置了。

  另外,上面這個程序使用了 index 函數,它的時間復雜度不是 O(1) 的。在某些編程語言中,截取一個序列的子序列需要把子序列復制一份,這也不是 O(1) 的。這些因素導致整個程序的時間復雜度高于 O(n),在最壞情況下可以達到 O(n^2)。一個解決辦法是把兩個已知序列包裝成輸入流(如 Python 中的 collections.deque),在創建根結點時,暫時先不去找它在中序遍歷中的位置,而是遞歸下去,直到在中序遍歷中遇到根結點時再返回來。Python 代碼如下,其中 stop 參數表示在中序遍歷中遇到什么元素就該返回了。

from

  這段程序理解起來稍微困難一些,不過它更能揭示「先序 + 中序」與「先序 + 空指針」兩種序列化方式的相似之處。在這段程序中,中序遍歷的作用是用做遞歸終止條件,即告訴程序哪些地方應當是空指針。也就是說,「中序遍歷」與「空指針」提供的是相同的信息,只不過更間接一些。

  現在來看其它使用兩種遍歷的序列化方法。「后序 + 中序」的情況跟「先序 + 中序」的情況是十分類似的,把上面兩段程序稍加修改,都可以用于「后序 + 中序」的重建(具體要修改哪里留作練習)。但已知先序和后序遍歷結果時,是不能重建二叉樹的,例如下面兩棵樹的先序遍歷都是 12,后序遍歷都是 21。

  同時也可以發現,上圖中兩棵樹的層序遍歷也都是 12。因此,依靠「層序 + 先序」或「層序 + 后序」兩種遍歷結果,也都不能重建二叉樹。依靠「層序 + 中序」是可以重建的,具體方法將在下一小節最后說明。

1.3 二叉搜索樹(BST)的序列化方法

  二叉搜索樹(binary search tree, BST)是這樣一種二叉樹:對任一結點,它的左子樹中所有結點都小于(或等于)本身,而右子樹中所有結點都大于(或等于)本身。BST 的定義不統一,有些定義不允許樹中有重復元素,有些定義允許各個結點的單側子樹中有等于本身的元素,有些定義允許兩側都有等于本身的元素。本文采用最寬松的定義,但本小節僅討論沒有重復元素的情況,至于這個條件的放寬,留到第三大節中討論。

  如果已知一棵樹是 BST,那么只需要知道先序、后序、層序遍歷中的一者(不需要包含空指針)就足以重建了。這是因為,把這些遍歷結果排個序,就是中序遍歷,從而化歸成了上一小節的情況。這說明,BST 的順序與中序遍歷提供的是同樣的信息。當然,排序的時間復雜度是 O(n log n),高于重建的復雜度 O(n)。能不能繞過排序呢?也是可以的,只要我們能在重建過程中,根據「樹是 BST」這個條件得知哪些地方是空指針。

  例如,在已知先序遍歷結果時,可以用如下方法重建 BST。inf 代表一個比所有元素都大的值。在上一小節里,我們用「中序遍歷的開頭就是上面某層的根結點(stop)」作為空指針的判斷條件。現在沒有中序遍歷了,但我們可以改用「先序遍歷的下一個結點大于等于 stop」作為空指針的判斷條件。

from

  已知后序遍歷時的重建方法與已知先序遍歷時類似,略。

  在已知層序遍歷時,BST 的重建方法如下。在重建過程中,對于每個結點,記錄下以它為根的子樹中的元素的取值范圍(用開區間表示)。結合結點本身的值,就可以知道它的兩個子結點的取值范圍。如果先序遍歷中的下一個元素正好落在這些范圍之內,那么這些子結點就存在,否則這些子結點為空。

from

  下面解答上一小節的遺留問題:對于一棵普通二叉樹(非 BST),在已知層序和中序遍歷時,如何重建。事實上,中序遍歷可以認為是指定了樹中元素的順序關系,于是便化歸為剛剛解決的「已知層序遍歷重建 BST」的問題。在實現上,可以用一個哈希表將樹中的元素映射為它們在中序遍歷中的次序,然后就可以套用上一段程序解決。

二、二叉樹序列化能夠重建的充分條件

  上文討論的所有情況,可以總結成如下的「定理」:

一棵二叉樹能夠被重建,如果滿足下面三個條件之一:
    a1. 已知先序遍歷;或
    a2. 已知后序遍歷;或
    a3. 已知層序遍歷;
  且滿足下面三個條件之一:
    b1. 前面已知的那種遍歷包含了空指針;或
    b2. 已知中序遍歷,且樹中不含重復元素;或
    b3. 樹是二叉搜索樹,且不含重復元素。

  這是本文的主要結論。它指出,中序遍歷提供的信息,與空指針和 BST 是相同的,而與先序、后序、層序遍歷提供的信息互補。同時,這個充分條件也幾乎是必要的,因為如果僅滿足 a 組的兩個條件,或者僅滿足 b 組的兩個條件,都不能重建二叉樹。

三、「不含重復元素」的必要性探討

  上一節給出的條件是個充分條件;導致它不是必要條件的原因,就在于 b2、b3 兩個條件中的「不含重復元素」。在這一節中,我們就來探討一下這個條件可以放寬到什么程度,還能保證重建出的樹是唯一的。

  先看 b3,即 BST 的情況。對于 BST,可以把「不含重復元素」,放寬到「允許一側子樹中有與根相等的元素」。無論是根據先序還是層序遍歷重建 BST,關鍵步驟都是確定遍歷結果中的下一個元素應該長在樹的什么位置,而這是根據每個可能長出結點的位置(下圖中灰色的橢圓)允許的取值范圍確定的。在不允許重復元素的情況下,各個「生長點」的取值范圍都是開區間;在允許一側子樹中有與根相等的元素的情況下,各個「生長點」的取值范圍是半開半閉區間 —— 在這兩種情況下,各區間都沒有重疊,所以都可以唯一確定下一個元素應該長在哪里。但如果放寬到「兩側子樹都允許有與根相等的元素」,區間就變成了閉區間,端點出現重疊,就不能保證重建出的樹唯一了。例如,如果先序或層序遍歷的結果是 533,則不能確定后一個 3 應該是前一個 3 的左孩子還是右孩子。

  不過,即使在兩側子樹都允許有與根相等的元素的情況下,重建出的樹也有可能是唯一的。比如,如果先序遍歷是 2132,那么后一個 2 只能作為 3 的左孩子,而不能作為 1 的右孩子(下圖左);再如,如果層序遍歷是 232,那么后一個 2 只能作為 3 的左孩子,而不能作為 前一個 2 的左孩子(下圖右)。這是因為,按照先序或層序的限制,在安放后一個 2 時,有些「生長點」已經不可用了。但這種情況只能在算法執行過程中發現,無法事先判斷,也就是說,很難給出在「兩側子樹都允許有與根相等的元素」的前提下樹能夠唯一重建的充要條件。

  再看 b2,即已知中序遍歷的情況。我們發現,如果允許有重復元素,那么也無法在事先判斷樹是否唯一。例如,當先序遍歷為 1213,中序遍歷為 1231 時,重建出的樹有兩種可能:若認為中序遍歷中的前一個 1 為根,則它有一棵右子樹,其先序遍歷為 213,中序遍歷為 231(下圖中);若認為中序遍歷中的后一個 1 為根,則它有一棵左子樹,其先序遍歷為 213,中序遍歷為 123(下圖左)。但在先序遍歷仍為 1213,把中序遍歷改為 1321 時,重建出的樹就是唯一的了(下圖右):此時只能認為中序遍歷中的后一個 1 為根。否則,我們將需要重建一棵先序遍歷為 213、中序遍歷為 321 的子樹,而這樣的樹是不存在的。

  「先序遍歷為 213、中序遍歷為 321 的樹不存在」—— 這個事實其實頗有深意。它告訴我們,并不是把先序遍歷隨便排列一下作為中序遍歷,都存在對應的樹。事實上,3 個元素的全排列有 3! = 6 種,而 3 個結點組成的二叉樹只有 Catalan(3) = 5 種,差的那一種恰好就是本段的例子。

  如果已知的是層序和中序遍歷,同樣無法事先判斷樹是否唯一。例如,固定中序遍歷為 121,若層序遍歷也是 121,則樹有下圖左、中兩種可能;但若層序遍歷是 211,則樹就只有下圖右一種可能了。于是,與 BST 的情況類似,若在已知中序遍歷的情況下允許樹中有重復元素,則很難給出樹能夠唯一的充要條件。

  作為總結,第二節給出的充分條件中,b2、b3 兩條中的「不含重復元素」,基本可以認為是必要的。除了對于 BST 可以放寬為「允許一側子樹有與根相等的元素」以外,其它情形很難放寬。

總結

以上是生活随笔為你收集整理的c语言判断一个已知的二叉树是否是二叉排序树_10584 二叉树怎样序列化才能重建...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。