segment树(线段树)

线段树(segment tree)是一种Binary Search Tree或者叫做ordered binary tree。对于线段树中的每一个非叶子节点[a,b],它的左子树表示的区间为[a,(a+b)/2],右子树表示的区间为[(a+b)/2+1,b]。如下图:

                                                                 [0-2]

                                                                /       \

                                                         [0-1]          [2-2]

                                                         /    \

                                                    [0-0]    [1-1]

 

下面看一道leetcode上的题,求动态区间的和(Range Sum Query - Mutable),题目如下:

Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive.

The update(i, val) function modifies nums by updating the element at index i to val.
Example:
Given nums = [1, 3, 5]

sumRange(0, 2) -> 9
update(1, 2)
sumRange(0, 2) -> 8
Note:
The array is only modifiable by the update function.
You may assume the number of calls to update and sumRange function is distributed evenly

分析如下:

一、构造线段树节点:

    class SegmentTreeNode {
        int start, end;
        int sum;
        SegmentTreeNode ltree, rtree;
        public SegmentTreeNode(int s, int e) {
            start = s;
            end = e;
        }
    }

二、建立线段树(根据数组nums,建立一个动态区间求和的线段树):

    public SegmentTreeNode buildTree(int[] nums, int left, int right) {
        SegmentTreeNode root = new SegmentTreeNode(left, right);
        if (left == right) {
            root.sum = nums[left];
        } else {
            int mid = left + (right - left)/2;
            root.ltree = buildTree(nums, left, mid);
            root.rtree = buildTree(nums, mid+1, right);
            root.sum = root.ltree.sum + root.rtree.sum;
        }
        return root;
    }

三、线段树的更新(更新int数组下标i的值为val):

    private void update(SegmentTreeNode root, int i, int val) {
        if (root.start == root.end) {
            root.sum = val;
        } else {
            int mid = root.start + (root.end-root.start)/2;
            if (i <= mid) {
                update(root.ltree, i, val);
            } else {
                update(root.rtree, i, val);
            }
            root.sum = root.ltree.sum + root.rtree.sum;
        }
    }

四、线段树的查询(查询int数组下标 i 到 j 的元素之和):

    private int sumRange(SegmentTreeNode root, int i, int j) {
        if (root.start == i && root.end == j) {
            return root.sum;
        } else {
            int mid = root.start + (root.end - root.start)/2;
            if (j <= mid) {
                return sumRange(root.ltree, i, j);
            } else if (i > mid) {
                return sumRange(root.rtree, i, j);
            } else {
                return sumRange(root.ltree, i, root.ltree.end) + sumRange(root.rtree, root.rtree.start, j);
            }
        }
    }

综上所述,上面Range Sum Query - Mutable的AC代码如下:

class SegmentTreeNode {
    int start, end;
    int sum;
    SegmentTreeNode ltree, rtree;
    public SegmentTreeNode(int s, int e) {
        start = s;
        end = e;
    }
}

public class NumArray {
    SegmentTreeNode root = null;
    
    public NumArray(int[] nums) {
        if(nums == null || nums.length == 0) {
            return;
        }
        root = buildTree(nums, 0, nums.length-1);
    }

    public SegmentTreeNode buildTree(int[] nums, int left, int right) {
        SegmentTreeNode root = new SegmentTreeNode(left, right);
        if (left == right) {
            root.sum = nums[left];
        } else {
            int mid = left + (right - left)/2;
            root.ltree = buildTree(nums, left, mid);
            root.rtree = buildTree(nums, mid+1, right);
            root.sum = root.ltree.sum + root.rtree.sum;
        }
        return root;
    }
    
    void update(int i, int val) {
        update(root, i, val);
    }

    private void update(SegmentTreeNode root, int i, int val) {
        if (root.start == root.end) {
            root.sum = val;
        } else {
            int mid = root.start + (root.end-root.start)/2;
            if (i <= mid) {
                update(root.ltree, i, val);
            } else {
                update(root.rtree, i, val);
            }
            root.sum = root.ltree.sum + root.rtree.sum;
        }
    }

    public int sumRange(int i, int j) {
         return sumRange(root, i, j);
    }

    private int sumRange(SegmentTreeNode root, int i, int j) {
        if (root.start == i && root.end == j) {
            return root.sum;
        } else {
            int mid = root.start + (root.end - root.start)/2;
            if (j <= mid) {
                return sumRange(root.ltree, i, j);
            } else if (i > mid) {
                return sumRange(root.rtree, i, j);
            } else {
                return sumRange(root.ltree, i, root.ltree.end) + sumRange(root.rtree, root.rtree.start, j);
            }
        }
    }
}

 

posted @ 2015-11-20 10:22  lasclocker  阅读(851)  评论(0编辑  收藏  举报