樹狀的資料結構的建立

Jason990420發表於2020-06-17

樹狀的資料結構的建立

很多時候我們會需要一個樹狀結構來管理我們的資料, 比如以下等等.

  • 檔案結構: 電腦 - 目錄 - 檔案
  • 房子結構: 建築 - 區域 - 設施
  • 書庫結構: 書庫 - 類別 - 書籍

樹狀結構由各節點所組成, 有幾項基本的屬性是必要的.

  • 父節點, 用來連結父項, 可以從樹狀結構的下層找到上層, 設定只有一項.
  • 子節點, 用來連結子項, 可以從樹狀結構的上層找到下層, 設定可以有多項.
  • 節點名, 用來代表節點, 以人類可識別的文字來代表, 因此可以重複, 不能在資料結構上用來代表節點
  • 節點值, 用來儲存節點本身的各項資訊
  • 節點鍵, 用來代表節點, 這個鍵值不需人人類可識別, 但為了代表各個節點, 此鍵值必須唯一, 不可重複.

除了各節點的各自訊息外, 另外需要有一個字典, 用來記錄所有的節點.

樹狀結構節點的類定義

所以我們現在要進行的就是建立一個節點的類. 以下使用假程式碼, 旣簡單又利於閱讀, 後面再編寫真程式碼.

"""
類/節點的定義 (class)
"""
class Node():
    """
    節點記錄表的類變數 = 空字典 {節點鍵:節點, ...}
    """
    elements = {}

    """
    函式/起始 - 引數為 節點名, 節點值 (__init__)
        屬性.節點名 = 節點名
        屬性.節點值 = 節點值
        屬性.父節點 = 無
        屬性.子節點 = 空列表
        屬性.節點鍵 = 呼叫節點鍵自動產生函式
    """
    def __init__(self, name, values={}):
        self.name = name
        self.parent = None
        self.children = []
        self.values = values
        self.key = self.get_key()
        Node.elements[self.key] = self

    """
    函式/節點鍵自動產生 (0 保留給樹根, 作為最頂層的存在)
        從 1 開始往上加, 在節點記錄表找到一個不存在的節點鍵
    """
    def get_key(self):
        key = 0
        while key in Node.elements:
            key += 1
        return key

    """
    函式/增加子節點 - 引數為 該子節點的節點鍵
        子節點列表加入 子節點鍵
        根據子節點鍵, 在節點記錄表中找到子節點, 該子節點的父節點為本節點鍵.
    """
    def add_child(self, child):
        key = child.key
        self.children.append(key)
        Node.elements[key].parent = self.key
    def add_children(self, children):
        for child in children:
            self.add_child(child)

    """
    函式/移除子節點 - 引數為 該子節點的節點鍵
        子節點列表刪除 子節點鍵
        根據子節點鍵, 在節點記錄表中找到子節點, 該子節點的父節點為設為 None.
    """
    def remove_child(self, key):
        if key in self.children:
            self.children.remove(key)
            Node.elements[key].parent = None
    def remove_children(self):
        for key in self.children:
            self.remove_child(key)

    """
    函式/顯示節點的字串形式 (__repr__)
        顯示 節點名 + 節點值
            按子節點列表迴圈往下找到各個子節點的 節點名 + 節點值
            直到沒有子節點
    """
    def get_string(self, key, i=0):
        node = Node.elements[key]
        result = ' '*i + node.name + ' ' + str(node.values) + '\n'
        for child in node.children:
            result += self.get_string(child, i+2)
        return result

    def __repr__(self):
        return self.get_string(self.key).strip()


使用方式

"""
建立節點
"""
chairs = [Node(f'Chair {i}', values={'material':'metal', 'size':'medium'}) for i in range(12)]
table_1 = Node('Table 1', values={'material':'wood', 'size':'medium'})
table_1.add_children([chairs[i] for i in range(4)])
table_2 = Node('Table 1', values={'material':'wood', 'size':'large'})
table_2.add_children([chairs[i] for i in range(4, 12)])
kitchen = Node('Kitchen 1', values={'area':20})
kitchen.add_child(table_1)
kitchen.add_child(table_2)
bedrooms = [Node(f'Bed {i}', values={'size':'double'}) for i in range(3)]
house = Node('House 1', values={'cost':1200000, 'area':100, 'city':'Zuhai'})
house.add_child(kitchen)
house.add_children(bedrooms)
>>> house
House 1 {'cost': 1200000, 'area': 100, 'city': 'Zuhai'}
  Kitchen 1 {'area': 20}
    Table 1 {'material': 'wood', 'size': 'medium'}
      Chair 0 {'material': 'metal', 'size': 'medium'}
      Chair 1 {'material': 'metal', 'size': 'medium'}
      Chair 2 {'material': 'metal', 'size': 'medium'}
      Chair 3 {'material': 'metal', 'size': 'medium'}
    Table 1 {'material': 'wood', 'size': 'large'}
      Chair 4 {'material': 'metal', 'size': 'medium'}
      Chair 5 {'material': 'metal', 'size': 'medium'}
      Chair 6 {'material': 'metal', 'size': 'medium'}
      Chair 7 {'material': 'metal', 'size': 'medium'}
      Chair 8 {'material': 'metal', 'size': 'medium'}
      Chair 9 {'material': 'metal', 'size': 'medium'}
      Chair 10 {'material': 'metal', 'size': 'medium'}
      Chair 11 {'material': 'metal', 'size': 'medium'}
  Bed 0 {'size': 'double'}
  Bed 1 {'size': 'double'}
  Bed 2 {'size': 'double'}

注: 刪除節點以及移動節點都可以作到, 就是複雜點, 這裡就不細說了.

本作品採用《CC 協議》,轉載必須註明作者和本文連結

Jason Yang

相關文章