深入理解資料結構--二叉樹(進階篇1)

oliver-l發表於2021-09-14

在上篇整理了二叉樹的相對基礎的資訊深入理解資料結構–二叉樹(基礎篇)

接下來深入講解二叉樹的進階內容

二叉查詢樹

二叉查詢樹(Binary Search Tree),顧名思義,是用來查詢資料的。它在二叉樹的基礎上,增加了幾個規則:

  1. 如果左子樹不為空,則左子樹上所有節點的值均小於根節點的值。
  2. 如果右子樹不為空,則右子樹上所有節點的值均大於根節點的值。
  3. 左、右子樹也都是二叉查詢樹。

下圖就是一顆標準的二叉查詢樹:

深入理解資料結構--二叉樹(進階篇1)

二叉樹的程式碼結構用go的結構體來實現如下:

type binaryTree struct {
    value int
    leftNode *binaryTree
    rightNode *binaryTree
}

二叉查詢樹有三個操作:查詢、插入和刪除

二叉樹的查詢

假設我們要查詢的值是4,查詢過程如下:

  1. 訪問根節點6,發現4<6

深入理解資料結構--二叉樹(進階篇1)

  1. 訪問根節點6的左孩子節點3,發現4>3

深入理解資料結構--二叉樹(進階篇1)

  1. 訪問節點3的右孩子節點4,發現正是要查詢的節點

深入理解資料結構--二叉樹(進階篇1)

對於一個節點分佈相對平衡的二叉查詢樹,如果節點總數是n,那麼查詢節點的時間複雜度就是O(logn),和樹的深度成正比

實現程式碼如下:

//節點查詢
func findNode(num int,tree *binaryTree) bool{
    targetNode := tree
    for targetNode != nil{
        if targetNode.value == num {
            return true
        }else if targetNode.value > num {
            targetNode = targetNode.leftNode
        }else {
            targetNode = targetNode.rightNode
        }
    }
    return false
}

二叉樹的插入

二叉樹的插入遍歷過程與查詢類似,這裡就直接寫程式碼實現

//節點插入
func insertNode(tree *binaryTree,node *binaryTree) *binaryTree {

    if tree.value == 0 {
        return node
    }
    if tree.value == node.value {
        return tree
    }else if tree.value > node.value {
        //往左子樹走,為空則直接插入節點
        if tree.leftNode == nil {
            tree.leftNode = node
        }else {
            tree.leftNode = insertNode(tree.leftNode,node)
        }
    }else {
        //往右子樹走,為空則直接插入節點
        if tree.rightNode == nil {
            tree.rightNode = node
        }else {
            tree.rightNode = insertNode(tree.rightNode,node)
        }
    }
    return tree
}

二叉樹的刪除

相對查詢和插入,二叉樹的刪除過程相對複雜一些,程式碼實現上也有對應的邏輯

二叉樹的刪除操作,可分為三種情況:

情況1,待刪除的節點沒有子節點

深入理解資料結構--二叉樹(進階篇1)

上圖中,待刪除的節點12是葉子節點,沒有孩子,因此直接刪除即可

深入理解資料結構--二叉樹(進階篇1)

情況2,待刪除的節點有一個孩子

深入理解資料結構--二叉樹(進階篇1)

上圖中,待刪除的節點13只有左孩子,於是我們讓左孩子節點11取代被刪除的節點,節點11以下的節點關係無須變動

深入理解資料結構--二叉樹(進階篇1)

情況3,待刪除的節點有兩個孩子

深入理解資料結構--二叉樹(進階篇1)

上圖中,待刪除的節點5有兩個孩子,這種情況比較複雜。需要選擇與待刪除節點最接近的節點來取代它。

上面的例子中,節點3僅小於節點5,節點6僅大於節點5.兩者都是合適的選擇。但習慣上我們選擇僅大於待刪除節點的節點,也就是用節點6來取代它。

深入理解資料結構--二叉樹(進階篇1)

被選中的節點6,僅大於節點5,因此一定沒有左孩子。所以我們按照情況1或情況2的方式,刪除多餘的節點6。

深入理解資料結構--二叉樹(進階篇1)

