Golang-樹-二叉樹
1.初始化
mkdir -p binaryTree
cd binaryTree
go mod init binaryTree
touch binaryTree.go
vim binaryTree.go
2.定義二叉樹結點結構體
// 定義二叉樹結點結構體
type BinaryTreeNode struct {
// 數據域
Data interface{}
// 左子結點
Lchild *BinaryTreeNode
// 右子結點
Rchild *BinaryTreeNode
}
3.根據圖創建二叉樹
// 根據圖創建二叉樹
func (node *BinaryTreeNode) CreateBinaryTree() {
if node == nil {
return
}
node1 := &BinaryTreeNode{1, nil, nil}
node2 := &BinaryTreeNode{2, nil, nil}
node3 := &BinaryTreeNode{3, nil, nil}
node4 := &BinaryTreeNode{4, nil, nil}
node5 := &BinaryTreeNode{5, nil, nil}
node6 := &BinaryTreeNode{6, nil, nil}
node7 := &BinaryTreeNode{7, nil, nil}
node.Data = 0
node.Lchild = node1
node1.Lchild = node3
node1.Rchild = node4
node3.Lchild = node7
node.Rchild = node2
node2.Lchild = node5
node2.Rchild = node6
}
測試
func main() {
tree := new(BinaryTreeNode)
tree.CreateBinaryTree()
fmt.Println(tree) // &{0 0xc0000044c0 0xc0000044e0} // 數據,左子節點,右子節點
}
4.打印二叉樹
二叉樹的遍歷的前提都是【先左右後】
先序、中序、後序遍歷是取決於根、如果根在前就是先序DLR(Data,Lchild,Rchild),根在中間即中序LDR(Lchild,Data,Rchild)、根在後就是後序LRD(Lchild,Rchild,Data)
1.先序遍歷DLR
根、左子樹、右子樹
// 打印二叉樹---先序遍歷DLR:先根、再左、再右
func (node *BinaryTreeNode) PreOrderPrint() {
// 容錯處理,同時也是遞歸出口
if node == nil {
return
}
// 根(Data)
fmt.Print(node.Data, " ")
// 左子樹(Lchild)遞歸調用
node.Lchild.PreOrderPrint()
// 右子樹(Rchild)遞歸調用
node.Rchild.PreOrderPrint()
}
測試
func main() {
tree := new(BinaryTreeNode)
tree.CreateBinaryTree()
fmt.Println("先序遍歷結果:")
tree.PreOrderPrint()
}
0 1 3 7 4 2 5 6
2.中序遍歷LDR
左子樹、根、右子樹
// 打印二叉樹---中序遍歷LDR:先左、再根、再右
func (node *BinaryTreeNode) MidOrderPrint() {
// 容錯處理,同時也是遞歸出口
if node == nil {
return
}
// 左子樹(Lchild)遞歸調用
node.Lchild.MidOrderPrint()
// 根(Data)
fmt.Print(node.Data, " ")
// 右子樹(Rchild)遞歸調用
node.Rchild.MidOrderPrint()
}
測試
func main() {
tree := new(BinaryTreeNode)
tree.CreateBinaryTree()
fmt.Println("中序遍歷結果:")
tree.MidOrderPrint()
}
7 3 1 4 0 5 2 6
3.後序遍歷LRD
左子樹、右子樹 、根
// 打印二叉樹---後序遍歷LRD:先左、再右、再根
func (node *BinaryTreeNode) PostOrderPrint() {
// 容錯處理,同時也是遞歸出口
if node == nil {
return
}
// 左子樹(Lchild)遞歸調用
node.Lchild.PostOrderPrint()
// 右子樹(Rchild)遞歸調用
node.Rchild.PostOrderPrint()
// 根(Data)
fmt.Print(node.Data, " ")
}
測試
func main() {
tree := new(BinaryTreeNode)
tree.CreateBinaryTree()
fmt.Println("後序遍歷結果:")
tree.PostOrderPrint()
}
7 3 4 1 5 6 2 0
5.獲取二叉樹高度/深度
// 獲取二叉樹樹高/深度
func (node *BinaryTreeNode) TreeHeight() int {
// 容錯處理,同時也是遞歸出口
if node == nil {
return 0 // 不能返回-1,否則少一個深度
}
// 左子樹遞歸探求深度
lch := node.Lchild.TreeHeight()
// 右子樹遞歸探求深度
rch := node.Rchild.TreeHeight()
if lch > rch {
// 每一次遞歸深度自增
lch++
return lch
} else {
// 每一次遞歸深度自增
rch++
return rch
}
}
測試
func main() {
tree := new(BinaryTreeNode)
tree.CreateBinaryTree()
th := tree.TreeHeight()
fmt.Println("二叉樹書高:", th)
}
4
6.獲取二叉樹葉子節點數
// 獲取二叉樹葉子節點數
func (node *BinaryTreeNode) LeafNumber() (number int) {
// 容錯處理
if node == nil {
return
}
// 判斷是否是葉子節點:左子樹爲nil,同時右子樹也爲nil
if node.Lchild == nil && node.Rchild == nil {
number++
}
// 左子樹(Lchild)遞歸調用
number += node.Lchild.LeafNumber()
// 右子樹(Rchild)遞歸調用
number += node.Rchild.LeafNumber()
return
}
// 獲取二叉樹葉子節點數--指針傳參
func (node *BinaryTreeNode) LeafNumber2(number *int) {
// 容錯處理
if node == nil {
return
}
// 判斷是否是葉子節點:左子樹爲nil,同時右子樹也爲nil
if node.Lchild == nil && node.Rchild == nil {
*number++
}
// 左子樹(Lchild)遞歸調用
node.Lchild.LeafNumber2(number)
// 右子樹(Rchild)遞歸調用
node.Rchild.LeafNumber2(number)
return
}
測試
func main() {
tree := new(BinaryTreeNode)
tree.CreateBinaryTree()
number := tree.LeafNumber()
fmt.Println("二叉樹葉子節點:", number)
num := 0
tree.LeafNumber2(&num)
fmt.Println("二叉樹葉子節點:", num)
}
4
7.查找二叉樹數據
// 查找二叉樹數據
func (node *BinaryTreeNode) Search(data interface{}, b *bool) {
if node == nil || data == nil {
return
}
// 比較數據類型和值是否一致
if reflect.DeepEqual(node.Data, data) && reflect.TypeOf(node.Data) == reflect.TypeOf(data) {
*b = true
return
}
// 左子樹(Lchild)遞歸調用
node.Lchild.Search(data, b)
// 右子樹(Rchild)遞歸調用
node.Rchild.Search(data, b)
}
測試
func main() {
tree := new(BinaryTreeNode)
tree.CreateBinaryTree()
number := 13
b := false
tree.Search(number, &b)
fmt.Printf("二叉樹是否存在數據 %d : %v\r\n", number, b)
}
8.銷燬二叉樹
// 銷燬二叉樹
func (node *BinaryTreeNode) Destroy() {
if node == nil {
return
}
// 左子樹(Lchild)遞歸調用
node.Lchild.Destroy()
// 銷燬數據,促使GC工作
node.Data = nil
node.Lchild = nil
// 右子樹(Rchild)遞歸調用
node.Rchild.Destroy()
// 銷燬數據,促使GC工作
node.Data = nil
node.Rchild = nil
}
測試
func main() {
tree := new(BinaryTreeNode)
tree.CreateBinaryTree()
fmt.Println("銷燬前:")
tree.PreOrderPrint()
fmt.Println()
tree.Destroy()
fmt.Println("銷燬後:")
tree.PreOrderPrint()
}
或者可以直接tree = nil
9.翻轉(滿二叉樹)
完全二叉樹
- 除最後一層外,每一層的結點數都達到最大值。(左子、右子都不缺)
- “滿二叉樹” 是“完全二叉樹”的特例!
滿二叉樹
每個結點都有 左子結點、右子結點 的 二叉樹。
將創建二叉樹的7的葉子節點註釋掉形成滿二叉樹:
// 根據圖創建二叉樹
func (node *BinaryTreeNode) CreateBinaryTree() {
if node == nil {
return
}
node1 := &BinaryTreeNode{1, nil, nil}
node2 := &BinaryTreeNode{2, nil, nil}
node3 := &BinaryTreeNode{3, nil, nil}
node4 := &BinaryTreeNode{4, nil, nil}
node5 := &BinaryTreeNode{5, nil, nil}
node6 := &BinaryTreeNode{6, nil, nil}
// node7 := &BinaryTreeNode{7, nil, nil}
node.Data = 0
node.Lchild = node1
node1.Lchild = node3
node1.Rchild = node4
// node3.Lchild = node7
node.Rchild = node2
node2.Lchild = node5
node2.Rchild = node6
}
翻轉操作
// 二叉樹翻轉(滿二叉樹)
func (node *BinaryTreeNode) Reverse() {
if node == nil {
return
}
// 左子樹和右子樹交換位置,go的多重賦值實現
node.Lchild, node.Rchild = node.Rchild, node.Lchild
// 左子樹(Lchild)遞歸調用
node.Lchild.Reverse()
// 右子樹(Rchild)遞歸調用
node.Rchild.Reverse()
}
測試
func main() {
tree := new(BinaryTreeNode)
tree.CreateBinaryTree()
fmt.Println("翻轉前:")
tree.PreOrderPrint()
fmt.Println()
tree.Reverse()
fmt.Println("翻轉後:")
tree.PreOrderPrint()
}
翻轉前:
0 1 3 4 2 5 6
翻轉後:
0 2 6 5 1 4 3
10.拷貝
// 拷貝二叉樹
func (node *BinaryTreeNode) Copy() *BinaryTreeNode {
// 容錯處理
if node == nil {
return nil
}
// 左子樹(Lchild)遞歸調用,得到左子樹
oldLChild := node.Lchild.Copy()
// 右子樹(Rchild)遞歸調用,得到右子樹
oldRChild := node.Rchild.Copy()
// 創建新結點並賦值
newBinaryTreeNode := new(BinaryTreeNode)
newBinaryTreeNode.Data = node.Data
newBinaryTreeNode.Lchild = oldLChild
newBinaryTreeNode.Rchild = oldRChild
return newBinaryTreeNode
}
測試
func main() {
tree := new(BinaryTreeNode)
tree.CreateBinaryTree()
fmt.Println("原二叉樹:")
tree.PreOrderPrint()
fmt.Println("\r\n拷貝的二叉樹:")
newTree := tree.Copy()
newTree.PreOrderPrint()
fmt.Println("\r\n修改拷貝的二叉樹,測試修改是否導致原二叉樹的變化:")
newTree.Lchild.Data = 666
fmt.Println("原二叉樹:")
tree.PreOrderPrint()
fmt.Println("\r\n拷貝並將左子樹的數值修改爲666的二叉樹:")
newTree.PreOrderPrint()
}
原二叉樹:
0 1 3 7 4 2 5 6
拷貝的二叉樹:
0 1 3 7 4 2 5 6
修改拷貝的二叉樹,測試修改是否導致原二叉樹的變化:
原二叉樹:
0 1 3 7 4 2 5 6
拷貝並將左子樹的數值修改爲666的二叉樹:
0 666 3 7 4 2 5 6
11.完整代碼
package main
import (
"fmt"
"reflect"
)
// 定義二叉樹結點結構體
type BinaryTreeNode struct {
// 數據域
Data interface{}
// 左子結點
Lchild *BinaryTreeNode
// 右子結點
Rchild *BinaryTreeNode
}
// 根據圖創建二叉樹
func (node *BinaryTreeNode) CreateBinaryTree() {
if node == nil {
return
}
node1 := &BinaryTreeNode{1, nil, nil}
node2 := &BinaryTreeNode{2, nil, nil}
node3 := &BinaryTreeNode{3, nil, nil}
node4 := &BinaryTreeNode{4, nil, nil}
node5 := &BinaryTreeNode{5, nil, nil}
node6 := &BinaryTreeNode{6, nil, nil}
node7 := &BinaryTreeNode{7, nil, nil}
node.Data = 0
node.Lchild = node1
node1.Lchild = node3
node1.Rchild = node4
node3.Lchild = node7
node.Rchild = node2
node2.Lchild = node5
node2.Rchild = node6
}
// 打印二叉樹---先序遍歷DLR:先根、再左、再右
func (node *BinaryTreeNode) PreOrderPrint() {
// 容錯處理,同時也是遞歸出口
if node == nil {
return
}
// 根(Data)
fmt.Print(node.Data, " ")
// 左子樹(Lchild)遞歸調用
node.Lchild.PreOrderPrint()
// 右子樹(Rchild)遞歸調用
node.Rchild.PreOrderPrint()
}
// 打印二叉樹---中序遍歷LDR:先左、再根、再右
func (node *BinaryTreeNode) MidOrderPrint() {
// 容錯處理,同時也是遞歸出口
if node == nil {
return
}
// 左子樹(Lchild)遞歸調用
node.Lchild.MidOrderPrint()
// 根(Data)
fmt.Print(node.Data, " ")
// 右子樹(Rchild)遞歸調用
node.Rchild.MidOrderPrint()
}
// 打印二叉樹---後序遍歷LRD:先左、再右、再根
func (node *BinaryTreeNode) PostOrderPrint() {
// 容錯處理,同時也是遞歸出口
if node == nil {
return
}
// 左子樹(Lchild)遞歸調用
node.Lchild.PostOrderPrint()
// 右子樹(Rchild)遞歸調用
node.Rchild.PostOrderPrint()
// 根(Data)
fmt.Print(node.Data, " ")
}
// 獲取二叉樹樹高/深度
func (node *BinaryTreeNode) TreeHeight() int {
// 容錯處理,同時也是遞歸出口
if node == nil {
return 0 // 不能返回-1,否則少一個深度
}
// 左子樹遞歸探求深度
lch := node.Lchild.TreeHeight()
// 右子樹遞歸探求深度
rch := node.Rchild.TreeHeight()
if lch > rch {
// 每一次遞歸深度自增
lch++
return lch
} else {
// 每一次遞歸深度自增
rch++
return rch
}
}
// 獲取二叉樹葉子節點數
func (node *BinaryTreeNode) LeafNumber() (number int) {
// 容錯處理
if node == nil {
return
}
// 判斷是否是葉子節點:左子樹爲nil,同時右子樹也爲nil
if node.Lchild == nil && node.Rchild == nil {
number++
}
// 左子樹(Lchild)遞歸調用
number += node.Lchild.LeafNumber()
// 右子樹(Rchild)遞歸調用
number += node.Rchild.LeafNumber()
return
}
// 獲取二叉樹葉子節點數--指針傳參
func (node *BinaryTreeNode) LeafNumber2(number *int) {
// 容錯處理
if node == nil {
return
}
// 判斷是否是葉子節點:左子樹爲nil,同時右子樹也爲nil
if node.Lchild == nil && node.Rchild == nil {
*number++
}
// 左子樹(Lchild)遞歸調用
node.Lchild.LeafNumber2(number)
// 右子樹(Rchild)遞歸調用
node.Rchild.LeafNumber2(number)
return
}
// 查找二叉樹數據
func (node *BinaryTreeNode) Search(data interface{}, b *bool) {
if node == nil || data == nil {
return
}
// 比較數據類型和值是否一致
if reflect.DeepEqual(node.Data, data) && reflect.TypeOf(node.Data) == reflect.TypeOf(data) {
*b = true
return
}
// 左子樹(Lchild)遞歸調用
node.Lchild.Search(data, b)
// 右子樹(Rchild)遞歸調用
node.Rchild.Search(data, b)
}
// 銷燬二叉樹
func (node *BinaryTreeNode) Destroy() {
if node == nil {
return
}
// 左子樹(Lchild)遞歸調用
node.Lchild.Destroy()
// 銷燬數據,促使GC工作
node.Data = nil
node.Lchild = nil
// 右子樹(Rchild)遞歸調用
node.Rchild.Destroy()
// 銷燬數據,促使GC工作
node.Data = nil
node.Rchild = nil
}
// 二叉樹翻轉(滿二叉樹)
func (node *BinaryTreeNode) Reverse() {
if node == nil {
return
}
// 左子樹和右子樹交換位置,go的多重賦值實現
node.Lchild, node.Rchild = node.Rchild, node.Lchild
// 左子樹(Lchild)遞歸調用
node.Lchild.Reverse()
// 右子樹(Rchild)遞歸調用
node.Rchild.Reverse()
}
// 拷貝二叉樹
func (node *BinaryTreeNode) Copy() *BinaryTreeNode {
// 容錯處理
if node == nil {
return nil
}
// 左子樹(Lchild)遞歸調用,得到左子樹
oldLChild := node.Lchild.Copy()
// 右子樹(Rchild)遞歸調用,得到右子樹
oldRChild := node.Rchild.Copy()
// 創建新結點並賦值
newBinaryTreeNode := new(BinaryTreeNode)
newBinaryTreeNode.Data = node.Data
newBinaryTreeNode.Lchild = oldLChild
newBinaryTreeNode.Rchild = oldRChild
return newBinaryTreeNode
}
func main() {
tree := new(BinaryTreeNode)
tree.CreateBinaryTree()
fmt.Println("原二叉樹:")
tree.PreOrderPrint()
fmt.Println("\r\n拷貝的二叉樹:")
newTree := tree.Copy()
newTree.PreOrderPrint()
fmt.Println("\r\n修改拷貝的二叉樹,測試修改是否導致原二叉樹的變化:")
newTree.Lchild.Data = 666
fmt.Println("原二叉樹:")
tree.PreOrderPrint()
fmt.Println("\r\n拷貝並將左子樹的數值修改爲666的二叉樹:")
newTree.PreOrderPrint()
}