Java手写树状数组(BIT)和树状数组(BIT)应用拓展案例

Java手写树状数组(BIT)和树状数组(BIT)应用拓展案例

1. 算法思维导图

以下是使用mermaid代码表示的树状数组(BIT)的实现原理:
树状数组 初始化 更新操作 查询操作 更新子节点 查询子节点

2. 该算法的手写必要性及市场调查

树状数组(BIT)是一种高效的数据结构,用于解决一维区间和的查询和更新问题。它在很多算法中都有广泛的应用,如逆序对的计算、求解逆序数、求解最小逆序对等。手写该算法有以下必要性和市场调查:

  • 必要性:手写该算法可以更深入地理解其原理和实现细节,有助于提高编程能力和解决实际问题的能力。
  • 市场调查:树状数组(BIT)在算法竞赛、数据处理、图像处理等领域都有广泛的应用,掌握该算法的手写实现可以提高在相关领域的竞争力。

3. 该算法的实现详细介绍和步骤

3.1 初始化

树状数组的初始化需要一个数组和数组的长度作为参数。初始化的步骤如下:

  1. 创建一个长度为n+1的数组bit,用于存储树状数组的节点。
  2. 将bit数组的所有元素初始化为0。
java 复制代码
class BinaryIndexedTree {
    int[] bit;

    BinaryIndexedTree(int n) {
        bit = new int[n+1];
        for (int i = 0; i <= n; i++) {
            bit[i] = 0;
        }
    }
}

3.2 更新操作

树状数组的更新操作用于将指定位置上的元素加上一个值。更新操作的步骤如下:

  1. 从更新位置开始,不断向上更新父节点,直到达到树状数组的最大长度。
  2. 更新父节点的值为原值加上要更新的值。
java 复制代码
class BinaryIndexedTree {
    // ...

    void update(int index, int value) {
        while (index < bit.length) {
            bit[index] += value;
            index += index & -index;
        }
    }
}

3.3 查询操作

树状数组的查询操作用于计算指定位置之前的所有元素的和。查询操作的步骤如下:

  1. 从查询位置开始,不断向上查询父节点,直到达到树状数组的最小长度。
  2. 将查询结果累加到一个变量中,直到达到查询位置。
java 复制代码
class BinaryIndexedTree {
    // ...

    int query(int index) {
        int sum = 0;
        while (index > 0) {
            sum += bit[index];
            index -= index & -index;
        }
        return sum;
    }
}

4. 该算法的手写实现总结及思维拓展

手写树状数组(BIT)的实现过程中,我们深入理解了其原理和实现细节。通过手动编写代码,我们加深了对树状数组的理解,并且可以根据实际需求进行定制化的修改和拓展。此外,手写实现也有助于提高编程能力和解决实际问题的能力。

思维拓展:除了基本的查询和更新操作,树状数组还可以进行一些其他的高级操作,如区间更新、区间查询等。可以根据实际需求进行相应的拓展和改进。

5. 该算法的完整代码

java 复制代码
class BinaryIndexedTree {
    int[] bit;

    BinaryIndexedTree(int n) {
        bit = new int[n+1];
        for (int i = 0; i <= n; i++) {
            bit[i] = 0;
        }
    }

    void update(int index, int value) {
        while (index < bit.length) {
            bit[index] += value;
            index += index & -index;
        }
    }

    int query(int index) {
        int sum = 0;
        while (index > 0) {
            sum += bit[index];
            index -= index & -index;
        }
        return sum;
    }
}

6. 该算法的应用前景调研

树状数组(BIT)作为一种高效的数据结构,有着广泛的应用前景。以下是该算法在不同领域的应用调研:

  • 算法竞赛:树状数组常用于解决一维区间和的查询和更新问题,是算法竞赛中常用的数据结构之一。
  • 数据处理:树状数组可以用于求解逆序对、求解最小逆序对等问题,对于大规模数据的处理具有较高的效率。
  • 图像处理:树状数组可以用于图像处理中的像素统计、图像压缩等操作,提高图像处理的速度和效果。

7. 该算法的拓展应用案例

以下是树状数组(BIT)的三个拓展应用案例的完整代码和步骤描述:

7.1 求解逆序数

java 复制代码
class Solution {
    public int reversePairs(int[] nums) {
        int n = nums.length;
        int[] copy = new int[n];
        System.arraycopy(nums, 0, copy, 0, n);
        Arrays.sort(copy);
        BinaryIndexedTree bit = new BinaryIndexedTree(n);
        int count = 0;
        for (int i = 0; i < n; i++) {
            count += bit.query(bit.getIndex(copy, 2L * nums[i] + 1));
            bit.update(bit.getIndex(copy, nums[i]), 1);
        }
        return count;
    }
}

步骤描述:

  1. 创建一个长度为n的辅助数组copy,并将原数组nums复制到copy中。
  2. 对copy进行排序,得到有序的副本。
  3. 创建一个长度为n的树状数组bit。
  4. 初始化逆序数的计数器count为0。
  5. 遍历原数组nums,对于每个元素nums[i],在树状数组bit中查询大于2 * nums[i]的元素个数,并累加到count中。
  6. 在树状数组bit中更新元素nums[i]的计数。
  7. 返回逆序数的计数器count。