程式碼實現如下,實現上相對複雜一點,需要運用遞迴的方式去處理:


//刪除節點
func deleteNode(num int,tree *binaryTree) *binaryTree{
   //先檢視刪除的值是否存在樹當中
  find := findNode(num,tree)
   if find {
      //配置到節點值,執行刪除操作
  if tree.value == num {
         //刪除的節點無左右節點
  if tree.leftNode == nil && tree.rightNode == nil {
            tree = &binaryTree{}
         }else if tree.leftNode == nil && tree.rightNode != nil {
            //左節點為空,右節點不為空
  tree = tree.rightNode
         }else if tree.rightNode == nil && tree.leftNode != nil {
            //右節點為空,左節點不為空
  tree = tree.leftNode
         }else{
            //節點左右節點都存在
  tree = replaceNode(tree)
         }
      }else if tree.value > num {
         tree.leftNode = deleteNode(num,tree.leftNode)
      }else {
         tree.rightNode = deleteNode(num,tree.rightNode)
      }
   }
   return tree
}

//替換刪除節點
func replaceNode(tree *binaryTree) *binaryTree{
   //刪除的節點無左右節點
  if tree.leftNode == nil && tree.rightNode == nil {
      tree = &binaryTree{}
   }else if tree.leftNode == nil && tree.rightNode != nil {
      //左節點為空,右節點不為空
  tree = tree.rightNode
   }else if tree.rightNode == nil && tree.leftNode != nil {
      //右節點為空,左節點不為空
  tree = tree.leftNode
   }else{
      //節點左右節點都存在,則從右子樹查詢節點替代父節點
 //若右節點下沒有左右節點,則直接用右節點的值替換,並刪除右節點  
     if tree.rightNode.leftNode == nil && tree.rightNode.rightNode == nil {
         tree.value = tree.rightNode.value
         tree.rightNode = &binaryTree{}
      }else if tree.rightNode.leftNode == nil && tree.rightNode.rightNode != nil {
         //若右節點下左節點為空,右節點不為空,則右節點的值替換,並將右節點的右節點替換過來
  tree.value = tree.rightNode.value
         tree.rightNode = tree.rightNode.rightNode
      }else{
         //若右節點的左節點不為空
  tree.value = tree.rightNode.leftNode.value
         tree.rightNode.leftNode = replaceNode(tree.rightNode.leftNode)
      }
   }
   return tree
}

實現二叉查詢樹的完整程式碼如下,二叉查詢樹的中序遍歷可獲取到已排序完成的節點,所以這裡用中序遍歷來判斷是否執行成功

package main

import "fmt"

type binaryTree struct {
    value int
    leftNode *binaryTree
    rightNode *binaryTree
}

func main(){

    var numArr = []int{10,11,4,2,8,1,3,6,9,5,7}

    tree := createBinarySearchTree(numArr)
    find := findNode(9,tree)
    fmt.Print(find)
    tree = deleteNode(4,tree)
    node := &binaryTree{13,nil,nil}
    tree = insertNode(tree,node)
    node = &binaryTree{1,nil,nil}

    var middle []int
    middle = middleForeach(*tree,middle)
    fmt.Println(middle)
}

//建立平衡二叉樹
func createBinarySearchTree(nums []int) *binaryTree{
    tree := new(binaryTree)
    for index := range nums{
        node := &binaryTree{nums[index],nil,nil}
        tree = insertNode(tree,node)
    }
    return tree
}

//刪除節點
func deleteNode(num int,tree *binaryTree) *binaryTree{
    //先檢視刪除的值是否存在樹當中
    find := findNode(num,tree)
    if find {
        //配置到節點值,執行刪除操作
        if tree.value == num {
            //刪除的節點無左右節點
            if tree.leftNode == nil && tree.rightNode == nil {
                tree = &binaryTree{}
            }else if tree.leftNode == nil && tree.rightNode != nil {
                //左節點為空,右節點不為空
                tree = tree.rightNode
            }else if tree.rightNode == nil && tree.leftNode != nil {
                //右節點為空,左節點不為空
                tree = tree.leftNode
            }else{
                //節點左右節點都存在
                tree = replaceNode(tree)
            }
        }else if tree.value > num {
            tree.leftNode = deleteNode(num,tree.leftNode)
        }else {
            tree.rightNode = deleteNode(num,tree.rightNode)
        }
    }
    return tree
}

