Case | $a :: b^d$ | $T(n)$ | ||
1 | $a \lt b^d$ | $ n^d$ | ||
2 | $a = b^d$ | $n^d \lg n$ | ||
3 | $a \gt b^d$ | $n^{\log_b a}$ |
Case | $\log_b a :: d$ | $T(n)$ | ||
1 | $\log_b a \lt d$ | $ n^d$ | ||
2 | $\log_b a = d$ | $n^d \lg n = $ | ||
$n^{\log_b a}\lg n $ | ||||
3 | $\log_b a \gt d$ | $n^{\log_b a}$ |
type IntArray is Array(1 .. n) of Integer A: IntArray d: Float ... procedure closest_brute(A: IntArray, d: out Float) d := Float'last; -- Look at each pair, but only once for i in A'range for j in i + 1 .. A'last dis := distance (A(i), A(j)) -- A(j) - A(i) d := (if dis < d then dis else d)
procedure closest(A: IntArray, d: out Float) sort(A) cp_helper(A, 1, A'last, d) procedure cp_helper(A: Array, l, r: Positive; d: out Float) if r - l < 3 then -- Handle the base case else mid := (l + r) / 2 cp_helper (A, l, mid, dL) cp_helper (A, mid + 1, r, dR) d := (if dL < dR then dL else dR)
-- Are we done?
across_dis := distance (A(mid), A(mid+1)) -- A(mid + 1) - A(mid) d := (if across_dis < d then across_dis else d)
type Point is record x, y: Natural; end record type PointArray is Array(1 .. n) of Point A: Array(1 .. n) of Point d: Float ... procedure closest_brute(A: PointArray, d: out Float) d = Natural'last -- Look at each pair, but only once for i in 1 .. A'last loop for j in i + 1 .. A'last loop tmp_dis = distance(A(i), A(j)) if tmp_dis < d then d := tmp_dis
procedure closest(A: PointArray, d: out Float) sort_by_x(A) cp_helper(A, 1, A'last, d) procedure cp_helper(A: Array, l, r: Positive; d: out Float) if r - l < 3 then -- Handle the base case else -- Divide: find closest of left and right halves mid := (l + r) / 2 cp_helper (A, l, mid, dL) cp_helper (A, mid + 1, r, dR) d := (if dL < dR then dL else dR)
-- Are we done?
-- Conquer: Compare each point on left with each on right for i in l .. mid loop for j in mid + 1 .. r loop tmp_dis = distance(A(i), A(j)) if tmp_dis < d then d := tmp_dis
d
of midline procedure closest(A: PointArray, d: out Float) sort_by_x(A) cp_helper(A, 1, A'last, d) cp_helper(A: Array, l, r: Positive; d: out Float) if r - l < 3 then -- Handle the base case else -- Divide: find closest of left and right halves mid := (l + r) / 2 cp_helper(A, l, mid, dL) cp_helper(A, mid+1, r, dR) d = min(dL, dR) -- Conquer: Only compare points close to midline -- Fill slab with all points within d left or right of mid slab : Array (l .. r) of Point
fillslab(A, l, r, d, slab, slab_size)
fillslab(A: Array; l, r: Positive, d: Float; slab: out PointArray, num_added: out Natural) num_added := 0 midx := A((l + r) / 2).x for p of A(l..r) if abs(p.x - midx) < d then num_added := @ + 1 slab(num_added) := p
-- Search the slab for i in l .. slab_size loop for j in i + 1 .. slab_size loop tmp_dis = distance(slab(i), slab(j))tmp_dis = distance(A(i), A(j))if tmp_dis < d then d := tmp_dis
-- Search the Y-sorted slab for i in l .. slab_size - 1 loop for j in i + 1 .. min(i + 7, slabsize) loop tmp_dis = distance(slab(i), slab(j))tmp_dis = distance(A(i), A(j))if tmp_dis < d then d := tmp_dis
A(i)
A(i)
A(i)
, consider a rectangle of dimension $d\times 2d$ above point A(i)
A(i).y
A(i)
procedure closest(A: PointArray, d: out Float) sort_by_x(A) cp_helper(A, 1, A'last, d) procedure cp_helper(A: Array, l, r: Positive; d: out Float) if r - l < 3 then -- Handle the base case else -- Divide: find closest of left and right halves mid := (l+r)/2 cp_helper(A, l, mid, dL) cp_helper(A, mid+1, r, dR) d = min(dL, dR) -- Conquer: Only compare points close to midline -- Fill slab with all points within d -- left or right of mid slab : Array (l .. r) of Point
fillslab(A, l, r, d, slab, slab_size)
procedure fillslab(A: Array; l, r: Positive, d: Float; slab: out PointArray, num_added: out Natural) num_added := 0 midx := A((l + r) / 2).x for p of A(l..r) if abs(p.x - midx) <= d then num_added := @ + 1 slab(num_added) := p
-- Sort the slab (later we see how to avoid this sort!) sort(slab(1 .. slab_size)); -- Search the slab for i in l .. slab_size - 7 loop for j in i + 1 .. min(i + 7, slabsize) loop tmp_dis = distance(slab(i), slab(j))tmp_dis = distance(A(i), A(j))if tmp_dis < d then d := tmp_dis
procedure closest(A: PointArray, d: out Float) B: Array(A'range) of Point := A sort_by_X(A) sort_by_Y(B) cp_helper(A, 1, A'last, B, d) procedure cp_helper(A: PointArray, l, r: Positive; B: PointArray; d: out Float) if r - l < 3 then -- Handle the base case else -- Divide: Distribute, then solve left and right halves mid := (l + r) / 2 BL: Array(l .. mid) of Point BR: Array(mid + 1 .. r) of Point
distribute(B, A(mid).x, BL, BR)
procedure distribute(B: PointArray; midx: Natural; BL, BR: out PointArray) countL, countR: Natural := 0 for p of B if p.x < midx then countL := @ + 1 BL(countL) := p else countR := @ + 1 BR(countR) := p assert(countL + countR = r - l + 1 AND countL = countR)
cp_helper(A, l, mid, BL, dL) cp_helper(A, mid + 1, r, BR, dR) d = min(dL, dR) -- Conquer: Only compare points close to midline -- Fill slab with all points OF B within d -- left or right of mid of A slab : Array (l .. r) of Point fillslab(B, d, slab, slab_size) -- Search the slab for i in l .. slab_size - 1 loop for j in i + 1 .. min(i + 7, slabsize) loop tmp_dis = distance(slab(i), slab(j))tmp_dis = distance(A(i), A(j))if tmp_dis < d then d := tmp_dis
type Triple is ... type TripleArray is ... procedure closest(A: PointArray, d: out Float) sort_by_X(A) B: TripleArray(A'range) of Triple := makeTripleArray(A) sort_by_Y(B) cp_helper(A, 1, A'last, B, d) procedure cp_helper(A: PointArray, l, r: Positive; B: TripleArray; d: out Float) if r - l < 3 then -- Handle the base case else -- Divide: find closest of left and right halves mid := (l + r)/2 BL: Array(l .. mid) of Point BR: Array(mid+1 .. r) of Point distribute(B, A(mid).x, BL, BR) cp_helper(A, BL, l, mid, dL) cp_helper(A, BR mid+1, r, dR) d = min(dL, dR) -- Conquer: Only compare points close to midline -- Fill slab with all points OF B within d left or right of mid of A slab : Array (l .. r) of Point fillslab(B, d, slab, slab_size) -- Search the slab for i in l .. slab_size - 7 loop for j in i + 1 .. min(i + 7, slabsize) loop tmp_dis = distance(slab(i), slab(j))tmp_dis = distance(A(i), A(j))if tmp_dis < d then d := tmp_dis
type Pair is ... type PairArray is ... procedure closest(A: PointArray, d: out Float) sort_by_X(A) cp_helper(A, 1, A'last, d) procedure cp_helper(A: PointArray, l, r: Positive; d: out Float) with pre => is_X_sorted(A(l .. r)), post => is_Y_sorted(A(l .. r)) if r - l < 3 then -- Handle the base case else -- Divide: find closest of left and right halves mid := (l + r)/2 cp_helper(A, l, mid, dL) cp_helper(A, mid+1, r, dR) -- AL and AR are each now in Y-sorted order! d = min(dL, dR) B: PointArray(l .. r) -- Space for merge merge(A(l .. mid), A(mid + 1 .. r), B) -- Merge AL and AR into B, in Y-sorted order! A(l .. r) := B -- when we're done, A must be sorted! -- Conquer: Only compare points close to midline -- Fill slab with all points OF A within d left or right of mid of A -- TODO: Hmmm, we'd better calculate and pass midx to fillslab slab : Array (l .. r) of Point fillslab(A, d, slab, slab_size) -- Search the slab for i in l .. slab_size - 7 loop for j in i + 1 .. min(i + 7, slabsize) loop tmp_dis = distance(slab(i), slab(j))tmp_dis = distance(A(i), A(j))if tmp_dis < d then d := tmp_dis