二叉樹簡介

落雷發表於2023-11-08

什麼是二叉樹?

二叉樹是電腦科學中一種重要的資料結構,它在許多應用領域中都有廣泛的用途。本文將介紹二叉樹的概念、性質、常見型別和應用。

二叉樹(Binary Tree)是一種樹形資料結構,它由節點構成,每個節點最多有兩個子節點,通常稱為左子節點右子節點。這兩個子節點可以為空,也可以包含資料或值。二叉樹是一種層次結構,根節點位於樹的頂部,其他節點按照層級依次排列。

二叉樹的性質

二叉樹具有許多重要的性質,包括:

  1. 根節點(Root Node): 二叉樹的頂部節點稱為根節點,它是整棵樹的起點。
  2. 分支節點(Internal Node): 除了葉子節點以外的節點都稱為分支節點,它們至少有一個子節點。
  3. 葉子節點(Leaf Node): 葉子節點是沒有子節點的節點,它們位於樹的末梢。
  4. 父節點(Parent Node): 有子節點的節點被稱為父節點。每個節點都有一個父節點,除了根節點。
  5. 子節點(Child Node): 子節點是直接連線到父節點的節點。一個父節點可以有最多兩個子節點,即左子節點和右子節點。
  6. 深度(Depth): 節點的深度是從根節點到該節點的路徑長度,根節點的深度為0。
  7. 高度(Height): 二叉樹的高度是從根節點到最深層葉子節點的最長路徑長度。樹的高度是整棵樹的高度。
  8. 度(Degree): 節點的度是指其子節點的數量,對於二叉樹,節點的度最大為2。
  9. 子樹(Subtree): 子樹是樹中的任何節點及其所有後代節點形成的樹。子樹可以是原樹的一部分。

常見型別的二叉樹

二叉樹有許多不同型別的變體,其中一些最常見的包括:

  1. 二叉搜尋樹(Binary Search Tree,BST): 二叉搜尋樹是一種特殊型別的二叉樹,其中左子樹的值小於或等於根節點的值,右子樹的值大於根節點的值。這種有序性質使得BST在搜尋、插入和刪除操作上非常高效。
  2. 平衡二叉樹(Balanced Binary Tree): 平衡二叉樹是一種二叉搜尋樹,它確保樹的高度保持在較小範圍內,以提高搜尋效能。常見的平衡二叉樹包括AVL樹和紅黑樹。
  3. 滿二叉樹(Full Binary Tree): 滿二叉樹是一種每個節點都有0或2個子節點的二叉樹。它的葉子節點都位於同一層。
  4. 完全二叉樹(Complete Binary Tree): 完全二叉樹是一種除了最後一層外,其他層都被完全填充的二叉樹。最後一層的節點從左向右填充。

二叉搜尋樹

以下是一個簡單的Go語言實現的二叉搜尋樹(Binary Search Tree,BST)示例。這個示例包括二叉搜尋樹的基本操作,如插入、查詢和中序遍歷。

package main

import "fmt"

// TreeNode 表示二叉搜尋樹的節點結構
type TreeNode struct {
	Value int
	Left  *TreeNode
	Right *TreeNode
}

// Insert 用於向BST中插入新的節點
func (root *TreeNode) Insert(value int) *TreeNode {
	if root == nil {
		return &TreeNode{Value: value}
	}

	if value < root.Value {
		root.Left = root.Left.Insert(value)
	} else if value > root.Value {
		root.Right = root.Right.Insert(value)
	}

	return root
}

// Search 用於在BST中搜尋特定值
func (root *TreeNode) Search(value int) *TreeNode {
	if root == nil || root.Value == value {
		return root
	}

	if value < root.Value {
		return root.Left.Search(value)
	}

	return root.Right.Search(value)
}

// InorderTraversal 用於執行中序遍歷BST
func (root *TreeNode) InorderTraversal() {
	if root != nil {
		root.Left.InorderTraversal()
		fmt.Printf("%d ", root.Value)
		root.Right.InorderTraversal()
	}
}

