zoukankan      html  css  js  c++  java
  • 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);
                }
            }
        }
    }
  • 相关阅读:
    .net实现浏览器大文件分片上传
    asp.net实现浏览器大文件分片上传
    php实现浏览器大文件分片上传
    Java实现浏览器大文件分片上传
    文件分片上传
    大文件分片上传
    pdf缩略图生成上传解决方案
    专业精神的三个步骤
    安卓TabHost+ViewPager+RadioGroup多功能模板整理
    java基础之概谈xml文件解析
  • 原文地址:https://www.cnblogs.com/lasclocker/p/4979933.html
Copyright © 2011-2022 走看看