二叉树的增删改查,深度、距离,前序、中序、后序遍历,广度优先遍历(GO语言)

本文详细介绍了二叉树的各种操作实现,包括插入、删除、搜索等基本操作,以及前序、中序、后序和广度优先遍历。此外还探讨了如何查找最小公共祖先、节点层级和节点间距离等问题。

二叉树

package main

import (
    "github.com/cheekybits/genny/generic"
    "sync"
    "fmt"
)

type Item generic.Type

//节点的结构
type Node struct {
    key   int
    value Item
    left  *Node
    right *Node
}

//树的结构
type ItemBinarySearchTree struct {
    root *Node
    lock sync.RWMutex
}

//格式化输出
func (tree *ItemBinarySearchTree) String() {
    tree.lock.Lock()
    defer tree.lock.Unlock()
    fmt.Println("格式化输出:")
    fmt.Println("--------------------------------")
    stringify(tree.root, 0)
    fmt.Println("--------------------------------")
}

func stringify(node *Node, level int) {
    if node != nil {
        format := ""
        for i := 0; i < level; i++ {
            format += "       "
        }

        format += "---[ "
        level++

        stringify(node.right, level)
        fmt.Printf(format+"%d\n", node.key)
        stringify(node.left, level)
    }
}

//插入节点
func (tree *ItemBinarySearchTree) Insert(key int, value Item) {
    tree.lock.Lock()
    defer tree.lock.Unlock()
    node := &Node{key, value, nil, nil}
    if tree.root == nil {
        tree.root = node
    } else {
        insertNode(tree.root, node)
    }
}

func insertNode(node, newNode *Node) {
    if newNode.key < node.key {
        if node.left == nil {
            node.left = newNode
        } else {
            insertNode(node.left, newNode)
        }
    } else {
        if node.right == nil {
            node.right = newNode
        } else {
            insertNode(node.right, newNode)
        }
    }
}

//最小节点
func (tree *ItemBinarySearchTree) Min() *Item {
    tree.lock.RLock()
    defer tree.lock.RUnlock()
    node := tree.root

    if node == nil {
        return nil
    }

    for {
        if node.left == nil {
            return &node.value
        }

        node = node.left
    }
}

//最大节点
func (tree *ItemBinarySearchTree) Max() Item {
    tree.lock.RLock()
    defer tree.lock.RUnlock()

    node := tree.root

    if node == nil {
        return nil
    }

    for {
        if node.right == nil {
            return node.value
        }
        node = node.right
    }
}

//搜索某个值
func (tree *ItemBinarySearchTree) Search(key int) bool {
    tree.lock.RLock()
    defer tree.lock.RUnlock()
    fmt.Print("是否存在节点:", key, "\t")
    return search(tree.root, key)
}

func search(node *Node, key int) bool {
    if node == nil {
        return false
    }

    if key < node.key {
        return search(node.left, key)
    }

    if key > node.key {
        return search(node.right, key)
    }

    return true
}

//删除节点
func (tree *ItemBinarySearchTree) Remove(key int) {
    tree.lock.Lock()
    defer tree.lock.Unlock()
    fmt.Println("删除节点:", key)
    remove(tree.root, key)
}

func remove(node *Node, key int) *Node {
    if node == nil {
        return nil
    }

    if key < node.key {
        node.left = remove(node.left, key)
        return node
    }

    if key > node.key {
        node.right = remove(node.right, key)
        return node
    }

    if node.left == nil && node.right == nil {
        node = nil
        return node
    }

    if node.left == nil {
        node = node.right
        return node
    }

    if node.right == nil {
        node = node.left
        return node
    }

    mostLeftNode := node.right
    for {
        if mostLeftNode != nil && mostLeftNode.left != nil {
            mostLeftNode = mostLeftNode.left
        } else {
            break
        }
    }

    node.key, node.value = mostLeftNode.key, mostLeftNode.value
    node.right = remove(node.right, node.key)
    return node
}

