数据结构-线段树 初始化、区间查询和区间更新(待完善)

一. 线段树的特点

  • 平衡二叉树:最大的深度 和最小的深度 差最大为1。

  • 一种二叉搜索树。它将一段区间划分为若干单位区间,每一个节点都储存着一个区间。它功能强大,支持区间求和,区间最大值,区间修改,单点修改等操作。
    处理问题: 区间查询 ,区间更新

  • 线段树 是以空间换时间的处理,开启4N的空间
    如果区间有n个元素,数组表示需要有多少节点? 4n的空间,我们的线段树不考虑添加元素,即空间固定,使用4n的静态空间即可。可能有浪费,最坏情况,浪费2n-1的空间,空间换时间。

    0 层 : 1
    1 层 : 2
    2 层 : 4
    3 层 : 8
    。。。
    h 层 : 2^h -1
    对满二叉树: h层,一共·2^h -1 个节点(大约2 ^ h)
    最后一层 (h-1)层,有2^(h-1) -1 个节点
    最后一层的节点数大致等于前面所有层节点之和。
    如果 n = 2^k ,只需要2n区间
    最坏情况,如果n = 2^k + 1 ,需要4n的空间。
    如果使用链表,可以避免浪费空间。

二. 线段树的初始化

在这里插入图片描述
伪代码如下:

 /**
 * 在treeIndex的位置创建表示区间[l...r]的线段树
 * 递归实现 这里有些不好理解,需要手动画画
 *
 * @param treeIndex
 * @param l
 * @param r
 */
private void buildSegmentTree(int treeIndex, int l, int r) {
    if (l == r) {
        tree[treeIndex] = data[l];
        return;
    }
    int leftTreeIndex = leftChild(treeIndex);
    int rightTreeIndex = rightChild(treeIndex);
    //创建左右子树
    int mid = l + (r - l) / 2;
    //l,mid; mid+1,r;递归
    buildSegmentTree(leftTreeIndex, l, mid);
    buildSegmentTree(rightTreeIndex, mid + 1, r);
    tree[treeIndex] = merge.merge(tree[leftTreeIndex], tree[rightTreeIndex]);
}

三. 区间查询

在这里插入图片描述
伪代码如下:

/**
     * 在以treeIndex为根的线段树中【l,r】的范围里,搜索区间【queryL,queryR】的值
     *
     * @param treeIndex  初始为0
     * @param l     初始为0 
     * @param r     初始为数组最大索引
     * @param queryL  左区间
     * @param queryR   右区间
     * @return
     */
    private E query(int treeIndex, int l, int r, int queryL, int queryR) {
        if (l == queryL && r == queryR) {
            return tree[treeIndex];
        }
        int mid = l + (r - l) / 2;
        int leftTreeIndex = leftChild(treeIndex);
        int rightTreeIndex = rightChild(treeIndex);
        if (queryL >= mid + 1) {
            return query(rightTreeIndex, mid + 1, r, queryL, queryR);
        } else if (queryR <= mid) {
            return query(leftTreeIndex, l, mid, queryL, queryR);
        } else {
            //一部分左孩子,一部分右孩子上
            E leftResult = query(leftTreeIndex, l, mid, queryL, mid);
            E rightResult = query(rightTreeIndex, mid + 1, r, mid + 1, queryR);
            return merge.merge(leftResult, rightResult);
        }
    }

四. 区间更新

都是采用递归的方式更新

//在以treeIndex为跟的线段树种更新index的值为e 类似二分搜索树中的更新
public void set(int treeIndex, int l, int r, int index, E e) {
    if (l == r) {
        tree[treeIndex] = e;
        return;
    }
    int mid = l + (r - l) / 2;
    int leftTreeIndex = leftChild(treeIndex);
    int rightTreeIndex = rightChild(treeIndex);
    if (index >= mid + 1) {
        set(rightTreeIndex, mid + 1, r, index, e);
    } else {
        set(leftTreeIndex, l, mid, index, e);
    }
    tree[treeIndex] = merge.merge(tree[leftTreeIndex], tree[rightTreeIndex]);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章