python實現樹結構


   

    樹在計算機科學的許多領域中使用,包括操作系統,圖形,數據庫系統和計算機網絡。樹數據結構與他們的植物表親有許多共同之處。樹數據結構具有根,分支和葉。自然界中的樹和計算機科學中的樹之間的區別在於樹數據結構的根在頂部,其葉在底部。

1 樹的相關定義

節點樹的基本部分。它可以有一個名稱,我們稱之為“鍵”。節點也可以有附加信息。我們將這個附加信息稱為“有效載荷”。雖然有效載荷信息不是許多樹算法的核心,但在利用樹的應用中通常是關鍵的。

樹的另一個基本部分。邊連接兩個節點以顯示它們之間存在關系。每個節點(除根之外)都恰好從另一個節點的傳入連接。每個節點可以具有多個輸出邊。

樹的根是樹中唯一沒有傳入邊的節點。

路徑路徑是由邊連接節點的有序列表。
子節點具有來自相同傳入邊的節點 c 的集合稱為該節點的子節點。
父節點具有和它相同傳入邊的所連接的節點稱為父節點。
兄弟節點樹中作為同一父節點的子節點的節點被稱為兄弟節點。
子樹由父節點和該父節點的所有后代組成的一組節點和邊。
葉節點葉節點是沒有子節點的節點。
高度樹的高度等於樹中任何節點的最大層數。

定義一:樹由一組節點和一組連接節點的邊組成。樹具有以下屬性:

  • 樹的一個節點被指定為根節點。
  • 除了根節點之外,每個節點 n 通過一個其他節點 p 的邊連接,其中 p 是 n 的父節點。
  • 從根路徑遍歷到每個節點路徑唯一。
  • 如果樹中的每個節點最多有兩個子節點,我們說該樹是一個二叉樹。下圖展示了合適定義一的。


定義二:樹是空的,或者由一個根節點和零個或多個子樹組成,每個子樹也是一棵樹。每個子樹的根節點通過邊連接到父樹的根節點。 下圖 說明了樹的這種遞歸定義。使用樹的遞歸定義,我們知道 下圖中的樹至少有四個節點,因為表示一個子樹的每個三角形必須有一個根節點。 它可能有比這更多的節點,但我們不知道,除非我們更深入樹。


2 列表表示樹結構

2.1 結構示意圖

列表為我們提供了一個簡單的遞歸數據結構,我們可以直接查看和檢查。在列表樹的列表中,我們將根節點的值存儲為列表的第一個元素。列表的第二個元素本身將是一個表示左子樹的列表。列表的第三個元素將是表示右子樹的另一個列表。下圖展示了一個簡單的樹和相應的列表實現。


myTree = ['a',   #root
      ['b',  #left subtree
       ['d', [], []],
       ['e', [], []] ],
      ['c',  #right subtree
       ['f', [], []],
       [] ]
     ]
樹的根是  myTree[0] ,根的左子樹是  myTree[1] ,右子樹是  myTree[2]

2.2 數的函數表達

下面我們用列表作為樹的函數來形式化樹數據結構的定義(並非定義一個二叉樹類),幫助我們操縱一個標准列表。

def BinaryTree(r):
    return [r, [], []]

BinaryTree 函數簡單地構造一個具有根節點和兩個子列表為空的列表。

2.3 插入子節點

要將左子樹添加到樹的根,我們需要在根列表的第二個位置插入一個新的列表。我們必須小心。如果列表已經在第二個位置有東西,我們需要跟蹤它,並沿着樹向下把它作為我們添加的列表的左子節點。下面代碼展示了插圖左子節點和右子節點的 python 代碼。

def insertLeft(root,newBranch):
    t = root.pop(1)
    if len(t) > 1:
        root.insert(1,[newBranch,t,[]])
    else:
        root.insert(1,[newBranch, [], []])
    return root

def insertRight(root,newBranch):
    t = root.pop(2)
    if len(t) > 1:
        root.insert(2,[newBranch,[],t])
    else:
        root.insert(2,[newBranch,[],[]])
    return root

要插入一個左子節點,我們首先獲得與當前左子節點對應的(可能為空的)列表。然后我們添加新的左子樹,添加舊的左子數作為新子節點的左子節點。這允許我們在任何位置將新節點拼接到樹中。

