去二进制搜索树

电脑杂谈  发布时间:2020-05-24 14:12:09  来源:网络整理

二叉树的遍历算法c实现_二叉排序树实现_树与二叉树的转换的实现

二叉搜索树(BST)是一个非常重要的数据结构,它涵盖了浅层和深层,涵盖了数据结构和算法中的许多问题. 为了练习Go编程,本文使用Go来实现BST. 这是一个初步的实现,它不考虑树的平衡并且不删除树节点.

首先定义BST的结构,这就是Go的优势所在. 由于Go为每种基本数据类型定义了初始零值,例如int类型为0,指针* TreeNode为nil二叉排序树实现,所以我们不需要编写复杂的构造函数以生成新节点.

type TreeNode struct {
    Left, Right *TreeNode
    Key         int
}
type Tree struct {
    Root *TreeNode
    Num  int
}
func NewTree() (t *Tree) {
    t = &Tree{}
    return
}

BST由于其数据组织特性,因此可以自然地使用递归来实现许多方法. 递归实现过于直观,因此在此不再赘述. 可以使用迭代来实现所有递归函数,并且递归需要占用函数调用堆栈. 一旦递归层过多,就很容易发生堆栈溢出. 因此,对于具有大数据量的输入,迭代实现是可靠的.

二叉排序树实现_二叉树的遍历算法c实现_树与二叉树的转换的实现

首先,插入节点以实现BST的节点顺序二叉排序树实现,即Key(左)

/*iterative insert new key into tree*/
func (t *Tree) Insert(val int) {
    node := &TreeNode{Key: val}
    if t.Root == nil {
        t.Root = node
        t.Num++
        return
    } //create root
    //find the parent node to host new one
    var cur, parent *TreeNode = t.Root, nil
    for cur != nil {
        parent = cur
        if val < cur.Key {
            cur = cur.Left
        } else {
            cur = cur.Right
        }
    }
    //link the new node to the tree
    if parent == nil {
        panic("corrupt tree") //parent = node
    } else if val < parent.Key {
        parent.Left = node
    } else if val > parent.Key {
        parent.Right = node
    }
    t.Num++
}

比较插入节点的递归实现

/*recursively insert new key into tree*/
func (t *Tree) InsertRecur(val int) {
    t.Root = insert(t.Root, val)
}
func insert(root *TreeNode, val int) *TreeNode {
    if root == nil {
        return &TreeNode{Key: val}
    }
    if val < root.Key {
        root.Left = insert(root.Left, val)
    } else if val > root.Key {
        root.Right = insert(root.Right, val)
    }
    return root
}

二叉排序树实现_树与二叉树的转换的实现_二叉树的遍历算法c实现

然后迭代地实现BST,中阶遍历,前阶遍历,后阶遍历和逐层遍历的几种遍历方法.

中阶遍历的输出是键值数组的序列. 中间顺序遍历是使用堆栈来实现的,该堆栈从根节点开始,从上到下,依次将左子节点推入堆栈,直到左子节点为空. 然后弹出栈顶,访问的第一个节点是最左边的子节点. 访问根节点后,以相同的方式访问正确的子树.

/*iterative in-order traversal*/
func (t *Tree) Inorder() (out []int) {
    if t.Root == nil {
        return
    }
    var stack []*TreeNode
    curr := t.Root
    for true {
        for curr != nil {
            stack = append(stack, curr)
            curr = curr.Left
        }
        if len(stack) > 0 {
            curr = stack[len(stack)-1]
            stack = stack[:len(stack)-1]
            out = append(out, curr.Key)
        }
        curr = curr.Right
        if curr == nil && len(stack) == 0 {
            break
        }
    }
    return
}

预遍历首先访问根节点,然后访问左右子树,因此可以使用队列来实现.

二叉排序树实现_树与二叉树的转换的实现_二叉树的遍历算法c实现

/*iterative pre-order traversal*/
func (t *Tree) Preorder() (out []int) {
    if t.Root == nil {
        return
    }
    queue := []*TreeNode{t.Root}
    for len(queue) > 0 {
        curr := queue[0]
        queue = queue[1:]
        out = append(out, curr.Key)
        if curr.Left != nil {
            queue = append(queue, curr.Left)
        }
        if curr.Right != nil {
            queue = append(queue, curr.Right)
        }
    }
    return
}