//前序遍历
func (tree *ItemBinarySearchTree) PreOrderTraverse(node *Node) {
    if node == nil {
        return
    }
    fmt.Print(node.value, "\t")
    tree.PreOrderTraverse(node.left)
    tree.PreOrderTraverse(node.right)
}

//后序遍历
func (tree *ItemBinarySearchTree) PostOrderTraverse() {
    tree.lock.Lock()
    defer tree.lock.Unlock()
    fmt.Println("后序遍历:")
    node := tree.root
    postOrder(node)
    fmt.Println()
}

func postOrder(node *Node) {
    if node == nil {
        return
    }
    postOrder(node.left)
    postOrder(node.right)
    fmt.Print(node.value, "\t")
}

//中序遍历
func (tree *ItemBinarySearchTree) InOrderTraverse() {
    fmt.Println("中序遍历:")
    node := tree.root
    InOrder(node)
    fmt.Println()
}

func InOrder(node *Node) {
    if node != nil {
        InOrder(node.left)
        fmt.Print(node.key, "\t")
        InOrder(node.right)
    }
}

//广度优先
func breadthFirst(node *Node) []Item {
    fmt.Println("广度优先遍历:")
    var result []Item
    var nodes = []Node{*node}

    for len(nodes) > 0 {
        node := nodes[0]
        nodes = nodes[1:]
        result = append(result, node.value)
        if node.left != nil {
            nodes = append(nodes, *node.left)
        }
        if node.right != nil {
            nodes = append(nodes, *node.right)
        }
    }

    return result
}

//二叉树的深度
func GetDepth(node *Node) int {
    depth := 0
    if node != nil {
        depth = max(GetDepth(node.left), GetDepth(node.right)) + 1
    }
    return depth
}

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

func GetDepth2(node *Node) int {
    if node == nil {
        return 0
    }
    return max(GetDepth2(node.left), GetDepth2(node.right)) + 1
}

//找出两个节点的最小共同父节点
func (tree *ItemBinarySearchTree) FindLCA(node *Node, key1 int, key2 int) {
    fmt.Print(key1, "和", key2, "的最小共同父节点为:")
    lca := findLCA(node, key1, key2)
    fmt.Println(lca.key)
}

func findLCA(node *Node, key1 int, key2 int) *Node {
    if node == nil {
        return nil
    }
    if node.key == key1 || node.key == key2 {
        return node
    }
    var leftNode = new(Node)
    leftNode = findLCA(node.left, key1, key2)
    var rightNode = new(Node)
    rightNode = findLCA(node.right, key1, key2)
    if leftNode != nil && rightNode != nil {
        return node
    }
    if leftNode != nil {
        return leftNode
    }
    return rightNode
}

//二叉树的深度
func (tree *ItemBinarySearchTree) FindLevel(node *Node, key int) {
    level := 1
    lev := findLevel(node, key, level)
    fmt.Println(key, "在第", lev, "层。")
}

func findLevel(node *Node, key int, level int) int {
    if node == nil {
        return -1
    }
    if node.key == key {
        return level
    }
    var lev int
    lev = findLevel(node.left, key, level+1)
    if lev == -1 {
        return findLevel(node.right, key, level+1)
    } else {
        return lev
    }
}

//任意两个节点的距离
func GetDistance(node *Node, key1 int, key2 int) {
    fmt.Print(key1, "和", key2, "的距离为:")
    dis := getDistance(node, key1, key2)
    fmt.Println(dis)
}

func getDistance(node *Node, key1 int, key2 int) int {
    lca := findLCA(node, key1, key2)
    disLCA := findLevel(node, lca.key, 1)
    disKey1 := findLevel(node, key1, 1)
    disKey2 := findLevel(node, key2, 1)
    dis := disKey1 + disKey2 - 2*disLCA
    return dis
}