//替換刪除節點
func replaceNode(tree *binaryTree) *binaryTree{
    //刪除的節點無左右節點
    if tree.leftNode == nil && tree.rightNode == nil {
        tree = &binaryTree{}
    }else if tree.leftNode == nil && tree.rightNode != nil {
        //左節點為空,右節點不為空
        tree = tree.rightNode
    }else if tree.rightNode == nil && tree.leftNode != nil {
        //右節點為空,左節點不為空
        tree = tree.leftNode
    }else{
        //節點左右節點都存在,則從右子樹查詢節點替代父節點
        //若右節點下沒有左右節點,則直接用右節點的值替換,並刪除右節點
        if tree.rightNode.leftNode == nil && tree.rightNode.rightNode == nil {
            tree.value = tree.rightNode.value
            tree.rightNode = &binaryTree{}
        }else if tree.rightNode.leftNode == nil && tree.rightNode.rightNode != nil {
            //若右節點下左節點為空,右節點不為空,則右節點的值替換,並將右節點的右節點替換過來
            tree.value = tree.rightNode.value
            tree.rightNode = tree.rightNode.rightNode
        }else{
            //若右節點的左節點不為空
            tree.value = tree.rightNode.leftNode.value
            tree.rightNode.leftNode = replaceNode(tree.rightNode.leftNode)
        }
    }
    return tree
}

//節點查詢
func findNode(num int,tree *binaryTree) bool{
    targetNode := tree
    for targetNode != nil{
        if targetNode.value == num {
            return true
        }else if targetNode.value > num {
            targetNode = targetNode.leftNode
        }else {
            targetNode = targetNode.rightNode
        }
    }
    return false
}

//節點插入
func insertNode(tree *binaryTree,node *binaryTree) *binaryTree {

    if tree.value == 0 {
        return node
    }
    if tree.value == node.value {
        return tree
    }else if tree.value > node.value {
        //往左子樹走,為空則直接插入節點
        if tree.leftNode == nil {
            tree.leftNode = node
        }else {
            tree.leftNode = insertNode(tree.leftNode,node)
        }
    }else {
        //往右子樹走,為空則直接插入節點
        if tree.rightNode == nil {
            tree.rightNode = node
        }else {
            tree.rightNode = insertNode(tree.rightNode,node)
        }
    }
    return tree
}

//中序遍歷
func middleForeach(tree binaryTree,num []int) []int{
    var leftNum,rightNum []int
    //若存在左節點,遍歷左節點樹
    if tree.leftNode != nil {
        leftNum = middleForeach(*tree.leftNode,leftNum)
        for _,value := range leftNum{
            num = append(num,value)
        }
    }

    //先遍歷根節點
    if tree.value != 0 {
        num = append(num,tree.value)
    }

    //若存在右節點,遍歷右節點樹
    if tree.rightNode != nil {
        rightNum = middleForeach(*tree.rightNode,rightNum)
        for _,value := range rightNum{
            num = append(num,value)
        }
    }

    return num
}

二叉樹的缺陷

假設初始的二叉查詢樹只有三個節點,根節點為9,左孩子為8,右孩子為12

深入理解資料結構--二叉樹(進階篇1)

接下來我們依次插入如下五個節點:7,6,5,4,3。依照二叉查詢樹的特性,結果會變成什麼樣呢?

深入理解資料結構--二叉樹(進階篇1)

雖然這樣一棵樹也符合二叉查詢樹的特性,但是查詢節點的時間複雜度退化成了O(n)

二叉平衡樹

二叉平衡樹是一種特性的二叉查詢樹,也被稱為AVL樹。它在每次插入、刪除節點之後,可以進行“自平衡”,也就是通過一系列調整重新達到平衡狀態。

平衡因子

下圖就是一顆典型的AVL樹,每個節點旁邊都標註了平衡因子

深入理解資料結構--二叉樹(進階篇1)

