使用Golang实现二叉索引树(Fenwick树)


二叉索引树(也称为Fenwick树)是一种高效处理数组上区间查询和点更新的数据结构。在本文中,我们将探讨两种不同的方法来在Go语言中实现二叉索引树,这里的实现指的是我们执行二叉索引树的主要操作:创建BIT(初始化)、更新和前缀和查询。

解释

Fenwick树是一种二叉树结构,它可以高效地维护数组的累积信息,特别是前缀和,并允许对范围进行更快的更新和查询。它应用于各种算法和问题,例如查找累积和和频率计数。

Original Array:     1 2 3 4 5 6 7 8

Fenwick Tree:       1 3  3  10  5  11  7  36
                      |  |      |     |   |
                      1  2      4     8   16

Fenwick树中的值通过以下方式获得:

  • 第一个索引包含原始数组中单个元素1的累加和。

  • 第二个索引包含索引1和2处元素的累加和,即1+2 =3。

  • 第三个索引包含索引3处元素的累加和,即3。

  • 第四个索引包含原始数组中索引1、2、3和4处元素的累加和,即1+2+3+4 =10。

  • 现在,第五个索引是原始数组中单个元素5的累加和,即5。

  • 第六个索引是索引5和6处元素的累加和,即11。

  • 索引7包含索引7处单个元素的累加和,即7。

  • 索引8包含原始数组中所有元素的累加和,即1+2+3+4+5+6+7+8 = 36。

语法

func NewTrie() *Trie func NewBinaryIndexedTree(size int) *BinaryIndexedTree

此语法定义了一个名为NewBinaryIndexedTree的函数,它是BinaryIndexedTree(Fenwick树)数据结构的构造函数,用于创建和初始化具有指定大小的新BinaryIndexedTree实例。

func (bit *BinaryIndexedTree) updateUtil(index, delta int)

此语法定义了一个名为updateUtil的函数,该函数更新Binary Indexed Tree(Fenwick树)数据结构实现中特定索引处的累积和,表示为数组。

算法

  • 首先用零初始化Fenwick树,数组大小增加一。

  • 要进行更新,请遍历Fenwick树,将值添加到特定位置及其对应的祖先。

  • 对于前缀和,请遍历Fenwick树,从特定位置及其祖先减去值。

  • 对于单个元素查询,计算直到所需索引的前缀和。

  • 对于范围查询,计算给定范围的前缀和。

示例1

在这个例子中,我们使用包含树的大小和数组表示的BinaryIndexedTree结构体在Go语言中实现了一个二叉索引树。NewBinaryIndexedTree函数初始化树,同时适应基于1的索引。update方法沿着树的路径递增树节点,而tquery方法高效地计算前缀和。

package main
import "fmt"
type BinaryIndexedTree struct {
    n   int  
    bit []int 
}
func NewBinaryIndexedTree(size int) *BinaryIndexedTree {
    return &BinaryIndexedTree{
    	n:   size + 1, 
    	bit: make([]int, size+1),
	}
}
func (bit *BinaryIndexedTree) update(index, delta int) {
	for i := index; i < bit.n; i += i & -i {
     	bit.bit[i] += delta
	}
}
func (bit *BinaryIndexedTree) query(index int) int {
    sum := 0
	for i := index; i > 0; i -= i & -i {
    	sum += bit.bit[i]
    }
    return sum
}
func main() {
	arr := []int{1, 2, 3, 4, 5}
    size := len(arr)
    bit := NewBinaryIndexedTree(size)
	for i, val := range arr {
    	bit.update(i+1, val)
    }
    fmt.Println("Original Array:", arr)
	fmt.Println("Prefix sum from index 1 to 4 (Method 1):", bit.query(4))
	bit.update(3, 6)
	fmt.Println("Updated Array:", bit.bit[1:])
	fmt.Println("Prefix sum from index 1 to 4 (Method 1):", bit.query(4))
}

输出

Original Array: [1 2 3 4 5]
Prefix sum from index 1 to 4 (Method 1): 10
Updated Array: [1 3 9 16 5]
Prefix sum from index 1 to 4 (Method 1): 16

示例2

在这个例子中,我们将使用包含树的大小和数组表示的BinaryIndexedTree结构体在Go语言中实现一个二叉索引树。NewBinaryIndexedTree函数初始化树,同时考虑基于1的索引。使用辅助递归函数进行树更新和前缀和计算,updateUtil函数修改树路径上的节点,而queryUtil函数计算前缀和。

package main
import "fmt"
type BinaryIndexedTree struct {
	n   int   
	bit []int 
}
func NewBinaryIndexedTree(size int) *BinaryIndexedTree {
    return &BinaryIndexedTree{
     	n:   size + 1, 
    	bit: make([]int, size+1),
    }
}
func (bit *BinaryIndexedTree) update(index, delta int) {
    bit.updateUtil(index, delta)
}
func (bit *BinaryIndexedTree) updateUtil(index, delta int) {
	if index <= 0 || index >= bit.n {
    	return
    }
    bit.bit[index] += delta
    bit.updateUtil(index+(index&-index), delta)
}
func (bit *BinaryIndexedTree) query(index int) int {
    return bit.queryUtil(index)
}
func (bit *BinaryIndexedTree) queryUtil(index int) int {
	if index <= 0 {
    	return 0
	}
	return bit.bit[index] + bit.queryUtil(index-(index&-index))
}
func main() {
	arr := []int{1, 2, 3, 4, 5}
	size := len(arr)
	bit := NewBinaryIndexedTree(size)
    for i, val := range arr {
    	bit.update(i+1, val)
    }
	fmt.Println("Original Array:", arr)
	fmt.Println("Prefix sum from index 1 to 4 (Method 2):", bit.query(4))
	bit.update(3, 6)
	fmt.Println("Updated Array:", bit.bit[1:])
	fmt.Println("Prefix sum from index 1 to 4 (Method 2):", bit.query(4))
}

输出

Original Array: [1 2 3 4 5]
Prefix sum from index 1 to 4 (Method 2): 10
Updated Array: [1 3 9 16 5]
Prefix sum from index 1 to 4 (Method 2): 16

现实生活中的应用

  • 交通管理:在交通管理系统中使用Fenwick树可以对与特定区域内车辆移动相关的数据进行结构化和检索,从而有助于优化交通监控和分析操作。

  • 传感器数据分析:在物联网(IoT)应用中使用Fenwick树可以更有效地存储和分析传感器数据。这包括计算关键指标,例如指定时间段内的平均温度和湿度测量值。

结论

Fenwick树是一种二叉树结构,它可以高效地维护数组的累积信息。在本文中,我们研究了在Go语言中实现二叉索引树的两个不同示例,为数组上的累积频率查询提供了高效的操作。第一个示例使用数组来简化实现和提高内存效率,使其成为实际应用的首选。另一方面,方法2提供了对二叉索引树树状结构的递归洞察,证明其对教育目的很有价值。

更新于:2023年10月18日

136 次浏览

开启你的职业生涯

完成课程获得认证

开始学习
广告