POJ 2104 K-th Number ——划分树

本文介绍了划分树算法,主要用于解决求解整数区间内第k大的数问题,如POJ 2104。算法包括建树(时间复杂度O(nlogn),空间复杂度O(nlogn))和查找(时间复杂度O(logn))两个部分。建树通过递归方式构建平衡二叉树,查找过程中利用toleft数组辅助,实现快速查询。
摘要由CSDN通过智能技术生成

POJ 2104 题解 ——划分树


本文是一个系列的第一篇文章。本系列基于上交老师出品的《程序设计解题策略》书籍。该书介绍了49个ACM/ICPC算法设计策略。本系列打算用一个更简单的方式介绍书中的解题策略。当然,针对每个策略,也会给出相应的测试题目及其代码。

划分树算法

问题与复杂度

划分树主要应用于求解整数区间内第k大的数。相关的题目如POJ 2104。划分树整个算法主要分为两个部分:第一部分,建立划分树——时间复杂度为O(nlogn),空间复杂度为O(nlogn);第二部分,查找——每次查找的时间复杂度为O(logn)。其中,n表示输入到数组的数据的大小。

建树

划分树的逻辑结构 划分树的逻辑结构是一个(平衡)二叉树,如图1所示。每个结点是一个一位数组。当前结点的两个左右子节点分别存储当前结点中各一半的数据,并且左子结点数组中的所有数据都小于右子结点数组中的所有数据。要注意的是,相对位序是不变的,如图中所示。
在这里插入图片描述

图1 划分树的结构

建立划分树,就是使用递归的方法把上面的这个结构给构建出来。下面我们考虑使用什么样的存储结构来表示划分树。

存储结构 由于每个结点是一个数组,因此我们可以使用二维数组来模拟划分树,可表示tree[logN][N],其中N表示n的最大值。二维数组的第一维表示二叉树的某层,第二维表示某层上的结点。此外,我们还需要一个附加记录toleft[logN][N]来辅助后面的查找操作。toleft[depth][i]表示:在第depth层,从数组toleft[depth]的第1个位置到第i个位置中共有多少个元素被划分到了下一层的左子结点中。

建树代码 从数据存储角度看,建树过程就是对二维数组tree与toleft进行数据填充的过程。C++代码如下:

void buildPartitionTree(int l, int r, int depth){
   
    // build partition tree.
    if(l == r) return;
    int mid = (l+r)>>1;
    int leftEquMid = mid - l + 1; // the number of equal to A[mid] that will be partitioned to left

    for(int i=l; i<=r; i++){
   
        if(tree[depth][i] < A[mid]){
    // A is a array that be sorted by ascending order.
            leftEquMid--;
        }
    }
    int lpos=l, rpos= mid + 1;
    for(int i=l; i<=r; i++){
   
        if(tree[depth][i] < A[mid]){
   
            tree[depth+1][lpos++] = tree[depth][i];
        }else if(tree[depth][i] == A[mid] && leftEquMid > 0){
   
            tree[depth+1][lpos++] = tree[depth][i];
            leftEquMid--;
        }else{
   
            tree[depth+
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值