其中節點4的左子樹高度是1,右子樹不存在,所以該節點的平衡因子是1-0=1
其中7的左子樹不存在,右子樹高度是1,所以平衡因子是0-1=-1
所有的葉子節點,不存在左右子樹,所以平衡因子都是0
AVL樹對平衡因子的限制(只能是-1,0,1),保證了任意節點的兩棵樹的高度差都不超過1,這種狀態被稱為高度平衡

以下是對計算樹平衡因子的程式碼實現,首先要計算左右子樹的高度,然後得到平衡因子,還新增了方法用於判斷樹是否達到平衡

//檢查樹是否達到平衡
func (tree binaryTree) isBalance() bool {
   if tree.RightNode == nil && tree.LeftNode == nil {
      return true
  }
   //節點的平衡因子
  factor := tree.getTreeFactor()
   if factor > 1 || factor < -1 {
      return false
  }
   return true
}

//獲取節點的平衡因子
func (tree binaryTree) getTreeFactor() int{
    leftFactor,rightFactor := 0,0
    if tree.RightNode != nil {
        rightFactor = tree.RightNode.getTreeHeight()
    }
    if tree.LeftNode != nil {
        leftFactor = tree.LeftNode.getTreeHeight()
    }
    factor := float64(leftFactor - rightFactor)
    return int(factor)
}

//獲取節點樹高度,深度優先
func (tree binaryTree) getTreeHeight() int{
   //節點無
  if tree.RightNode == nil && tree.LeftNode == nil {
      return 1
  }
   leftHeight,rightHeight := 1,1
  if tree.LeftNode != nil && tree.LeftNode.Value != 0 {
      leftHeight = 1 + tree.LeftNode.getTreeHeight()
   }
   if tree.RightNode != nil && tree.RightNode.Value != 0{
      rightHeight = 1 + tree.RightNode.getTreeHeight()
   }
   //比較左右節點樹高度
  height := math.Max(float64(leftHeight),float64(rightHeight))
   return int(height)
}

樹平衡調整

當插入節點導致平衡因子被打破,這時候需要對樹進行調整,AVL樹調整可分為4種情況

  1. 左左局面(LL)

深入理解資料結構--二叉樹(進階篇1)

顧名思義,祖父節點A右一個左孩子節點B,而節點B又有一個左孩子節點C。標號1,2,3,4的三角形是各個節點的子樹。

在這種局面下,我們以節點A為軸,進行右旋操作:

深入理解資料結構--二叉樹(進階篇1)

  1. 右右局面(RR)

深入理解資料結構--二叉樹(進階篇1)

祖父節點A有一個右孩子節點B,而節點B又有一個右孩子節點C。
在這種局面下,我們以節點A為軸,進行左旋操作。

深入理解資料結構--二叉樹(進階篇1)

  1. 左右局面(LR)

深入理解資料結構--二叉樹(進階篇1)

祖父節點A有一個左孩子節點B,而節點B又有一個右孩子節點C。
在這種局面下,我們先以節點B為軸,進行左旋操作。

深入理解資料結構--二叉樹(進階篇1)

這樣就轉化成了左左局面。我們繼續以節點A為軸,進行右旋操作。

深入理解資料結構--二叉樹(進階篇1)

  1. 右左局面(RL)

深入理解資料結構--二叉樹(進階篇1)

祖父節點A右一個右孩子節點B,而節點B又有一個左孩子節點C。
在這種局面下,我們先以節點B為軸,進行右旋操作。

深入理解資料結構--二叉樹(進階篇1)

這樣就轉化成了右右局面。我們繼續以節點A為軸,進行左旋操作。

深入理解資料結構--二叉樹(進階篇1)

程式碼實現如下:

//左左局面
func LeftLeftRotate(tree *binaryTree) *binaryTree{
    //原節點左節點成為根節點
    mainNode := tree.LeftNode
    changeNode := &binaryTree{}
    //判斷原節點左節點是否存在
    if mainNode.RightNode != nil {
        changeNode = mainNode.RightNode
    }
    mainRightNode := tree
    mainRightNode.LeftNode = changeNode
    //重新整理樹高度
    mainRightNode.Height = mainRightNode.getTreeHeight()
    mainNode.RightNode = mainRightNode
    mainNode.Height = mainNode.getTreeHeight()
    return mainNode
}

