Rangelab
实验背景
为实现范围查找,设计orderTable数据结构,本实验实现了一些基本的接口,并实现一定条件下的Rane query
实验细节
1 Ordered Tables
1.1 First and last
fun first (T : 'a table) : (key * 'a) option
fun last (T : 'a table) : (key * 'a) option
函数功能:
返回ordered table的第一个或者最后一个元素
函数思路:
既为BST存储,那么根据BST的特性求最大最小元素即可
函数代码:
fun first (T : 'a table) : (key * 'a) option =
case Tree.expose T of
NONE => NONE
| SOME {key, value, left, right} =>
case (Tree.expose left,Tree.expose right)
of (NONE,_) => SOME (key,value)
| (_,_) => first left
fun last (T : 'a table) : (key * 'a) option =
case Tree.expose T of
NONE => NONE
| SOME {key, value, left, right} =>
case (Tree.expose left,Tree.expose right)
of (_,NONE) => SOME (key,value)
| (_,_) => last right
1.2 Previous and next
fun previous (T : 'a table) (k : key) : (key * 'a) option
fun next (T : 'a table) (k : key) : (key * 'a) option
函数功能:
返回给定元素的之前或者之后的一个元素
函数思路:
将所给orderedtable在所给的key处切开,产生左树和右树,对左树取last即为previous,对右树取first即为next
函数代码:
fun previous (T : 'a table) (k : key) : (key * 'a) option =
last (#1 (Tree.splitAt (T,k)))
fun next (T : 'a table) (k : key) : (key * 'a) option =
first (#3 (Tree.splitAt (T,k)))
1.3 Join and split
fun join (L : 'a table, R : 'a table) :'a table
ffun split (L : 'a table, k : key) :'a table * 'a option * 'a table
函数功能:
合并两个table或者在某点切开一个table
函数思路:
调用Tree.join以及Tree.splitAt 即可
函数代码:
fun join (L : 'a table, R : 'a table) : 'a table =
Tree.join (L,R)
fun split (T : 'a table, k : key) : 'a table * 'a option * 'a table =
Tree.splitAt (T,k)
1.4 getRange
fun getRange (T : 'a table) (low :key, high :key) : 'a table
函数功能:
返回位于给定的key:low和high之间的元素构成的新的table
函数思路:
分别在low和high处切开,再取中间元素合并即可
函数代码:
fun getRange (T : 'a table) (low : key, high : key) : 'a table =
let
val (_,x,r) = split (T,low)
val x' = case x
of NONE => r
| SOME v => join (Tree.singleton (low,v),r)
val (l,y,_) = split (x',high)
val y' = case y
of NONE => l
| SOME v => join (Tree.singleton (high,v),l)
in
y'
end
2.1 makeCountTable
fun makeCountTable:point seq -> countTable
函数功能:
将所给的点串转化成countable
函数思路:
将输入的点按横坐标从小到大排序,然后整理成一个Table,Table.value是x<=key的全部点所构成的Table
函数代码:
type countTable = ((point seq) table) table
fun makeCountTable (S : point seq) : countTable =
if Seq.length S = 0 then empty ()
else
let
val preS = Seq.map (fn (x,y) => (x,(y,(x,y)))) S
val preT = Seq.map (fn (x,y) => (x,collect y)) (Seq.collect (fn (x,y) => compareKey (x,y)) preS)
fun f (x:(Key.t * Key.t) seq,y:(Key.t * Key.t) seq) = Seq.append (x,y)
val res = Seq.scani (fn ((m,x),(n,y)) => (n,merge f (x,y))) (#1 (Seq.nth preT 0),empty ()) preT
in
fromSeq res
end
渐进复杂度分析:
W(map)=O(n) S(map)=O(1)
W(preT)=O(nlogn) S(preT)=O(log^2n)
W(res)=O(n) S=O(logn)
2.2 count
count:Table -> point * point -> int
函数功能:
返回给定点所确定的矩形区域内的点的个数
函数思路:
求出xLight之前的点数以及xRight之前的点数作差即可
函数代码:
fun count (T : countTable)
((xLeft, yHi) : point, (xRght, yLo) : point) : int =
if size T = 0 then 0
else
let
val left = previous T xLeft
val leftNum = case left of NONE => 0
| SOME x => size (getRange (#2 x) (yLo,yHi))
val right = case find T xRght of NONE => previous T xRght
| SOME x => SOME (xRght,x)
val rightNum = case right of NONE => 0
| SOME x => size (getRange (#2 x) (yLo,yHi))
in
rightNum - leftNum
end