Libros de misterio recomendados.
ENCUESTAS A ESTUDIANTES
The majority of examples in the remaining chapters use the banker’s method rather than the physicist’s method. Therefore, we give a second example of the physicist’s method here.
Imagine that you want to sort several similar lists, such as
xs
andx
::xs
, orxs
@zs
andys
@zs
. For efficiency, you wish to take advantage of the fact that these lists share common tails, so that you do not repeat the work of sorting those tails. We call an abstract data type for this problem a sortable collection.Figure 3.5 gives a signature for sortable collections. Note that the
new
function, which creates an empty collection, is parameterized by the “less than” relation on the elements to be sorted.Now, if we create a sortable collection
xs
0by adding each of the elements in
xs
, then we can sort bothxs
andx
::xs
by callingsort xs
0and
sort
(add
(x
,xs
0signature SORTABLE =
sig
typeSortable
val new : fLess :!boolg!Sortable (sort in increasing order by Less)
val add :Sortable!Sortable
val sort :Sortable!list
end
Figure 3.5: Signature for sortable collections.
One possible representation for sortable collections is balanced binary search trees. Then
add
takesO(log n)
worst-case time andsort
takesO(n)
time. We achieve the same bounds, but in an amortized sense, using bottom-up mergesort.Bottom-up mergesort first splits a list into
n
ordered segments, where each segment initially contains a single element. It then merges equal-sized segments in pairs until only one segment of each size remains. Finally, segments of unequal size are merged, from smallest to largest.Suppose we take a snapshot just before the final cleanup phase. Then the sizes of all segments are distinct powers of 2, corresponding to the one bits of
n
. This is the representation we will use for sortable collections. Then similar collections will share all the work of bottom- up mergesort except for the final cleanup phase merging unequal-sized segments. The complete representation is a suspended list of segments, each of which is anlist
, together with the comparison function and the size.type
Sortable =fLess : !bool, Size : int, Segments : list list suspgThe individual segments are stored in increasing order of size, and the elements in each segment are stored in increasing order as determined by the comparison function.
The fundamental operation on segments is
merge
, which merges two ordered lists. Except for being parameterized onless
, this function is completely standard.fun merge
less
(xs
,ys
) = let fun mrg ([ ],ys
) =ys
jmrg (
xs
, [ ]) =xs
jmrg (
x
::xs
,y
::ys
) = ifless
(x
,y
) thenx
:: mrg (xs
,y
::ys
)else
y
:: mrg (x
::xs
,ys
) in mrg (xs
,ys
) endTo add a new element, we create a new singleton segment. If the smallest existing segment is also a singleton, we merge the two segments and continue merging until the new segment
is smaller than the smallest existing segment. This merging is controlled by the bits of
n
. If the lowest bit ofn
is zero, then we simply cons the new segment onto the segment list. If the lowest bit is one, then we merge the two segments and repeat. Of course, all this is done lazily.fun add (
x
,fLess =less
, Size =size
, Segments =segs
g) =let fun addSeg (
seg
,segs
,size
) =if
size
mod 2 = 0 thenseg
::segs
else addSeg (merge
less
(seg
, hdsegs
), tlsegs
,size
div 2)infLess =
less
, Size =size
+1, Segments = $addSeg ([x
], forcesegs
,size
)gendFinally, to
sort
a collection, we merge the segments from smallest to largest. fun sortfLess =less
, Segments =segs
, . . .g=let fun mergeAll (
xs
, [ ]) =xs
jmergeAll (
xs
,seg
::segs
) = mergeAll (mergeless
(xs
,seg
),segs
)in mergeAll ([ ], force
segs
) endRemark:
mergeAll
can be viewed as computing [ ]1s
1
11
s
mwhere
s
i is thei
th segment and1is left-associative, infix notation formerge
. This is a specificinstance of a very common program schema, which can be written
cx
1
x
mfor any
c
and left-associative . Other instances of this schema include summing a list ofintegers (
c = 0
and= +
) or finding the maximum of a list of natural numbers (c = 0
and
= max
). One of the greatest strengths of functional languages is the ability to defineschemas like this as higher-order functions (i.e., functions that take functions as arguments or return functions as results). For example, the above schema might be written
fun foldl (
f
,c
, [ ]) =c
jfoldl (
f
,c
,x
::xs
) = foldl (f
,f
(c
,x
),xs
)Then
sort
could be writtenfun sortfLess =
less
, Segments =segs
, . . .g= foldl (mergeless
, [ ], forcesegs
)This also takes advantage of the fact that
merge
is written as a curried function. A curried function is a multiargument function that can be partially applied (i.e., applied to just some of its arguments). The result is a function that takes the remaining arguments. In this case, we have appliedmerge
to just one of its three arguments,less
. The remaining two arguments willstructure BottomUpMergeSort : SORTABLE =
struct
typeSortable =fLess :!bool, Size : int, Segments :list list suspg
fun merge
less
(xs
,ys
) =let fun mrg ([ ],
ys
) =ys
jmrg (xs
, [ ]) =xs
jmrg (
x
::xs
,y
::ys
) = ifless
(x
,y
) thenx
:: mrg (xs
,y
::ys
)else
y
:: mrg (x
::xs
,ys
)in mrg (
xs
,ys
) endfun newfLess =
less
g=fLess =less
, Size = 0, Segments = $[ ]gfun add (
x
,fLess =less
, Size =size
, Segments =segs
g) =let fun addSeg (
seg
,segs
,size
) =if
size
mod 2 = 0 thenseg
::segs
else addSeg (merge
less
(seg
, hdsegs
), tlsegs
,size
div 2)infLess =
less
, Size =size
+1, Segments = $addSeg ([x
], forcesegs
,size
)gendfun sortfLess =
less
, Segments =segs
, . . .g=let fun mergeAll (
xs
, [ ]) =xs
jmergeAll (
xs
,seg
::segs
) = mergeAll (mergeless
(xs
,seg
),segs
)in mergeAll ([ ], force
segs
) endend
Figure 3.6: Sortable collections based on bottom-up mergesort.
The complete code for this implementation of sortable collections appears in Figure 3.6. We show that
add
takesO(log n)
amortized time andsort
takesO(n)
amortized time using the physicist’s method. We begin by defining the potential function , which is completely determined by the size of the collection:(n) = 2n
;2
1 Xi=0
b
i(n mod 2
i+ 1)
where
b
i is thei
th bit ofn
. Note that(n)
is bounded above by2n
and that(n) = 0
exactly whenn = 2
k;1
for somek
.We first calculate the complete cost of
add
. Its unshared cost is one and its shared cost is the cost of performing the merges inaddSeg
. Suppose that the lowestk
bits ofn
are one (i.e.,b
i= 1
fori < k
andb
k= 0
). ThenaddSeg
performsk
merges. The first combines two lists of size 1, the second combines two lists of size 2, and so on. Since merging two lists of sizem
takes2m
steps,addSeg
takes(1+1)+(2+2)++(2
k;1
+2
k;1) = 2(
Pk;1
i=0
2
i
) = 2(2
k;1)
steps. The complete cost of
add
is therefore2(2
k ;1) + 1 = 2
k +1Next, we calculate the change in potential. Let
n
0=
n + 1
and letb
0 i be thei
th bit ofn
0 . Then,(n
0)
;(n) = 2n
0 ;2
P 1 i=0b
0 i(n
0mod 2
i+ 1)
;(2n
;2
P 1 i=0b
i(n mod 2
i+ 1))
= 2 + 2
P 1 i=0(b
i(n mod 2
i+ 1)
;b
0 i(n
0mod 2
i+ 1))
= 2 + 2
P 1 i=0(i)
where
(i) = b
i(n mod 2
i+ 1)
;b
0i
(n
0mod 2
i+ 1)
. We consider three cases:
i < k
,i = k
, andi > k
.(
i < k
): Sinceb
i= 1
andb
0i
= 0
,(k) = n mod 2
i+ 1
. Butn mod 2
i= 2
i ;1
so(k) = 2
i. (i = k
): Sinceb
k= 0
andb
0 k= 1
,(k) =
;(n
0mod 2
k+ 1)
. Butn
0mod 2
k= 0
so(k) =
;1 =
;b
0 k. (i > k
): Sinceb
0 i=
b
i,(k) = b
0 i(n mod 2
i ;n
0mod 2
i)
. Butn
0mod 2
i= (n +
1) mod 2
i=n mod 2
i+ 1
so(i) = b
0i
(
;1) =
;b
0 i. Therefore,(n
0)
;(n) = 2 + 2
P 1 i=0(i)
= 2 + 2
Pk ;1 i=02
i+ 2
P 1 i=k(
;b
0 i)
= 2 + 2(2
k ;1)
;2
P 1 i=kb
0 i= 2
k+1 ;2B
0 whereB
0is the number of one bits in
n
0. Then the amortized cost of
add
is(2
k+1 ;1)
;(2
k +1 ;2B
0) = 2B
0 ;1
SinceB
0is
O(log n)
, so is the amortized cost ofadd
.Finally, we calculate the amortized cost of
sort
. The first action ofsort
is to force the suspended list of segments. Since the potential is not necessarily zero, this adds(n)
to the amortized cost of the operation. It next merges the segments from smallest to largest. The worst case is whenn = 2
k ;1
, so that there is one segment of each size from1
to2
k;1
. Merging these segments takes