func main() {
	root := &TreeNode{Value: 10}
	root.Insert(5)
	root.Insert(15)
	root.Insert(3)
	root.Insert(7)
	root.Insert(12)
	root.Insert(18)

	fmt.Println("Inorder Traversal of BST:")
	root.InorderTraversal()
	fmt.Println()

	searchValue := 7
	if root.Search(searchValue) != nil {
		fmt.Printf("Found %d in BST.\n", searchValue)
	} else {
		fmt.Printf("%d not found in BST.\n", searchValue)
	}

	searchValue = 8
	if root.Search(searchValue) != nil {
		fmt.Printf("Found %d in BST.\n", searchValue)
	} else {
		fmt.Printf("%d not found in BST.\n", searchValue)
	}
}

在這個示例中,我們定義了一個TreeNode結構來表示BST的節點,以及用於插入和搜尋節點的方法。我們還實現了中序遍歷以演示BST中元素的有序輸出。在main函式中,我們建立了一個BST,插入了一些值,然後進行了搜尋操作並進行了中序遍歷。

平衡二叉樹

平衡二叉樹(Balanced Binary Tree)是一種特殊型別的二叉樹,它的高度保持在較小範圍內,以確保樹的效能在搜尋、插入和刪除操作上都很好。其中一個常見的平衡二叉樹是AVL樹。以下是一個用Go語言實現的簡單AVL樹示例:

package main

import (
	"fmt"
)

