前段時間剛好在學習機器學習中的決策樹,想起多年前學習樹這個資料結構的場景,剛好藉此機會迴歸一下知識點。
樹是一種非常常見的資料結構,它由節點(Node)和邊(Edge)構成。它有如下的一些特徵:
1. 根結點(Root Node):樹有且只有一個根結點,它是樹的頂端結點。
2. 結點(Node):每個結點包含一個值或資訊,除了根結點,每個結點都有一個父結點和零個或多個子結點。
3. 邊(Edge):連線兩個結點的連線,表示結點之間的關係。
4. 葉結點(Leaf Node):沒有子結點的結點。
5. 子結點(Child Node):直接連線在某結點下的結點。
6. 父結點(Parent Node):直接連線在某結點上的結點。
7. 子樹(Subtree):由一個結點及其所有子結點組成的樹。
根據樹的節點情況,主要有下面的分類:
1. 二叉樹(Binary Tree):每個結點最多有兩個子結點,稱為左子結點和右子結點。
2. 完全二叉樹(Complete Binary Tree):除了最後一層,其他層的結點都填滿了,最後一層的結點靠左排列。
3. 滿二叉樹(Full Binary Tree):每個結點要麼是葉結點,要麼有兩個子結點。
4. 平衡二叉樹(Balanced Binary Tree):左右子樹的高度差不超過1的二叉樹。
5. 二叉搜尋樹(Binary Search Tree, BST):左子結點的值小於父結點的值,右子結點的值大於父結點的值。
樹的真實應用很多,比如LInux系統中的檔案系統結構就是樹結構。
我用Python實現了這個檔案系統的樹結構,程式碼如下:
class FileSystemNode:
def __init__(self, name, is_directory=False):
self.name = name
self.is_directory = is_directory
self.children = []
def add_child(self, child_node):
if self.is_directory:
self.children.append(child_node)
else:
raise ValueError("Cannot add child to a file node")
def __repr__(self, level=0):
ret = "\t" * level + repr(self.name) + "\n"
for child in self.children:
ret += child.__repr__(level + 1)
return ret
# 建立檔案系統根目錄
root = FileSystemNode("/", is_directory=True)
# 建立子目錄和檔案
home = FileSystemNode("home", is_directory=True)
var = FileSystemNode("var", is_directory=True)
etc = FileSystemNode("etc", is_directory=True)
user1 = FileSystemNode("user1", is_directory=True)
user2 = FileSystemNode("user2", is_directory=True)
documents = FileSystemNode("documents", is_directory=True)
pictures = FileSystemNode("pictures", is_directory=True)
file1 = FileSystemNode("file1.txt")
photo1 = FileSystemNode("photo1.jpg")
# 構建檔案系統樹
root.add_child(home)
root.add_child(var)
root.add_child(etc)
home.add_child(user1)
home.add_child(user2)
user1.add_child(documents)
user1.add_child(pictures)
documents.add_child(file1)
pictures.add_child(photo1)
# 列印檔案系統樹
print(root)
執行程式碼,可以得到輸出如下所示:
'/'
'home'
'user1'
'documents'
'file1.txt'
'pictures'
'photo1.jpg'
'user2'
'var'
'etc'
可以看出這個資料夾結構是一個多叉樹,一個父節點可以有多個子節點。
最開始說到的決策樹也是一種樹結構的應用。下面是用Python實現的樹的定義和三種遍歷演算法:
class TreeNode:
def __init__(self, value=0, left=None, right=None):
self.value = value
self.left = left
self.right = right
# 建立一個簡單的二叉樹
root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
root.left.left = TreeNode(4)
root.left.right = TreeNode(5)
# 前序遍歷
def pre_order_traversal(node):
if not node:
return
print(node.value, end=' ')
pre_order_traversal(node.left)
pre_order_traversal(node.right)
# 中序遍歷
def mid_order_traversal(node):
if not node:
return
mid_order_traversal(node.left)
print(node.value, end=' ')
mid_order_traversal(node.right)
# 後序遍歷
def post_order_traversal(node):
if not node:
return
post_order_traversal(node.left)
post_order_traversal(node.right)
print(node.value, end=' ')
# 呼叫前序遍歷
pre_order_traversal(root) # 輸出:1 2 4 5 3
print("-------------------------\r\n")
mid_order_traversal(root)
print("-------------------------\r\n")
post_order_traversal(root)
明天在繼續學習樹的其他案例,日拱一卒,不負年華。