后顺序遍历的递归实现比前顺序和中顺序更复杂,并且可以使用两个堆栈来实现. 在堆栈1中,按照root-> left-> right的顺序将节点压入堆栈,同时将根压入堆栈2,最后将堆栈2压出,结果是后遍历.

/*iterative post-order traversal with two stacks*/
func (t *Tree) Postorder() (out []int) {
    if t.Root == nil {
        return
    }
    var stack1, stack2 []*TreeNode
    stack1 = append(stack1, t.Root)
    for len(stack1) > 0 {
        curr := stack1[len(stack1)-1]
        stack1 = stack1[:len(stack1)-1]
        stack2 = append(stack2, curr)
        if curr.Left != nil {
            stack1 = append(stack1, curr.Left)
        }
        if curr.Right != nil {
            stack1 = append(stack1, curr.Right)
        }
    }
    for len(stack2) > 0 {
        curr := stack2[len(stack2)-1]
        stack2 = stack2[:len(stack2)-1]
        out = append(out, curr.Key)
    }
    return
}

序列遍历使用BFS,即广度优先搜索. 使用队列,每次访问图层时,您都将加入下一层的节点.

二叉排序树实现_二叉树的遍历算法c实现_树与二叉树的转换的实现

/*iterative level-order traversal with BFS*/
func (t *Tree) LevelOrder() (out [][]int) {
    if t.Root == nil {
        return
    }
    queue := []*TreeNode{t.Root}
    level := 0
    for len(queue) > 0 {
        size := len(queue)
        if size > 0 {
            out = append(out, []int{})
        } //allocate array to store next level
        for ; size > 0; size-- {
            curr := queue[0]
            queue = queue[1:]
            out[level] = append(out[level], curr.Key) //travers node of current level
            //put next level nodes into queue
            if curr.Left != nil {
                queue = append(queue, curr.Left)
            }
            if curr.Right != nil {
                queue = append(queue, curr.Right)
            }
        }
        level++ //increase level
    }
    return
}

本文没有实现平衡的搜索树,但是BST的平衡对搜索效率有很大的影响. 这里我们实现了一种检测树平衡的方法,并使用重建的BST进行平衡.

/*get the height of tree in recursively manner*/
func getHeightRecur(root *TreeNode) int {
    if root == nil {
        return 0
    }
    if root.Left == nil && root.Right == nil {
        return 1
    }
    return Max(getHeightRecur(root.Left), getHeightRecur(root.Right)) + 1
}
/*check if tree is balanced in recursively manner*/
func (t *Tree) IsBalancedRecur() bool {
    if t.Root == nil {
        return true
    }
    return Abs(getHeightRecur(t.Root.Left)-getHeightRecur(t.Root.Right)) < 1
}
/*create and link tree node for a balanced tree*/
func buildBalancedTree(keys []int, start, end int) (root *TreeNode) {
    if start < end {
        return
    }
    mid := start + (end-start)/2
    root = &TreeNode{Key: keys[mid]}
    root.Left = buildBalancedTree(keys, start, mid-1)
    root.Right = buildBalancedTree(keys, mid+1, end)
    return
}
/*rebuild the tree to make it balanced*/
func (t *Tree) MakeBalancedRecur() {
    keys := t.Inorder()
    t.Root = buildBalancedTree(keys, 0, len(keys)-1)
}

最后添加测试用例进行验证

func TreeTest(n int) {
    nums := []int{3, 4, 6, 2, 1, 5}
    tree := NewTree()
    for _, n := range nums {
        tree.Insert(n)
    }
    //visit := tree.Inorder()
    fmt.Println("#", n, "TreeTest", tree.Num)
    fmt.Println("pre-order", tree.Preorder())
    fmt.Println("in-order", tree.Inorder())
    fmt.Println("post-order", tree.Postorder())
    fmt.Println("level-order", tree.LevelOrder())
}

代码列表:


本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-220573-1.html

    相关阅读
      发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

      • 黄童
        黄童

        在水下布监测系统是真的

      • 鲁盼盼
        鲁盼盼

        每年只创新广告就行了

      热点图片
      拼命载入中...