m4_divert(2)
m4_define(_commentnesting, 0)
m4_define(_begincomment,m4_dnl
m4_ifelse(_commentnesting, 0, ))
m4_define(_warning,m4_dnl
_begincomment()This document was created by gen-_name.html Do not edit this document, edit gen-_name.html._endcomment())
m4_define(_hdrs, )
m4_define(_anchor_no, 0)
m4_define(_abs, m4_ifelse(m4_eval($1 < 0), 1, m4_eval(-($1)), $1))
m4_define(hdr,
_warning()
,_warning()
$1
_warning())
m4_define(itl,_warning()$1_warning())
m4_define(bld,_warning()$1_warning())
m4_define(hrf,_warning()$2_warning())
m4_define(mailat,_warning()hrf(mailto:$1,$1)_warning())
m4_define(nwsgrp, hrf(news:$1, $1))
m4_define(bookref, $1, $2. $3: $4, $5.)
m4_define(i2m,m4_ifelse(
$1,01,January,
$1,02,February,
$1,03,March,
$1,04,April,
$1,05,May,
$1,06,June,
$1,07,July,
$1,08,August,
$1,09,September,
$1,10,October,
$1,11,November,December))
m4_dnl $Revision: 1.5 $, $Date: 1999/12/09 19:16:32 $
Let the value of itl(T)(itl(n)) be the number of edges in an itl(n)-vertex complete graph. Removing one vertex and the itl(n) - 1 adjacent edges leaves a complete graph with itl(n)-1 vertices; that is the number of edges in an itl(n)-vertex complete graph is itl(n) - 1 plus the number of edges in an itl(n)-1-vertex complete graph, or
itl(T)(itl(n)) = itl(n) - 1 + itl(T)(itl(n) - 1)Unrolling this a few times suggests the recurrence relation equals
itl(T)(1) = 0
sum(i = 1 to n, i - 1)
To prove recurrence relation correct, let the hypothesis be
itl(H)(itl(n)): itl(T)(itl(n)) = sum(itl(i) = 1 to itl(n), itl(i) - 1)The base case
itl(H)(1): itl(T)(1) = 0 = sum(itl(i) = 1 to 1, itl(i) - 1)holds. Let itl(H)(itl(j)) be true for itl(j) >= 1 and consider itl(H)(itl(j) + 1). Given a itl(j)-vertex complete graph, I can form a itl(j)+1-vertex complete graph by adding a vertex and itl(j) new edges; that is
itl(T)(itl(j) + 1) = itl(j) + itl(T)(itl(j))Because itl(H)(itl(j)) is true, this gives
which establishes itl(H)(itl(j) + 1).
itl(T)(itl(j) + 1) = itl(j) + sum(itl(i) = 1 to itl(j), itl(i) - 1) = sum(itl(i) = 1 to itl(j) + 1, itl(i) - 1)
Let the hypothesis be
itl(H)(itl(n)) = sps(itl(n), 2) - itl(n) is even.The base case itl(H)(0) = sps(0, 2) - 0 = 0 is true. Let itl(H)(itl(j)) be true for itl(j) >= 0 and consider itl(H)(itl(j) + 1):
which is even by the inductive hypothesis.
sps((itl(j) + 1), 2) - (itl(j) + 1) = sps(itl(j), 2) + 2itl(j) + 1 - itl(j) - 1 = sps(itl(j), 2) + itl(j)
The hypothesis itl(H)(itl(n)) be a straightforward restatement of the problem:
Either 0 <= itl(i) < itl(n) and itl(A)[itl(i)] = itl(x)The base case itl(H)(0) is established by setting itl(i) to -1: itl(A) contains no elements at all.
or itl(i) = -1 and for all itl(j) such that 0 <= itl(j) < itl(n), itl(A)[itl(i)] != itl(x)
for any itl(n)-element array itl(A).
For the inductive step, assume itl(H)(itl(j)) is true and consider itl(H)(itl(j) + 1). Given an itl(j) + 1 element array, pick any from the array and compare it to itl(x). If they're equal, set itl(i) appropriately, otherwise continue searching through the rest of the array. Because the rest of the array has itl(j) elements, the inductive hypothesis holds and itl(i) will be set correctly.
A linear search algorithm follows directly from the inductive argument; however, the argument selected an arbitrary element of itl(A) to examine, giving us a degree of freedom when developing the algorithm. Just to be different, the algorithm examines the middle element of itl(A).
where theint lsa(A, x) n <- |A| if n = 0 return -1 else m <- n/2 if A[m] = x return m else return lsa(A[0..m-1] || A[m+1..n-1], x)
||
operator is array concatenation.
The binary search algorithm is
Binary search works by chopping the array in half and throwing away the half that can't contain the element being searched for. The invariant should reflect that behavior:bool bsearch(a, x) l <- 0 r <- |a| do l < r m <- l + (r - l)/2 if a[m] <= x then l <- m + 1 or x < a[m] then r <- m fi od return l > 0 and a[l - 1] = x
a[0 .. l - 1] <= x and x < a[r .. |a| - 1] and l <= rIn this case, the invariant partitions the array so that the search element, if it exists, is in the left part of the array.
The initial assignments to l
and r
preserve the invariant because
they both describe empty segments of a
.
Let the invariant be true when the loop body starts executing. Because l <
r
, the first assignment establishes l <= m < r
. One of the two if
branches must be true. If the first is true, extending the left part of the
array to one past the element a[m]
maintains the invariant; it also
increases the value of l
. If the second branch is true, extending the
right part of the array to the element a[m]
also maintains the invariant
and decreases the value of r
. In either case, executing the do body
maintains the invariant.
Because the value of l
is increased or the value r
is decreased on
every iteration, eventually the do guard l < r
will fail, in which case
l >= r
. Coupled with the invariant l <= r
, this means that l =
r
, and all of a
has been partitioned into two parts. If a
contains
x
, it will be in the left part of itl(a), and, because itl(a) is sorted,
it will be the right-most element.
This page last modified on 12 i2m(11) 1999. m4_dnl $Revision: 1.2 $, $Date: 1999/03/12 17:36:48 $ m4_divert(1) m4_changequote({, }) {m4_define(tblfcntnts, _toc_tableit(}_hdrs{) _toc_down(_toc_ilevel, _toc_level) ) m4_define(_toc_tableit, m4_regexp($1, \([0-9]+\)\([0-9]+\)\([^]+\)\(.*\), m4_ifdef(_toc_level, , m4_define(_toc_level, m4_eval(\2 - 1)) m4_define(_toc_ilevel, _toc_level)) _toc_entry(\1, \2, \3) _toc_tableit(\4)) ) m4_define(_toc_down, m4_ifelse(m4_eval($1 < $2), 1, _toc_down($1, m4_eval($2 - 1))) ) m4_define(_toc_entry, m4_ifelse(m4_eval($2 > _toc_level),1,