type TreeNode struct {
	Value       int
	Left, Right *TreeNode
	Height      int
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func height(node *TreeNode) int {
	if node == nil {
		return -1
	}
	return node.Height
}

func updateHeight(node *TreeNode) {
	node.Height = 1 + max(height(node.Left), height(node.Right))
}

func rotateRight(y *TreeNode) *TreeNode {
	x := y.Left
	T2 := x.Right

	x.Right = y
	y.Left = T2

	updateHeight(y)
	updateHeight(x)

	return x
}

func rotateLeft(x *TreeNode) *TreeNode {
	y := x.Right
	T2 := y.Left

	y.Left = x
	x.Right = T2

	updateHeight(x)
	updateHeight(y)

	return y
}

func getBalance(node *TreeNode) int {
	if node == nil {
		return 0
	}
	return height(node.Left) - height(node.Right)
}

func insert(root *TreeNode, value int) *TreeNode {
	if root == nil {
		return &TreeNode{Value: value, Height: 1}
	}

	if value < root.Value {
		root.Left = insert(root.Left, value)
	} else if value > root.Value {
		root.Right = insert(root.Right, value)
	} else {
		// Duplicate values are not allowed
		return root
	}

	updateHeight(root)

	balance := getBalance(root)

	// Left-Left case
	if balance > 1 && value < root.Left.Value {
		return rotateRight(root)
	}

	// Right-Right case
	if balance < -1 && value > root.Right.Value {
		return rotateLeft(root)
	}

	// Left-Right case
	if balance > 1 && value > root.Left.Value {
		root.Left = rotateLeft(root.Left)
		return rotateRight(root)
	}

	// Right-Left case
	if balance < -1 && value < root.Right.Value {
		root.Right = rotateRight(root.Right)
		return rotateLeft(root)
	}

	return root
}

func inorderTraversal(root *TreeNode) {
	if root != nil {
		inorderTraversal(root.Left)
		fmt.Printf("%d ", root.Value)
		inorderTraversal(root.Right)
	}
}

func main() {
	var root *TreeNode

	values := []int{10, 5, 15, 3, 7, 12, 18}

	for _, value := range values {
		root = insert(root, value)
	}

	fmt.Println("Inorder Traversal of AVL Tree:")
	inorderTraversal(root)
	fmt.Println()
}

在這個示例中,我們定義了一個TreeNode結構來表示AVL樹的節點,包括值、左子樹、右子樹和高度。我們還實現了插入操作,以確保樹的平衡性。在main函式中,我們建立了一個AVL樹,插入了一些值,然後進行了中序遍歷以顯示樹的元素按升序排列。

滿二叉樹

滿二叉樹(Full Binary Tree)作為一種特殊型別的二叉樹,每個節點都有0或2個子節點,而且葉子節點都位於同一層。以下是一個用Go語言實現的滿二叉樹示例:

package main

import (
	"fmt"
)

type TreeNode struct {
	Value  int
	Left   *TreeNode
	Right  *TreeNode
}

func NewTreeNode(value int) *TreeNode {
	return &TreeNode{Value: value}
}

func main() {
	root := NewTreeNode(1)
	root.Left = NewTreeNode(2)
	root.Right = NewTreeNode(3)
	root.Left.Left = NewTreeNode(4)
	root.Left.Right = NewTreeNode(5)
	root.Right.Left = NewTreeNode(6)
	root.Right.Right = NewTreeNode(7)

	fmt.Println("Inorder Traversal of Full Binary Tree:")
	inorderTraversal(root)
	fmt.Println()
}

func inorderTraversal(root *TreeNode) {
	if root != nil {
		inorderTraversal(root.Left)
		fmt.Printf("%d ", root.Value)
		inorderTraversal(root.Right)
	}
}

在這個示例中,我們定義了一個TreeNode結構來表示滿二叉樹的節點,包括值、左子樹和右子樹。在main函式中,我們手動構建了一個滿二叉樹,並執行了中序遍歷以顯示樹的元素。請注意,滿二叉樹的特點是每個節點都有0或2個子節點,並且葉子節點都在同一層。這使得滿二叉樹在某些應用中具有特殊的優勢。

完全二叉樹

以下是一個用Go語言實現的完全二叉樹示例。在完全二叉樹中,除了最後一層,其他層都是滿的,最後一層的節點從左向右填充。

package main

import (
	"fmt"
)

type TreeNode struct {
	Value int
	Left  *TreeNode
	Right *TreeNode
}

func NewTreeNode(value int) *TreeNode {
	return &TreeNode{Value: value}
}

func main() {
	root := NewTreeNode(1)
	root.Left = NewTreeNode(2)
	root.Right = NewTreeNode(3)
	root.Left.Left = NewTreeNode(4)
	root.Left.Right = NewTreeNode(5)
	root.Right.Left = NewTreeNode(6)

	fmt.Println("Inorder Traversal of Complete Binary Tree:")
	inorderTraversal(root)
	fmt.Println()
}

func inorderTraversal(root *TreeNode) {
	if root != nil {
		inorderTraversal(root.Left)
		fmt.Printf("%d ", root.Value)
		inorderTraversal(root.Right)
	}
}

在這個示例中,我們定義了一個TreeNode結構來表示完全二叉樹的節點,包括值、左子樹和右子樹。在main函式中,我們手動構建了一個完全二叉樹,並執行了中序遍歷以顯示樹的元素。請注意,完全二叉樹的特點是除了最後一層,其他層都是滿的,最後一層的節點從左向右填充。這種結構在一些應用中具有特殊的性質,例如在堆資料結構中的應用。

二叉樹的應用

二叉樹在電腦科學和程式設計中有廣泛的應用,包括:

  1. 二叉搜尋樹的搜尋、插入和刪除操作: 用於高效地管理有序資料集合。
  2. 圖形學: 用於構建場景圖、動畫和圖形渲染。
  3. 檔案系統: 檔案和目錄的組織通常以樹的形式表示,以實現高效的檔案檢索和管理。
  4. 資料壓縮: 哈夫曼樹(Huffman Tree)用於資料壓縮。
  5. 編譯器: 語法分析器使用語法樹來表示程式的結構,以進行編譯和最佳化。
  6. 網路路由: 網路路由演算法使用樹結構來確定最佳路徑。
  7. 人工智慧: 決策樹用於模擬決策和行為。

二叉樹的遍歷

二叉樹的遍歷是一種常見的操作,用於訪問樹中的所有節點。主要的遍歷方法包括:

  1. 前序遍歷(Preorder Traversal): 從根節點開始,首先訪問根節點,然後依次遍歷左子樹和右子樹。
  2. 中序遍歷(Inorder Traversal): 從根節點開始,首先遍歷左子樹,然後訪問根節點,最後遍歷右子樹。對於二叉搜尋樹,中序遍歷可以得到有序的結果。
  3. 後序遍歷(Postorder Traversal): 從根節點開始,首先遍歷左子樹和右子樹,最後訪問根節點。
  4. 層序遍歷(Level-order Traversal): 從樹的頂部開始,逐層遍歷節點,首先訪問根節點,然後依次遍歷每一層的節點。

二叉樹的遍歷是許多樹操作的基礎,它們可以用於搜尋、資料提取、樹的複製等任務。


孟斯特

宣告:本作品採用署名-非商業性使用-相同方式共享 4.0 國際 (CC BY-NC-SA 4.0)進行許可,使用時請註明出處。
Author: mengbin
blog: mengbin
Github: mengbin92
cnblogs: 戀水無意


相關文章