高级数据结构 - 线段树(2)

【回顾】
上一次我们讲了一些线段树的基础,地址是http://t.cn/RbQ9gVH,主要涉及的有对区间和单个点的修改、查询。这一篇则相对偏向效率与正确性的证明。
【线段树的高度】
首先我们假设线段树有n个节点,那么我们断言这棵线段树的高度不会超过 高级数据结构 - 线段树(2) - wenjianwei1 - 算法的设计。考虑将n替换成2的整幂次方,使得 高级数据结构 - 线段树(2) - wenjianwei1 - 算法的设计,而k最小。这很容易实现,一个简单的while循环之类就可以轻易搞定了。然后,以这个2的整幂次方为节点数建一棵线段树,显然这棵新的线段树必定不会比原来的更浅,如果比原来的更浅,那就干脆将剩余的那些节点用特殊值补掉,反正也可以通过处理令其不会影响结果。那么这颗线段树的高度,其实和二分查找的类似。想想看,点状匹配第p个元素,实际上就是在一个序列1,2,3,4,5……n中二分查找一个元素p,只不过我们将区间化作一个个的节点,这样更加强大。
那么,我们继续考虑,如果我们点状匹配一个元素,那么最后到达的必定是叶节点。让我们继续考虑,如果现在访问到了某一个节点d,那么下一步因为是点状匹配,所以说只会到某一个子节点去,而这个子节点所管理的空间比d少一半,所以我们可以很轻易地得出结论:任意一颗高度为2的正幂次方的线段树的高度不超过 高级数据结构 - 线段树(2) - wenjianwei1 - 算法的设计。再有我们上面的另一个结论,就算n不是2的整幂次方,那么这棵线段树仍然高度不会超过 高级数据结构 - 线段树(2) - wenjianwei1 - 算法的设计

【各种操作的效率】
下面我们来考虑各个上一篇文章里所讲述了的操作:点状查询、点状修改、区间查询、区间修改。在这个开头,我们先归约一下。
实际上来说,点状的查询和修改都在本质上属于区间的修改和查询的子集,因此这两个操作完全可以忽略。不过,这会不会对效率有影响呢?我们下面就先简单地分析一下:点状的查询和修改,因为只是查询或修改某一个元素,那么这个元素肯定处在叶节点上,由程序我们可以知道,其的时间复杂度刚好就是线段树的高度!所以说,这是一个和二分查找的时间复杂度非常类似的复杂度。查询和修改在本质上都很相似,因此都是 高级数据结构 - 线段树(2) - wenjianwei1 - 算法的设计级别的时间复杂度。
下面继续来分析一下区间级别的操作。
修改和查询类似,只不过查询时将相应的节点进行一定的答案合并操作(如求最值、求和)接着返回,而修改是将标记打上去。这么说,我们就只讨论查询了。
查询过程中,我们都知道,在极限的情况下,查询过程可能会到达叶节点,那么我们的问题来了:在线段树的某一层中,最多可能有多少个节点被线段树包含?如果我们能求出来,就将这个节点数的函数和树的高度相乘,就可以得出极限情况下的时间复杂度了。很容易看出,答案是最多4个,如下所示:
高级数据结构 - 线段树(2) - wenjianwei1 - 算法的设计
  这是很自然的。但是,现实一定是这样的吗?一定会只有这么多个吗?会不会出现更多?下面就予以说明。我们假想一下,如果在下面的一层中出现了除这4个之外的一个节点,它也被选中了,那么这个节点应该在哪里?我们将上层的两个节点标为1、2,下层的四个节点标为3、4、5、6,那么,这个节点不可能在3左边或6的右边。因为查询是连续的,我们看到3和6中都没有完全选完,这意味着,区间的开始和结尾,都分别在3和6号节点所表示的范围内,而如果在3的左边或6的右边,这就意味着这个区间中间有一段没有被选到!这和算法的逻辑相悖。
接着,这个节点有可能是节点4和5间的一个点吗?仍然不可能。因为如果这个节点在4和5之间,那么其的某个祖先一定被选了。这样的话,既然选了一个祖先,那么以这个祖先为根的子树都相当于被选了(在节点上有附加的信息!),那么我们还要这个节点干什么?
综上所述,一层最多四个节点(被选),这是一个常数,所以各种操作的效率都是 高级数据结构 - 线段树(2) - wenjianwei1 - 算法的设计 。相当低。
【正确性证明】
  正确性的证明可以说是显而易见了。由程序的逻辑,我们很容易推出来,这里就忽略了。

你可能感兴趣的:(数据结构)