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

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日

相关文章

  • C语言中单链表的基本操作指南(增删改查)

    C语言中单链表的基本操作指南如下: 单链表 单链表是一种线性结构,具有链式存储的特点,即用指针相连的方式存储数据。单链表的每个节点包含一个数据域和一个指向下一个节点的指针域。单链表与数组相比,其插入和删除操作效率较高,但是查找效率较低。 在C语言中,可以使用结构体和指针实现单链表。如下所示,Node结构体表示单链表中的一个节点,包含一个数据成员和一个指向下一…

    数据结构 2023年5月17日
    00
  • 一行python实现树形结构的方法

    想要一行Python实现树形结构,我们需要使用Python的字典数据类型来完成任务。下面是详细的操作步骤: 创建树形结构字典 我们可以用嵌套字典来表示树形结构,我们需要选择其中一个节点作为根节点,并以键值对的形式保存其子节点。最终,我们将根节点作为整个字典的返回值。下面是实现代码: tree = lambda: defaultdict(tree) 插入节点 …

    数据结构 2023年5月17日
    00
  • C++数据结构之文件压缩(哈夫曼树)实例详解

    我来为您详细讲解一下“C++数据结构之文件压缩(哈夫曼树)实例详解”这篇文章的完整攻略: 文章基本信息 标题:C++数据结构之文件压缩(哈夫曼树)实例详解 作者:Coder_XWG 发布时间:2019年12月24日 文章概述 该篇文章主要讲解了哈夫曼树在文件压缩方面的应用。通过实例讲解了如何使用哈夫曼编码将文件进行压缩,以及如何解压缩被压缩的文件,并对文章中…

    数据结构 2023年5月17日
    00
  • 简单讲解哈希表

    哈希表(Hash Table),也被称为散列表,是一种高效的数据结构,它可以在O(1)的时间复杂度下完成插入、删除、查找等基本操作。哈希表是通过将关键字映射到一个固定大小的表中来实现的,这个映射函数被称为哈希函数。 什么是哈希函数 哈希函数是将任意长度的输入值(也称为“键”或“关键字”)映射为固定大小的输出值(也称为“哈希值”或“散列”)。哈希函数必须将不同…

    数据结构 2023年5月17日
    00
  • JavaScript数据结构Number

    JavaScript数据结构Number 简介 JavaScript中的Number是一种表示数字的数据类型,包括整数和浮点数。Number类型的值是不可变的。 数字类型(Number)的创建 数字类型可以通过直接赋值的方式创建,如: let num = 10; // 整数 let floatNum = 3.14; // 浮点数 另外,JavaScript还…

    数据结构 2023年5月17日
    00
  • 详解C语言内核中的链表与结构体

    详解C语言内核中的链表与结构体 1. 链表的概念 链表是一种线性数据结构,由多个节点组成,每个节点包含了两部分内容:数据和指针。 链表有多种类型,但其中最常见的是单向链表和双向链表。在单向链表中,每个节点只包含一个指针,它指向下一个节点;在双向链表中,每个节点包含两个指针,一个指向上一个节点,一个指向下一个节点。 链表的特点是可以动态地添加或删除节点,是一种…

    数据结构 2023年5月17日
    00
  • redis中hash数据结构及说明

    Redis中Hash数据结构及说明 简介 Redis中的Hash是一个string类型的field和value的映射表,可以将多个键值对存储在一个数据结构中,适合于存储对象。 通过HASH数据结构,我们可以方便的对单个field进行增删改查操作,增加了程序编写的方便性。 命令 以下是Hash数据结构的基础命令: HSET 将哈希表 key 中的域 field…

    数据结构 2023年5月17日
    00
  • java 数据结构单链表的实现

    Java中实现单链表数据结构通常需要以下几个步骤: 1. 定义节点类 首先需要定义一个节点类,用于表示链表中的一个节点。每个节点包含两个属性:data表示节点的数据,next表示节点的下一个节点。这两个属性都需要定义为public,以便后续操作的访问。 public class Node { public int data; public Node next…

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