//右右局面
func RightRightRotate(tree *binaryTree) *binaryTree{
    mainNode := tree.RightNode
    changeNode := &binaryTree{}
    if mainNode.LeftNode != nil {
        changeNode = mainNode.LeftNode
    }
    mainLeftNode := tree
    mainLeftNode.RightNode = changeNode
    mainLeftNode.Height = mainLeftNode.getTreeHeight()
    mainNode.LeftNode = mainLeftNode
    mainNode.Height = mainNode.getTreeHeight()
    return mainNode
}

//左右局面
func LeftRightRotate(tree *binaryTree) *binaryTree{
    mainLeftNode := tree.LeftNode
    changeNode := &binaryTree{}
    mainNode := mainLeftNode.RightNode
    if mainNode.LeftNode != nil {
        changeNode = mainNode.LeftNode
    }
    mainLeftNode.RightNode = changeNode
    mainLeftNode.Height = mainLeftNode.getTreeHeight()
    mainNode.LeftNode = mainLeftNode
    mainNode.Height = mainNode.getTreeHeight()
    tree.LeftNode = mainNode
    tree = LeftLeftRotate(tree)
    return tree
}

//右左局面
func RightLightRotate(tree *binaryTree) *binaryTree{
    mainRightNode := tree.RightNode
    changeNode := &binaryTree{}
    mainNode := mainRightNode.LeftNode
    if mainNode.RightNode != nil {
        changeNode = mainNode.RightNode
    }
    mainRightNode.LeftNode = changeNode
    mainRightNode.Height = mainRightNode.getTreeHeight()
    mainNode.RightNode = mainRightNode
    mainNode.Height = mainNode.getTreeHeight()
    tree.RightNode = mainNode
    tree = RightRightRotate(tree)
    return tree
}

二叉平衡樹的插入和刪除

在程式碼實現上,可以複用二叉查詢樹的程式碼邏輯,在二叉查詢樹的基礎上新增邏輯,在節點的插入和刪除後,新增判斷邏輯,判斷二叉平衡樹的平衡是否被破壞,若被破壞則進行相關的調整,過程就不多贅述,直接上完整實現程式碼

package main

import (
    "fmt"
    "math"
)

type binaryTree struct {
    Value int
    Height int
    LeftNode *binaryTree
    RightNode *binaryTree
}

func main(){
    var numArr = []int{10,11,4,2,8,1,3,6,9,5,7,12}
    tree := createBinaryBalanceTree(numArr)
    var middle []int
    tree = deleteNode(9,tree)
    tree = deleteNode(11,tree)
    tree = deleteNode(12,tree)
    fmt.Println("\n")
    middle := middleForeach(*tree,middle)
    fmt.Println(middle,"\n")
}


//獲取節點樹高度,深度優先
func (tree binaryTree) getTreeHeight() int{
    //節點無
    if tree.RightNode == nil && tree.LeftNode == nil {
        return 1
    }
    leftHeight,rightHeight := 1,1
    if tree.LeftNode != nil && tree.LeftNode.Value != 0 {
        leftHeight = 1 + tree.LeftNode.getTreeHeight()
    }
    if tree.RightNode != nil && tree.RightNode.Value != 0{
        rightHeight = 1 + tree.RightNode.getTreeHeight()
    }
    //比較左右節點樹高度
    height := math.Max(float64(leftHeight),float64(rightHeight))
    return int(height)
}

//檢查樹是否達到平衡
func (tree binaryTree) isBalance() bool {
    if tree.RightNode == nil && tree.LeftNode == nil {
        return true
    }
    //節點的平衡因子
    factor := tree.getTreeFactor()
    if factor > 1 || factor < -1 {
        return false
    }
    return true
}

//獲取節點的平衡因子
func (tree binaryTree) getTreeFactor() int{
    leftFactor,rightFactor := 0,0
    if tree.RightNode != nil {
        rightFactor = tree.RightNode.getTreeHeight()
    }
    if tree.LeftNode != nil {
        leftFactor = tree.LeftNode.getTreeHeight()
    }
    factor := float64(leftFactor - rightFactor)
    return int(factor)
}

