Java数据结构之线段树的原理与实现

yizhihongxing

Java数据结构之线段树的原理与实现

什么是线段树

线段树是一种基于分治思想的数据结构,它可以用来解决各种区间查询问题,例如区间求和、最大值、最小值等等。在算法竞赛和数据结构课程中,线段树被广泛应用,是一种非常实用的数据结构。

线段树的基本原理

线段树是一种二叉树,它的每个节点包含一个区间,叶子节点表示区间中的单个元素,非叶子节点表示区间的合并。

线段树的建立过程分为三步:

  1. 从上到下递归地将区间划分为两个子区间。
  2. 当划分到区间长度为1时,将该节点标记为叶子节点,将该位置对应的数值存入该叶子节点。
  3. 从下到上递归地合并每个节点的信息。例如求和的话,每个节点需要记录一个区间的和。

查询的过程也分为三步:

  1. 先找到包含查询区间的最小区间。
  2. 对于覆盖完全的区间,直接返回该区间的信息,否则,递归地查询该节点的子节点。
  3. 将子节点的信息合并,得到查询区间的结果。

修改操作则是找到该位置对应的叶子节点,然后递归地重新合并所有受到该修改操作影响的节点的信息。

编程实现

我们可以使用Java来实现线段树的建立和查询操作。下面是一个示例代码:

class SegmentTree {
    int n;
    int[] nums;
    int[] tree;

    public SegmentTree(int[] nums) {
        this.n = nums.length;
        this.nums = nums;
        this.tree = new int[n * 4];
        build(0, 0, n - 1);
    }

    private void build(int node, int left, int right) {
        if (left == right) {
            tree[node] = nums[left];
        } else {
            int mid = left + (right - left) / 2;
            build(node * 2 + 1, left, mid);
            build(node * 2 + 2, mid + 1, right);
            tree[node] = tree[node * 2 + 1] + tree[node * 2 + 2];
        }
    }

    public int query(int left, int right) {
        return query(0, 0, n - 1, left, right);
    }

    private int query(int node, int nodeLeft, int nodeRight, int queryLeft, int queryRight) {
        if (nodeLeft >= queryLeft && nodeRight <= queryRight) {
            return tree[node];
        } else if (nodeRight < queryLeft || nodeLeft > queryRight) {
            return 0;
        } else {
            int mid = nodeLeft + (nodeRight - nodeLeft) / 2;
            return query(node * 2 + 1, nodeLeft, mid, queryLeft, queryRight)
                    + query(node * 2 + 2, mid + 1, nodeRight, queryLeft, queryRight);
        }
    }

    public void update(int index, int val) {
        update(0, 0, n - 1, index, val);
    }

    private void update(int node, int nodeLeft, int nodeRight, int index, int val) {
        if (nodeLeft == nodeRight) {
            tree[node] = val;
        } else {
            int mid = nodeLeft + (nodeRight - nodeLeft) / 2;
            if (index <= mid) {
                update(node * 2 + 1, nodeLeft, mid, index, val);
            } else {
                update(node * 2 + 2, mid + 1, nodeRight, index, val);
            }
            tree[node] = tree[node * 2 + 1] + tree[node * 2 + 2];
        }
    }
}

上面的代码实现了线段树的基本功能,包括建树、查询和修改。可以根据实际需求对其进行更改。

示例说明1:使用线段树查询数组的区间和

下面是一个使用线段树查询数组的区间和的示例代码:

public class Main {
    public static void main(String[] args) {
        int[] nums = {1, 3, 5, 7, 9, 11};
        SegmentTree tree = new SegmentTree(nums);
        System.out.println(tree.query(0, 2)); // 1 + 3 + 5 = 9
        tree.update(1, 2);
        System.out.println(tree.query(0, 2)); // 1 + 2 + 5 = 8
    }
}

该示例中,我们将数组 {1, 3, 5, 7, 9, 11} 转化为线段树,并查询区间 [0, 2] 的和。然后我们将该数组的第二个元素修改为2,之后再次查询区间 [0, 2] 的和。控制台将输出9和8。

示例说明2:使用线段树查询数组的区间最大值

下面的示例代码演示了如何使用线段树查询数组的区间最大值:

public class Main {
    static class Node {
        int val;
        int start, end;

        public Node(int val, int start, int end) {
            this.val = val;
            this.start = start;
            this.end = end;
        }
    }

    public static void main(String[] args) {
        int[] nums = {1, 3, 5, 2, 4, 6, 8};
        List<Node> list = new ArrayList<>(nums.length);
        for (int i = 0; i < nums.length; i++) {
            Node node = new Node(nums[i], i, i);
            list.add(node);
        }

        SegmentTree tree = new SegmentTree(list.stream().mapToInt(n -> n.val).toArray());

        IntStream.range(0, nums.length - 1).forEach(i -> {
            Node left = list.get(i);
            Node right = list.get(i + 1);
            if (left.val > right.val) {
                left.end = right.start;
            }
        });

        int ans = 0;
        for (Node node : list) {
            ans = Math.max(ans, tree.query(node.start, node.end));
        }

        System.out.println(ans);
    }
}

