Skyline Problem及算法分析

本文详细介绍了Skyline Problem的问题背景,通过一个实例展示了算法的实现过程,并重点分析了算法的时间复杂度为O(nlogn)。同时,文章证明了算法的正确性,确保了输出序列满足横坐标升序排列且符合 skyline 要求。
摘要由CSDN通过智能技术生成

问题

参见问题描述
在这里插入图片描述

算法实现

本文以Divide and Conquer为例使用sml来实现

定义1

  • critical point,即关键点,记作cp。它是用来刻画 s k y l i n e skyline skyline的点
  • point sequence,点序列,记作ps。它包含二维平面上的一些点 p i ( x i , y i ) p_i(x_i,y_i) pi(xi,yi)
  • critical point sequence,即关键点序列,记作cps(下同),它是刻画这些矩形的 s k y l i n e skyline skyline的一个最小 s e q u e n c e sequence sequence(并不只是简单的cp序列)
    e g \mathcal {eg} eg:对于一个矩形 b [ l , h , r ] b[l, h, r] b[l,h,r],它有两个 c p cp cp分别为 ( l , h ) (l, h) (l,h) ( r , 0 ) (r,0) (r,0) c p s b = < ( l , h ) , ( r , 0 ) > cps_{b}=<(l, h),(r,0)> cpsb=<(l,h),(r,0)>

概述

  • D i v i d e Divide Divide:将 p s ps ps分成两半
  • C o m b i n e Combine Combine:将两个 c p s cps cps按照横坐标 x i x_i xi升序排列合并为一个 c p s cps cps
//(*接受b[l,h,r]返回<(l,h),(r,0)>*)
fun getSkyline4One(b:int*int*int) =
    let val P = (#3 b, 0)::[]
    in (#1 b, #2 b)::P end;
    
//(*divide*)
//(*接受表xs,返回(xs/2, xs/2)*)
fun splitMid(xs) = 
	let fun split(x::xs, ys, n) = 
    		if n=0 then (rev ys, x::xs) else splitMid(xs, x::ys, n-1)
    in split(xs, [], length(xs) div 2) end
    
//(*combine*)
fun combine([], [], y, _, _) = rev y
    //(*合并完成 ,返回p(xi, yi)按照xi升序排列的 P表*)
  | combine([], sr::srs, y, hl, hr) = combine([], srs, sr::y, hl, hr)
    //(*LeftSkyline已经合并(扫描)完成,将RightSkyline剩余点之间插入合并的表中*)
  | combine(sl::sls, [], y, hl, hr) = combine(sls, [], sl::y, hl, hr)
    //(*RightSkyline已经合并(扫描)完成,将LeftSkyline剩余点之间插入合并的表中*)
  | combine(sl::sls, sr::srs, y, hl, hr) = 
    //(*一般的合并操作*)
        let val (slx, sly) = sl
            val (srx, sry) = sr
            val (_, lasth) = if null y then (0, 0) else hd y
        in  if slx<srx then //(*将Left中的点插入合并表*)
                let val maxh = if hr>sly then hr else sly
                in if lasth=maxh then combine(sls, sr::srs, y, sly, hr) 
                   else combine(sls, sr::srs, (slx, maxh)::y, sly, hr) end                      
            else //(*slx>srx 将Right中的点插入合并表*)
                let val maxh = if hl>sry then hl else sry
                in if lasth=maxh then combine(sl::sls, srs, y, hl ,sry)
                   else combine(sl::sls, srs, (srx,maxh)::y, hl, sry) end
        end;//(*if-else 均为尾递归 相当于扫描两个表 O(|L|+|R|), 由于splitMId |L|=|R|*)

fun MySkyline (bseq:(int*int*int) list):(int*int) list = 
    if List.length(bseq) = 1 then getSkyline4One(List.nth(bseq, 0))
    else let val (seq1, seq2) = splitMid(bseq) 
             val (sl, sr) = (MySkyline(seq1), MySkyline(seq2)) //(* skylineLeft  skylineRight *)
             val P = combine(sl, sr, [], 0, 0)
         in P end;

时间复杂度

fun MySkyline (bseq:(int*int*int) list):(int*int) list = 
    if List.length(bseq) = 1 then getSkyline4One(List.nth(bseq, 0)) //O(1)
    else let val (seq1, seq2) = splitMid(bseq, [], length(bseq) div 2) //O(n/2)
             val (sl, sr) = (MySkyline(seq1), MySkyline(seq2)) //2Work(n/2)
             val P = combine(sl, sr, [], 0, 0) //O(n)
         in P end;

除了更新高度的一些 O ( 1 ) O(1) O(1)操作, c o m b i n e combine combine完全等同于归并排序的 m e r g e merge merge,所以有,
W c o m b i n e ( n ) = W m e r g e ( n ) = O ( n ) W_{combine}(n)=W_{merge}(n)=O(n) Wcombine(n)=Wmerge(n)=O(n)

于是,
W M y S k y l i n e ( n ) = 2 W M y S k y l i n e ( n / 2 ) + W c o m b i n e ( n ) + W s p l i t M i d ( n ) + O ( 1 ) = 2 W M y S k y l i n e ( n / 2 ) + O ( n ) + O ( n 2 ) = 2 W M y S k y l i n e ( n / 2 ) + O ( n ) \begin{aligned} W_{MySkyline} (n) & =2W_{MySkyline}(n/2)+W_{combine}(n)+W_{splitMid}(n)+O(1)\\ & =2W_{MySkyline}(n/2)+O(n)+O(\frac n2)\\ & =2W_{MySkyline}(n/2)+O(n) \end{aligned} WMySkyline(n)=2WMySkyline(n/2)+Wcombine(n)+WsplitMid(n)+O(1)=2WMySkyline(n/2)+O(n)+O(2n)=2WMySkyline(n/2)+O(n)

主定理Brick Tree Method可得
W M y S k y l i n e ( n )

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值