7.2 区间和的查询

java 复制代码
class NumArray {
    int[] nums;
    int[] bit;

    public NumArray(int[] nums) {
        this.nums = nums;
        this.bit = new int[nums.length + 1];
        for (int i = 0; i < nums.length; i++) {
            update(i, nums[i]);
        }
    }

    public void update(int index, int val) {
        int diff = val - nums[index];
        nums[index] = val;
        index++;
        while (index <= nums.length) {
            bit[index] += diff;
            index += index & -index;
        }
    }

    public int sumRange(int left, int right) {
        return query(right + 1) - query(left);
    }

    private int query(int index) {
        int sum = 0;
        while (index > 0) {
            sum += bit[index];
            index -= index & -index;
        }
        return sum;
    }
}

步骤描述:

  1. 创建一个长度为n的数组nums,并将输入的nums复制到该数组中。
  2. 创建一个长度为n+1的树状数组bit,并初始化为0。
  3. 遍历数组nums,对于每个元素,调用update方法更新树状数组bit。
  4. 在update方法中,计算差值diff为新值与原值的差,更新nums[index]为新值,并将差值diff累加到bit[index]中,同时更新index为下一个需要更新的位置。
  5. 在sumRange方法中,调用query方法查询右边界right+1的前缀和,减去查询左边界left的前缀和,即可得到[left, right]的区间和。
  6. 在query方法中,初始化求和变量sum为0,然后从index开始,每次将bit[index]累加到sum中,然后将index减去最低位的1,直到index为0为止,最后返回sum。

7.3 区间更新和查询

java 复制代码
class NumArray {
    int[] nums;
    int[] bit1;
    int[] bit2;

    public NumArray(int[] nums) {
        this.nums = nums;
        this.bit1 = new int[nums.length + 1];
        this.bit2 = new int[nums.length + 1];
        for (int i = 0; i < nums.length; i++) {
            update(i, i, nums[i]);
        }
    }

    public void update(int left, int right, int val) {
        updateBIT(bit1, left, val);
        updateBIT(bit1, right + 1, -val);
        updateBIT(bit2, left, val * (left - 1));
        updateBIT(bit2, right + 1, -val * right);
    }

    public int sumRange(int left, int right) {
        return sumBIT(bit1, right) * right - sumBIT(bit2, right) - sumBIT(bit1, left - 1) * (left - 1) + sumBIT(bit2, left - 1);
    }

    private void updateBIT(int[] bit, int index, int val) {
        index++;
        while (index < bit.length) {
            bit[index] += val;
            index += index & -index;
        }
    }

    private int sumBIT(int[] bit, int index) {
        int sum = 0;
        index++;
        while (index > 0) {
            sum += bit[index];
            index -= index & -index;
        }
        return sum;
    }
}

步骤描述:

  1. 创建一个长度为n的数组nums,并将输入的nums复制到该数组中。
  2. 创建两个长度为n+1的树状数组bit1和bit2,并初始化为0。
  3. 遍历数组nums,对于每个元素,调用update方法更新树状数组bit1和bit2。
  4. 在update方法中,先调用updateBIT方法更新bit1,将val累加到bit1[left],将-val累加到bit1[right+1],然后调用updateBIT方法更新bit2,将val * (left-1)累加到bit2[left],将-val * right累加到bit2[right+1]。
  5. 在sumRange方法中,调用sumBIT方法计算right的前缀和乘以right,减去sumBIT方法计算right的前缀和,再减去sumBIT方法计算left-1的前缀和乘以left-1,最后加上sumBIT方法计算left-1的前缀和,即可得到[left, right]的区间和。
  6. 在updateBIT方法中,将index加1,然后从index开始,每次将val累加到bit[index]中,然后将index加上最低位的1,直到index小于bit的长度为止。
  7. 在sumBIT方法中,将index加1,然后从index开始,每次将bit[index]累加到sum中,然后将index减去最低位的1,直到index为0为止,最后返回sum。

以上是树状数组的拓展应用案例的完整代码和步骤描述。这些案例展示了树状数组在不同问题中的灵活应用,可以根据实际需求进行相应的拓展和改进。

相关推荐
A charmer2 分钟前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
Peter_chq4 分钟前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
Yaml427 分钟前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍
小小小妮子~29 分钟前
Spring Boot详解:从入门到精通
java·spring boot·后端
hong16168830 分钟前
Spring Boot中实现多数据源连接和切换的方案
java·spring boot·后端
wheeldown31 分钟前
【数据结构】选择排序
数据结构·算法·排序算法
aloha_7891 小时前
从零记录搭建一个干净的mybatis环境
java·笔记·spring·spring cloud·maven·mybatis·springboot
记录成长java1 小时前
ServletContext,Cookie,HttpSession的使用
java·开发语言·servlet
前端青山1 小时前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js
睡觉谁叫~~~2 小时前
一文解秘Rust如何与Java互操作
java·开发语言·后端·rust