该示例中,我们将数组 {1, 3, 5, 2, 4, 6, 8} 转化为线段树,并查询其中的区间最大值。我们还通过修改线段树节点信息来查找每个局部最大值的起始和结束位置。控制台将输出 6,表示数组中的最大值为6。

总结

线段树是一种实用而优秀的数据结构,它可以用来解决区间问题。建树、查询和修改等操作都能快速实现,并且时间复杂度为 O(log n)。在算法竞赛和数据结构课程中,掌握线段树的原理和实现是必不可少的。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java数据结构之线段树的原理与实现 - Python技术站

(0)
上一篇 2023年5月17日
下一篇 2023年5月17日

相关文章

  • Java数据结构之常见排序算法(下)

    Java数据结构之常见排序算法(下) 前言 这是 Java 数据结构之常见排序算法的第二篇,本篇文章将继续介绍常见的排序算法。对于尚未了解基本排序算法的读者,可以先阅读 Java 数据结构之常见排序算法(上)。 快速排序 快速排序是一种使用分治思想的排序算法,其思路是将一个数组分为两个子数组,再对子数组进行排序,这个过程不断递归执行。在具体实现时,选择一个元…

    数据结构 2023年5月17日
    00
  • C语言 超详细讲解算法的时间复杂度和空间复杂度

    C语言 超详细讲解算法的时间复杂度和空间复杂度 什么是时间复杂度和空间复杂度? 在进行算法分析时,我们需要考虑的两个重要因素是时间复杂度和空间复杂度。时间复杂度是指算法所需要的时间量,而空间复杂度是指算法所需要的空间量。在编写算法时,我们常常需要考虑如何在时间和空间两者之间做出平衡,以使算法既有足够高的效率,又不占用过多的资源。 如何计算时间复杂度? 计算时…

    数据结构 2023年5月17日
    00
  • C语言数据结构之算法的时间复杂度

    关于C语言数据结构之算法的时间复杂度,需要先了解一些基本概念。 什么是时间复杂度 时间复杂度是算法的一种衡量标准,用于评估算法的执行效率。表示代码执行的时间和数据量之间的关系,通常用大O符号来表示,称为“大O记法”。 时间复杂度的分类 时间复杂度可分为以下几类: 常数阶:O(1) 对数阶:O(log n) 线性阶:O(n) 线性对数阶:O(n log n) …

    数据结构 2023年5月17日
    00
  • C语言数据结构之 折半查找实例详解

    C语言数据结构之 折半查找实例详解 什么是折半查找? 折半查找是一种在有序数组中查找某个特定元素的算法。其基本思想是将查找的值与数组的中间元素比较,如果比中间元素小,则在数组的左半部分查找;如果比中间元素大,则在数组的右半部分查找,直到找到该元素或查找范围为空。 折半查找算法的流程 确定要查找的数组arr和其元素个数n,以及要查找的元素value。 设定左边…

    数据结构 2023年5月17日
    00
  • Java数据结构之顺序表的实现

    下面是“Java数据结构之顺序表的实现”的完整攻略: 标题:Java数据结构之顺序表的实现 一、什么是顺序表 顺序表是一种线性表结构,其数据元素在物理位置上是连续的,通过下标访问,具有随机访问的优点。 二、顺序表的实现 使用Java语言实现顺序表,需要定义以下三个类: 1. SeqList类 构造顺序表的数据结构,并定义了一些基本操作,如插入、删除、修改等。…

    数据结构 2023年5月17日
    00
  • php数据结构与算法(PHP描述) 查找与二分法查找

    以下是详细讲解“php数据结构与算法(PHP描述) 查找与二分法查找”的完整攻略。 1. 数据结构与算法简介 数据结构是计算机中存储和组织数据的方式。它涉及到数据的表示、处理和存储方式等。 算法则是完成特定任务的步骤集合。算法设计可以优化计算机程序的效率和速度。 PHP是一种非常流行的服务器端脚本语言,数据结构和算法对web开发者来说非常重要。因此,我们需要…

    数据结构 2023年5月17日
    00
  • go语言数据结构之前缀树Trie

    前缀树Trie 前缀树Trie是一种树形数据结构,被用于快速查找内存中的字符串数据。它非常适合存储大量的字符串,并且能够非常快速的查找以一个指定的字符串前缀开头的全部字符串。 相关术语 在学习前缀树Trie之前,需要掌握一下相关术语: 根节点:Trie树的根节点,代表空字符串。 边:连接两个节点的线,代表一个字符。 节点:表示一个字符串,可能是某个字符串的结…

    数据结构 2023年5月17日
    00
  • Python数据结构之二叉排序树的定义、查找、插入、构造、删除

    Python数据结构之二叉排序树 一、定义 二叉排序树(Binary Search Tree,BST),也称为二叉查找树或二叉搜索树,是一种基于二叉树的数据结构,其中每个节点都包含一个键值,且满足: 左子树中所有节点的键值均小于当前节点; 右子树中所有节点的键值均大于当前节点; 这是一种自平衡的数据结构,可以快速地进行查找、插入、删除等操作。 二、查找 查找…

    数据结构 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部