//建立二叉平衡樹
func createBinaryBalanceTree(nums []int) *binaryTree{
    tree := new(binaryTree)
    for index := range nums{
        node := &binaryTree{Value: nums[index]}
        tree = insertNode(tree,node)
    }
    return tree
}

//插入節點
func insertNode(tree *binaryTree,node *binaryTree) *binaryTree {

    if tree.Value == 0 {
        return node
    }
    if tree.Value == node.Value {
        return tree
    }else if tree.Value > node.Value {
        //往左子樹走,為空則直接插入節點
        if tree.LeftNode == nil {
            tree.LeftNode = node
        }else {
            tree.LeftNode = insertNode(tree.LeftNode,node)
        }
        //節點高度重置
        tree.LeftNode.Height = tree.LeftNode.getTreeHeight()
    }else {
        //往右子樹走,為空則直接插入節點
        if tree.RightNode == nil {
            tree.RightNode = node
        }else {
            tree.RightNode = insertNode(tree.RightNode,node)
        }
        //節點高度重置
        tree.RightNode.Height = tree.RightNode.getTreeHeight()
    }
    //節點高度重置
    tree.Height = tree.getTreeHeight()
    //節點不平衡
    if !tree.isBalance() {
        //tree = treeInsertRotateBalance(node,tree)
        //左子樹偏大
        if tree.getTreeFactor() > 1 {
            if node.Value < tree.LeftNode.Value {
                tree = LeftLeftRotate(tree)
            }else {
                tree = LeftRightRotate(tree)
            }
        }else {
            //右子樹偏大
            if node.Value > tree.RightNode.Value {
                tree = RightRightRotate(tree)
            }else {
                tree = RightLightRotate(tree)
            }
        }
    }
    return tree
}


//刪除節點
func deleteNode(num int,tree *binaryTree) *binaryTree{
    //先檢視刪除的值是否存在樹當中
    find := findNode(num,tree)
    if find {
        //配置到節點值,執行刪除操作
        if tree.Value == num {
            //刪除的節點無左右節點
            if tree.LeftNode == nil && tree.RightNode == nil {
                tree = &binaryTree{}
            }else if tree.LeftNode == nil && tree.RightNode != nil {
                //左節點為空,右節點不為空
                tree = tree.RightNode
            }else if tree.RightNode == nil && tree.LeftNode != nil {
                //右節點為空,左節點不為空
                tree = tree.LeftNode
            }else{
                //節點左右節點都存在
                tree = replaceNode(tree)
            }
        }else if tree.Value > num {
            tree.LeftNode = deleteNode(num,tree.LeftNode)
        }else {
            tree.RightNode = deleteNode(num,tree.RightNode)
        }
        tree.Height = tree.getTreeHeight()
    }
    if !tree.isBalance() {
        if tree.getTreeFactor() > 1 {
            if num > tree.Value {
                tree = LeftLeftRotate(tree)
            }else {
                tree = LeftRightRotate(tree)
            }
        }else {
            if num < tree.Value {
                tree = RightRightRotate(tree)
            }else {
                tree = RightLightRotate(tree)
            }
        }
    }
    return tree
}

//替換刪除節點
func replaceNode(tree *binaryTree) *binaryTree{
    //刪除的節點無左右節點
    if tree.LeftNode == nil && tree.RightNode == nil {
        tree = &binaryTree{}
    }else if tree.LeftNode == nil && tree.RightNode != nil {
        //左節點為空,右節點不為空
        tree = tree.RightNode
    }else if tree.RightNode == nil && tree.LeftNode != nil {
        //右節點為空,左節點不為空
        tree = tree.LeftNode
    }else{
        //節點左右節點都存在,則從右子樹查詢節點替代父節點
        //若右節點下沒有左右節點,則直接用右節點的值替換,並刪除右節點
        if tree.RightNode.LeftNode == nil && tree.RightNode.RightNode == nil {
            tree.Value = tree.RightNode.Value
            tree.RightNode = &binaryTree{}
        }else if tree.RightNode.LeftNode == nil && tree.RightNode.RightNode != nil {
            //若右節點下左節點為空,右節點不為空,則右節點的值替換,並將右節點的右節點替換過來
            tree.Value = tree.RightNode.Value
            tree.RightNode = tree.RightNode.RightNode
        }else{
            //若右節點的左節點不為空
            tree.Value = tree.RightNode.LeftNode.Value
            tree.RightNode.LeftNode = replaceNode(tree.RightNode.LeftNode)
        }
    }
    return tree
}

