1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package main

/*
    二叉搜索树
    右子树所有节点均大于根节点, 左子树所有节点均小于根节点
    而且左右子树需要均为二叉搜索树
*/
type searchTreeNode struct {
    data int
    left *searchTreeNode
    right *searchTreeNode
}

func DeleteNode(root *searchTreeNode, value int)  *searchTreeNode {
    if root == nil {
        return nil
    }
    // 待删除节点在右子树
    if root.data < value {
        root.right = DeleteNode(root.right, value)
        return root
    }
    // 待删除节点在左子树
    if root.data > value {
        root.left = DeleteNode(root.left, value)
        return root
    }
    // 待删除节点为根节点
    // 找到右子树的最小值和根节点交换
    // 在删除掉交换后的那个节点
    if root.left == nil {
        return root.right
    }
    if root.right == nil {
        return root.left
    }
    minNode := root.right
    for minNode.left != nil {
        minNode = minNode.left
    }

    root.data = minNode.data
    root.right = DeleteNode(root.right, value)
    return root
}

func AddNode(root *searchTreeNode, value int) *searchTreeNode {
    if root == nil {
        return &searchTreeNode{
            data:  value,
        }
    }

    // 需要插入到右子树
    if root.data < value {
        root.right = AddNode(root.right, value)
        return root
    }
    // 需要插入到左子树
    if root.data > value {
        root.left = AddNode(root.left, value)
        return root
    }

    return root
}

平衡二叉树

每个节点左右子树的高度差不大于1.

B树 balance树

根据上图我们来看下B+树和B树有什么不同。

  1. B+树非叶子节点上是不存储数据的,仅存储键值,而B树节点中不仅存储键值,也会存储数据。之所以这么做是因为在数据库中页的大小是固定的,innodb中页的默认大小是16KB。如果不存储数据,那么就会存储更多的键值,相应的树的阶数(节点的子节点树)就会更大,树就会更矮更胖,如此一来我们查找数据进行磁盘的IO次数有会再次减少,数据查询的效率也会更快。另外,B+树的阶数是等于键值的数量的,如果我们的B+树一个节点可以存储1000个键值,那么3层B+树可以存储1000×1000×1000=10亿个数据。一般根节点是常驻内存的,所以一般我们查找10亿数据,只需要2次磁盘IO。
  2. 因为B+树索引的所有数据均存储在叶子节点,而且数据是按照顺序排列的。那么B+树使得范围查找,排序查找,分组查找以及去重查找变得异常简单。而B树因为数据分散在各个节点,要实现这一点是很不容易的。