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日

相关文章

  • Java数据结构之链表实现(单向、双向链表及链表反转)

    Java数据结构之链表实现 链表基础概念 链表是一种数据结构,它由一系列节点(Node)组成,每个节点包含两个部分,一个是数据域(data),一个是指针域(next)。数据域存储数据信息,指针域指向下一个节点。 链表的种类很多,比如单向链表、双向链表、循环链表等等。 单向链表:链表的每个节点只有一个指针域,指向下一个节点。 双向链表:链表的每个节点有两个指针…

    数据结构 2023年5月17日
    00
  • 详解python数据结构之队列Queue

    详解Python数据结构之队列 (Queue) 在计算机科学中,队列(Queue)是一种数据结构,可以用于按顺序存储和访问元素。该数据结构遵循先进先出(FIFO)原则,人们可以从队列的前面插入元素,从队列的后面删除元素。Python内置了队列模块(queue),这个模块实现了多线程安全队列、同步机制及相关数据结构。Queue模块提供了三种队列类型: FIFO…

    数据结构 2023年5月17日
    00
  • C语言数据结构 栈的基础操作

    C语言数据结构 栈的基础操作 1. 栈的基本概念 栈(Stack)是一种基于LIFO(后进先出)原理的数据结构,类似于一组盘子,只能在盘子的顶部进行操作。每次从顶部添加或移除盘子。 栈具有两个基本操作:入栈(push)和出栈(pop)。当添加一个元素时,我们称其为“push”,当移除一个元素时,我们称其为“pop”。 2. 栈的实现 栈可以使用数组或链表来实…

    数据结构 2023年5月17日
    00
  • C语言数据结构之模式匹配字符串定位问题

    C语言数据结构之模式匹配字符串定位问题 什么是模式匹配字符串定位? 模式匹配字符串定位即在一个文本串中匹配一个模式串,并且返回模式串在文本串中第一次出现的位置。 例如,对于文本串“this is a test string”,我们想要匹配模式串“test”,我们期望得到的结果是第一次出现的位置为10。 KMP算法 算法思路 KMP算法是一种高效的字符串匹配算…

    数据结构 2023年5月16日
    00
  • PAT甲级真题1020.树的遍历

    翻译和代码思路:Acwing 一个二叉树,树中每个节点的权值互不相同。 现在给出它的后序遍历和中序遍历,请你输出它的层序遍历。 输入格式 第一行包含整数 N,表示二叉树的节点数。 第二行包含 N个整数,表示二叉树的后序遍历。 第三行包含 N 个整数,表示二叉树的中序遍历。 输出格式 输出一行 N个整数,表示二叉树的层序遍历。 数据范围 1<=N<…

    算法与数据结构 2023年4月17日
    00
  • C语言数据结构与算法之时间空间复杂度入门

    C语言数据结构与算法之时间空间复杂度入门攻略 1. 什么是时间复杂度和空间复杂度? 在进行算法设计时,我们不仅需要考虑到算法的正确性,还要考虑到算法的执行效率。而衡量算法执行效率的指标主要有两个,即时间复杂度和空间复杂度: 时间复杂度:衡量算法所需时间的度量,通常用“大O”符号来表示。比如,对于n个元素的数组,某些算法需要执行n次操作,这个算法的时间复杂度就…

    数据结构 2023年5月16日
    00
  • 在matlab中创建类似字典的数据结构方式

    当需要使用类似字典的数据结构时,Matlab中可以使用结构体来实现。结构体是一种有序的数据集合,每个元素都可以包含不同类型的数据(如字符串、数值等),并通过指定一个名称来唯一地标识该元素。 创建一个空结构体 使用struct函数可以创建一个空的结构体,可以使用下面的代码: st = struct; 添加键值对 可以将键值对添加到结构体中,可以使用下面的代码向…

    数据结构 2023年5月17日
    00
  • C语言数据结构之堆、堆排序的分析及实现

    C语言数据结构之堆、堆排序的分析及实现 什么是堆 堆(Heap)是一种特殊的树形数据结构,它满足两个条件: 堆是一棵完全二叉树; 堆中任意节点的值总是不大于/不小于其子节点的值。 如果父节点的值不大于所有子节点的值,此堆称为小根堆,又称为最小堆。如果父节点的值不小于所有子节点的值,此堆称为大根堆,又称为最大堆。 堆通常可以使用数组来实现,具体实现方法是将堆的…

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