下面編寫一些訪問函數來獲取和設置根節點的值,以及獲取左或右子樹,完成這組樹形函數。

def getRootVal(root):
    return root[0]

def setRootVal(root,newVal):
    root[0] = newVal

def getLeftChild(root):
    return root[1]

def getRightChild(root):
    return root[2]

3 節點表示

3.1 結構示意圖

示意圖第二種表示樹的方法使用節點和引用。在這種情況下,我們將定義一個具有根值屬性的類,以及左和右子樹。 它的結構類似於下圖:

3.2 構造類

這個表示重要的事情是 left和 right 的屬性將成為對 BinaryTree 類的其他實例的引用。 例如,當我們在樹中插入一個新的左子節點時,我們用 python 創建另一個 BinaryTree 實例如下,並在根節點中修改self.leftChild 來引用新樹節點。

class BinaryTree:
    def __init__(self,rootObj):
        self.key = rootObj
        self.leftChild = None
        self.rightChild = None

構造函數希望獲取某種對象存儲在根中。 就像你可以在列表中存儲任何你喜歡的對象一樣,樹的根對象可以是對任何對象的引用。 對於我們的先前示例,我們將存儲節點的名稱作為根值。使用節點和引用來表示 Figure 2 中的樹,我們將創建 BinaryTree 類的六個實例。

3.2.1 添加節點

要向樹中添加一個左子樹,我們將創建一個新的二叉樹對象,並設置根的左邊屬性來引用這個新對象。 代碼如下:

def insertLeft(self,newNode):
    if self.leftChild == None:
        self.leftChild = BinaryTree(newNode)
    else:
        t = BinaryTree(newNode)
        t.leftChild = self.leftChild
        self.leftChild = t

我們必須考慮兩種插入情況。 第一種情況的特征沒有現有左孩子的節點。當沒有左子代時,只需向樹中添加一個節點。 第二種情況的特征在於具有現有左子代的節點。在第二種情況下,我們插入一個節點並將現有的子節點放到樹中的下一個層。第二種情況由 Listing 5 第 4 行的 else 語句處理。同理,在根和現有的右子代之間插入節點。

def insertRight(self,newNode):
    if self.rightChild == None:
        self.rightChild = BinaryTree(newNode)
    else:
        t = BinaryTree(newNode)
        t.rightChild = self.rightChild
        self.rightChild = t

3.2.2 獲取左右子代和根植

def getRightChild(self):
    return self.rightChild

def getLeftChild(self):
    return self.leftChild

def setRootVal(self,obj):
    self.key = obj

def getRootVal(self):
    return self.key

3 完整的二叉樹結構

使用節點 a 作為根的簡單樹,並將節點 b 和 c 添加為子節點。下面代碼創建樹並查看存儲在 key,left 和 right 中的一些值。

class BinaryTree:
    def __init__(self,rootObj):
        self.key = rootObj
        self.leftChild = None
        self.rightChild = None

    def insertLeft(self,newNode):
        if self.leftChild == None:
            self.leftChild = BinaryTree(newNode)
        else:
            t = BinaryTree(newNode)
            t.leftChild = self.leftChild
            self.leftChild = t

    def insertRight(self,newNode):
        if self.rightChild == None:
            self.rightChild = BinaryTree(newNode)
        else:
            t = BinaryTree(newNode)
            t.rightChild = self.rightChild
            self.rightChild = t


    def getRightChild(self):
        return self.rightChild

    def getLeftChild(self):
        return self.leftChild

    def setRootVal(self,obj):
        self.key = obj

    def getRootVal(self):
        return self.key


r = BinaryTree('a')
print(r.getRootVal())
print(r.getLeftChild())
r.insertLeft('b')
print(r.getLeftChild())
print(r.getLeftChild().getRootVal())
r.insertRight('c')
print(r.getRightChild())
print(r.getRightChild().getRootVal())
r.getRightChild().setRootVal('hello')
print(r.getRightChild().getRootVal())

參考資料:《problem-solving-with-algorithms-and-data-structure-using-python》 
http://www.pythonworks.org/pythonds


免責聲明!

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



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