func main() {
    var tree ItemBinarySearchTree
    tree.Insert(8, "8")
    tree.Insert(4, "4")
    tree.Insert(13, "13")
    tree.Insert(2, "2")
    tree.Insert(6, "6")
    tree.Insert(1, "1")
    tree.Insert(10, "10")
    tree.Insert(12, "12")
    tree.Insert(3, "3")
    tree.Insert(9, "9")
    tree.Insert(5, "5")
    tree.Insert(7, "7")
    tree.Insert(11, "11")

    tree.String()

    fmt.Printf("二叉树key最小的节点的value值:%v\n", *tree.Min())
    //fmt.Printf("二叉树key最大的节点的value值:%v\n", tree.Max())
    fmt.Println("最大的节点是:", tree.Max())

    fmt.Println(tree.Search(16))

    tree.Remove(8)
    tree.String()

    fmt.Println("前序遍历:")
    tree.PreOrderTraverse(tree.root)
    fmt.Println()

    tree.InOrderTraverse()

    tree.PostOrderTraverse()

    breadthTree := breadthFirst(tree.root)
    fmt.Println(breadthTree)

    fmt.Println("广度优先遍历:")
    for _, value := range breadthTree {
        fmt.Print(value, "\t")
        //fmt.Println(value)
    }
    fmt.Println()

    fmt.Print("二叉树的深度:")
    fmt.Println(GetDepth(tree.root))

    fmt.Print("二叉树的深度为:")
    fmt.Println(GetDepth2(tree.root))

    tree.FindLCA(tree.root, 3, 11)

    tree.FindLevel(tree.root, 11)

    GetDistance(tree.root, 4, 10)

}

运行结果