//左左局面
func LeftLeftRotate(tree *binaryTree) *binaryTree{
    //原節點左節點成為根節點
    mainNode := tree.LeftNode
    changeNode := &binaryTree{}
    //判斷原節點左節點是否存在
    if mainNode.RightNode != nil {
        changeNode = mainNode.RightNode
    }
    mainRightNode := tree
    mainRightNode.LeftNode = changeNode
    //重新整理樹高度
    mainRightNode.Height = mainRightNode.getTreeHeight()
    mainNode.RightNode = mainRightNode
    mainNode.Height = mainNode.getTreeHeight()
    return mainNode
}

//右右局面
func RightRightRotate(tree *binaryTree) *binaryTree{
    mainNode := tree.RightNode
    changeNode := &binaryTree{}
    if mainNode.LeftNode != nil {
        changeNode = mainNode.LeftNode
    }
    mainLeftNode := tree
    mainLeftNode.RightNode = changeNode
    mainLeftNode.Height = mainLeftNode.getTreeHeight()
    mainNode.LeftNode = mainLeftNode
    mainNode.Height = mainNode.getTreeHeight()
    return mainNode
}

//左右局面
func LeftRightRotate(tree *binaryTree) *binaryTree{
    mainLeftNode := tree.LeftNode
    changeNode := &binaryTree{}
    mainNode := mainLeftNode.RightNode
    if mainNode.LeftNode != nil {
        changeNode = mainNode.LeftNode
    }
    mainLeftNode.RightNode = changeNode
    mainLeftNode.Height = mainLeftNode.getTreeHeight()
    mainNode.LeftNode = mainLeftNode
    mainNode.Height = mainNode.getTreeHeight()
    tree.LeftNode = mainNode
    tree = LeftLeftRotate(tree)
    return tree
}

//右左局面
func RightLightRotate(tree *binaryTree) *binaryTree{
    mainRightNode := tree.RightNode
    changeNode := &binaryTree{}
    mainNode := mainRightNode.LeftNode
    if mainNode.RightNode != nil {
        changeNode = mainNode.RightNode
    }
    mainRightNode.LeftNode = changeNode
    mainRightNode.Height = mainRightNode.getTreeHeight()
    mainNode.RightNode = mainRightNode
    mainNode.Height = mainNode.getTreeHeight()
    tree.RightNode = mainNode
    tree = RightRightRotate(tree)
    return tree
}

//節點查詢
func findNode(num int,tree *binaryTree) bool{
    targetNode := tree
    for targetNode != nil{
        if targetNode.Value == num {
            return true
        }else if targetNode.Value > num {
            targetNode = targetNode.LeftNode
        }else {
            targetNode = targetNode.RightNode
        }
    }
    return false
}

//中序遍歷
func middleForeach(tree binaryTree,num []int) []int{
    var leftNum,rightNum []int
    //若存在左節點,遍歷左節點樹
    if tree.LeftNode != nil {
        leftNum = middleForeach(*tree.LeftNode,leftNum)
        for _,value := range leftNum{
            num = append(num,value)
        }
    }

    //先遍歷根節點
    if tree.Value != 0 {
        num = append(num,tree.Value)
    }

    //若存在右節點,遍歷右節點樹
    if tree.RightNode != nil {
        rightNum = middleForeach(*tree.RightNode,rightNum)
        for _,value := range rightNum{
            num = append(num,value)
        }
    }

    return num
}

程式碼實現上相對有點複雜,在開始編寫的時候還是有點難度,但是完成後發現給自己帶來了特別大的成就感,或許這也是寫程式碼的樂趣吧。後續會繼續學習,爭取把紅黑樹也實現了。

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

相關文章