返回

线段树——区间查询优化利器

后端

线段树概述

线段树是一种树形数据结构,每个节点代表一个数组中的某个区间。线段树的每个节点都有三个子节点:左子节点、右子节点和父节点。左子节点和右子节点分别代表区间的前半部分和后半部分,父节点代表整个区间。

线段树的构建过程如下:

  1. 将数组中的每个元素作为叶节点,从左到右依次插入到线段树中。
  2. 将叶节点的父节点设为叶节点的左子节点和右子节点的父节点。
  3. 重复步骤2,直到所有的节点都具有父节点。

线段树的查询过程如下:

  1. 从根节点开始,依次比较查询区间与当前节点所代表的区间。
  2. 如果查询区间完全包含在当前节点所代表的区间内,则直接返回当前节点的值。
  3. 如果查询区间与当前节点所代表的区间有重叠,则递归查询当前节点的左子节点和右子节点。
  4. 将左子节点和右子节点的查询结果合并,得到最终的查询结果。

线段树的修改过程如下:

  1. 从根节点开始,依次比较修改区间与当前节点所代表的区间。
  2. 如果修改区间完全包含在当前节点所代表的区间内,则直接修改当前节点的值。
  3. 如果修改区间与当前节点所代表的区间有重叠,则递归修改当前节点的左子节点和右子节点。
  4. 将左子节点和右子节点的修改结果合并,得到最终的修改结果。

线段树的应用

线段树可以用来解决许多与区间相关的复杂问题,例如:

  • 区间和:计算一个数组中某个区间内所有元素的和。
  • 区间最大值:计算一个数组中某个区间内所有元素的最大值。
  • 区间最小值:计算一个数组中某个区间内所有元素的最小值。
  • 区间中位数:计算一个数组中某个区间内所有元素的中位数。
  • 区间众数:计算一个数组中某个区间内出现次数最多的元素。
  • 区间乘积:计算一个数组中某个区间内所有元素的乘积。
  • 区间异或和:计算一个数组中某个区间内所有元素的异或和。

Python实现

class Node:
    def __init__(self, start, end, value):
        self.start = start
        self.end = end
        self.value = value
        self.left = None
        self.right = None

class SegmentTree:
    def __init__(self, array):
        self.root = self._build_tree(array, 0, len(array) - 1)

    def _build_tree(self, array, start, end):
        if start == end:
            return Node(start, end, array[start])

        mid = (start + end) // 2
        left_child = self._build_tree(array, start, mid)
        right_child = self._build_tree(array, mid + 1, end)

        return Node(start, end, left_child.value + right_child.value)

    def query(self, start, end):
        return self._query(self.root, start, end)

    def _query(self, node, start, end):
        if node.start == start and node.end == end:
            return node.value

        mid = (node.start + node.end) // 2

        if end <= mid:
            return self._query(node.left, start, end)
        elif start > mid:
            return self._query(node.right, start, end)
        else:
            return self._query(node.left, start, mid) + self._query(node.right, mid + 1, end)

    def update(self, index, value):
        self._update(self.root, index, value)

    def _update(self, node, index, value):
        if node.start == node.end == index:
            node.value = value
            return

        mid = (node.start + node.end) // 2

        if index <= mid:
            self._update(node.left, index, value)
        else:
            self._update(node.right, index, value)

        node.value = node.left.value + node.right.value

if __name__ == "__main__":
    array = [1, 2, 3, 4, 5]
    segment_tree = SegmentTree(array)

    print(segment_tree.query(0, 2))  # 6
    print(segment_tree.query(1, 3))  # 9
    print(segment_tree.query(2, 4))  # 12

    segment_tree.update(2, 10)

    print(segment_tree.query(0, 2))  # 11
    print(segment_tree.query(1, 3))  # 15
    print(segment_tree.query(2, 4))  # 17

结论

线段树是一种非常强大的数据结构,可以用来高效地查询和修改数组中的元素。线段树的应用非常广泛,可以用来解决许多与区间相关的复杂问题。