zkw线段树

zkw线段树(Zkw Segment Tree)线段树的升级版,其功能与传统的线段树相同,可以维护一个长度为n的数组,用O(log n)的时间复杂度更新元素,用O(log n)的时间复杂得到区间和。相比于传统线段树的递归实现,zkw线段树只要使用循环即可实现,并且代码行数更少,执行效率更好。

线段树有两个操作:

1  void update(int i, int delta):更新数组中下标为i的元素的值,将其值加delta

2  int get(int min, int max):得到区间[min, max]和

时间复杂度:更新和求区间和操作都是O(log n)

空间复杂度:O(n)

传统的线段树是自顶向下的,从根结点出发到叶子结点再回到根结点,而zkw线段树是自底向上的,直接从叶子结点出发到达根结点。

java代码实现

/**
 *              1
 *          /       \
 *       2             3
 *    /    \        /    \
 *   4      5      6      7
 *  / \    / \    / \    / \
 * 8  9  10  11  12 13  14 15
 */
public class ZkwSegmentTree {

    private int[] nodes;
    private int size;
    private int firstLeaf;

    public ZkwSegmentTree(int size) {
        this.size = size;
        for (firstLeaf = 1; firstLeaf < size; firstLeaf <<= 1);
        nodes = new int[firstLeaf + size];
    }

    public ZkwSegmentTree(int[] a) {
        size = a.length;
        for (firstLeaf = 1; firstLeaf < size; firstLeaf <<= 1);
        nodes = new int[firstLeaf + size];
        System.arraycopy(a, 0, nodes, firstLeaf, size);
        for (int ni = firstLeaf - 1; ni > 0; ni--) {
            int left = ni << 1, right = ni << 1 | 1;
            nodes[ni] = (left < nodes.length ? nodes[left] : 0) + (right < nodes.length ? nodes[right] : 0);
        }
    }

    public void update(int i, int delta) {
        for (int ni = firstLeaf + i; ni > 0; ni >>= 1) nodes[ni] += delta;
    }

    public int get(int i) {
        return nodes[firstLeaf + i];
    }

    public int get(int min, int max) {
        int sum = 0, left = firstLeaf + min, right = firstLeaf + max;
        for (; left < right; left >>= 1, right >>= 1) {
            if ((left & 1) == 1) sum += nodes[left++];
            if ((right & 1) == 0) sum += nodes[right--];
        }
        if (left == right) sum += nodes[left];
        return sum;
    }
}

rust代码实现

/**
 *              1
 *          /       \
 *       2             3
 *    /    \        /    \
 *   4      5      6      7
 *  / \    / \    / \    / \
 * 8  9  10  11  12 13  14 15
 */
pub struct ZkwSegmentTree {
    nodes: Vec<i32>,
    size: usize,
    first_leaf: usize,
}

impl ZkwSegmentTree {
    pub fn new(size: usize) -> Self {
        let mut first_leaf = 1;
        while first_leaf < size {
            first_leaf <<= 1;
        }
        let nodes = vec![0; first_leaf + size];
        ZkwSegmentTree { nodes, size, first_leaf }
    }

    pub fn from(a: Vec<i32>) -> Self {
        let size = a.len();
        let mut first_leaf = 1;
        while first_leaf < size {
            first_leaf <<= 1;
        }
        let mut nodes = vec![0; first_leaf + size];
        for i in 0..size {
            nodes[first_leaf + i] = a[i];
        }
        for ni in (1..first_leaf).rev() {
            let left = ni << 1;
            let right = ni << 1 | 1;
            nodes[ni] = nodes.get(left).unwrap_or(&0) + nodes.get(right).unwrap_or(&0)
        }
        ZkwSegmentTree { nodes, size, first_leaf }
    }

    pub fn update(&mut self, i: usize, delta: i32) {
        let mut ni = self.first_leaf + i;
        while ni > 0 {
            self.nodes[ni] += delta;
            ni >>= 1;
        }
    }

    pub fn get(&self, i: usize) -> i32 {
        self.nodes[self.first_leaf + i]
    }

    pub fn sum(&self, min: usize, max: usize) -> i32 {
        let mut sum = 0;
        let mut left = self.first_leaf + min;
        let mut right = self.first_leaf + max;
        while left < right {
            if (left & 1) == 1 {
                sum += self.nodes[left];
                left += 1;
            }
            if (right & 1) == 0 {
                sum += self.nodes[right];
                right -= 1;
            }
            left >>= 1;
            right >>= 1;
        }
        if left == right {
            sum += self.nodes[left];
        }
        sum
    }
}

源代码地址GitHub - SSSxCCC/Algorithm: Implement some data structures and algorithm.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值