格式化输出:
--------------------------------
       ---[ 13
                     ---[ 12
                            ---[ 11
              ---[ 10
                     ---[ 9
---[ 8
                     ---[ 7
              ---[ 6
                     ---[ 5
       ---[ 4
                     ---[ 3
              ---[ 2
                     ---[ 1
--------------------------------
二叉树key最小的节点的value值:1
最大的节点是: 13
是否存在节点:16   false
删除节点: 8
格式化输出:
--------------------------------
       ---[ 13
                     ---[ 12
                            ---[ 11
              ---[ 10
---[ 9
                     ---[ 7
              ---[ 6
                     ---[ 5
       ---[ 4
                     ---[ 3
              ---[ 2
                     ---[ 1
--------------------------------
前序遍历:
9   4   2   1   3   6   5   7   13  10  12  11  
中序遍历:
1   2   3   4   5   6   7   9   10  11  12  13  
后序遍历:
1   3   2   5   7   6   4   11  12  10  13  9   
广度优先遍历:
[9 4 13 2 6 10 1 3 5 7 12 11]
广度优先遍历:
9   4   13  2   6   10  1   3   5   7   12  11  
二叉树的深度:5
二叉树的深度为:5
3和11的最小共同父节点为:9
11 在第 5 层。
4和10的距离为:3
<think>好的,我现在需要帮助用户理解二叉树前序、中后序遍历的概念、实现以及它们的区别。首先,我需要回顾一下这三种遍历的基本定义,然后考虑它们的递归和非递归实现方法,最后比较它们之间的区别和应用场景。 根据用户提供的引用内容,前序遍历的顺是根节点、左子树、右子树(DLR),中遍历是左子树、根节点、右子树(LDR),后序遍历是左子树、右子树、根节点(LRD)。引用[1]中提到,前序列的第一个元素是整个树的根节点,通过在中列中找到根节点的位置来划分左右子树,这在构建二叉树时非常有用。引用[2]讨论了递归和非递归实现,特别是非递归方法中如何处理左路节点和右子树,以及访问根节点的时机不同。引用[3]则解释了遍历的命名规则和基本结构。 接下来,我需要将这些信息整理成一个清晰的回答结构。首先解释每种遍历的概念和访问顺,然后分别说明递归和非递归的实现方式,可能还需要给出代码示例。最后比较它们的区别,比如访问根节点的顺不同,应用场景的不同(比如前序用于复制树,中用于二叉搜索树的有输出等)。 需要注意用户提到的系统级指令,特别是数学表达式要用$...$,但这里可能更多的是代码块的使用。需要确保代码示例正确,比如用Python或C++的语法。用户提供的引用中有C++的例子,但用户可能需要通用的解释,或者跨语言的示例。 另外,用户要求生成相关问题,我需要考虑与遍历相关的常见问题,比如如何根据遍历结果重建二叉树,非递归实现的复杂度,遍历的应用等。 在组织内容时,要分点清晰,先讲概念,再讲实现,最后比较区别。同时,引用文献需要自然地插入到相关内容后面,比如在提到前序遍历根节点时引用[1],在讨论非递归实现时引用[2]等。 现在需要检查是否有遗漏的部分,比如层序遍历是否要提及?但用户的问题主要围绕前序、中后序,所以可能不需要。但引用[3]提到了层序遍历,可以作为扩展问题。 最后,确保语言简洁,用中文回答,避免使用Markdown格式,但代码块需要用指定的格式。同时,生成的相关问题要有针对性,帮助用户深入理解。</think>### 二叉树前序、中后序遍历详解 #### 一、概念与遍历 1. **前序遍历(DLR)** 访问顺:根节点 → 左子树 → 右子树 **示例**:若二叉树为 $A(B(D, E), C(F, \emptyset))$(其中 $\emptyset$ 表示空节点),前序遍历结果为 $A \ B \ D \ E \ C \ F$[^1]。 2. **中遍历(LDR)** 访问顺:左子树 → 根节点 → 右子树 **示例**:上述二叉树的中遍历结果为 $D \ B \ E \ A \ F \ C$[^3]。 3. **后序遍历(LRD)** 访问顺:左子树 → 右子树 → 根节点 **示例**:后序遍历结果为 $D \ E \ B \ F \ C \ A$。 --- #### 二、实现方法 ##### 1. 递归实现(以C++为例) ```cpp // 前序遍历 void preOrder(TreeNode* root) { if (root == nullptr) return; cout << root->val << " "; // 访问根 preOrder(root->left); // 左子树 preOrder(root->right); // 右子树 } // 中遍历 void inOrder(TreeNode* root) { if (root == nullptr) return; inOrder(root->left); // 左子树 cout << root->val << " "; // 访问根 inOrder(root->right); // 右子树 } // 后序遍历 void postOrder(TreeNode* root) { if (root == nullptr) return; postOrder(root->left); // 左子树 postOrder(root->right); // 右子树 cout << root->val << " "; // 访问根 } ``` ##### 2. 非递归实现(核心思路) - **前序遍历**:使用栈保存右子树,优先访问根节点后再处理左子树[^2]。 - **中遍历**:先将左路节点全部入栈,出栈时访问根节点,再处理右子树。 - **后序遍历**:需记录上一个访问的节点,确保右子树已处理完毕再访问根节点。 --- #### 三、关键区别 | 遍历方式 | 根节点访问时机 | 典型应用场景 | |----------|----------------|--------------| | 前序遍历 | 最先访问根节点 | 复制二叉树结构、前缀表达式 | | 中遍历 | 中间访问根节点 | 二叉搜索树有输出、中缀表达式 | | 后序遍历 | 最后访问根节点 | 释放内存资源、后缀表达式 | --- #### 四、相关问题 1. 如何通过前序和中遍历列重建二叉树? 2. 非递归遍历的时间复杂度是多少?如何优化? 3. 为什么中遍历对二叉搜索树特别重要? 4. 层序遍历与前三种遍历有何本质区别? : 前序列的第一个元素是根节点,用于划分左右子树结构。 [^2]: 非递归实现通过栈模拟递归过程,访问根的时机决定遍历类型。 : 三种遍历本质是深度优先搜索,而层序遍历属于广度优先搜索。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值