home *** CD-ROM | disk | FTP | other *** search
- FUNCTION select(VAR list : real_array;first,last,k : INTEGER) : BOOLEAN;
-
- {$c-,m-,f-,r- [turn off checking options for speed : select is debugged]}
- {
- Original Authors : Robert W.Floyd,Stanford U.,Ca. &
- Ronald L.Rivest,M.I.T.,Ma.
- Original language : Algol
- Reference : Algorithm 489 Collected Algorithms A.C.M.
-
- Modified 1982 for Pascal/z by G.M.Acland,U. of Penn.
-
- Comment : Does a partial sort of the array list (using a partitioning technic
- similar to that used in QUICKSORT,QUICKERSORT etc.),such that :
- 1 : list[k] ends up containing the (k - first +1)th smallest value.
- 2 : all values for list[i] such that i =< k , will be =< list[k].
- i.e. the left "half" of the array will contain only values
- equal to or less than the (k - first + 1)th smallest.
- 3 : all values for list[i] such that i >= k , will be >= list[k].
- i.e. the right "half" contains only values equal to or
- greater than the (k - first + 1)th smallest.
- The most frequent use for this type of procedure is in finding the
- median of an array.In this case one sets first = 1 , last = n , where n is the
- order of the array,and k := (first+last)DIV 2 for n = ODD.Where n is even the
- median calculation is more complex.The FUNCTION median demonstrates this use.
- If the function is called with ((last - first) < 1 ) , or if k is
- < first or > last , it returns FALSE.
- }
-
- CONST
- multiplier = 0.1;
- cutoff = 100; { segment size below which the algorithm
- does not sample but only partitions. }
- VAR
- left,right,
- leftpart,
- rightpart,
- newleft,
- newright : INTEGER;
- altleft,
- altright,
- leftside,
- rightside,
- samplesize,
- listsize,
- lnlistsize,
- tempreal,
- estimate,sd,
- sd1,sd2 : REAL;
- dummy : BOOLEAN;
-
- FUNCTION larger(a,b:INTEGER):INTEGER;
- BEGIN
- IF a > b THEN larger := a ELSE larger := b;
- END;
-
- FUNCTION smaller(a,b:INTEGER):INTEGER;
- BEGIN
- IF a < b THEN smaller := a ELSE smaller := b;
- END;
-
- PROCEDURE exchange(VAR a,b:REAL);
- VAR temp : REAL;
- BEGIN
- temp := a;
- a := b;
- b := temp;
- END;
-
- BEGIN { function SELECT }
- IF ((last - first) < 1)
- OR (k < first)
- OR (k > last) THEN select:= FALSE
- ELSE BEGIN
- select := TRUE;
- right := last;
- left := first;
- WHILE right > left DO
- BEGIN
- IF (right - left) > cutoff THEN
- BEGIN
-
- {comment : use SELECT recursively on a sample of size "samplesize"
- to get an estimate of the (k - left + 1)th smallest element into
- list[k],biased slightly so that the (k - left + 1)th element is
- expected to lie in the smaller set after partitioning , and so
- that this partition is kept as small as possible.}
-
- listsize := right - left + 1;
- leftside := k - left + 1;
- lnlistsize := LN(listsize);
- samplesize := multiplier * EXP(2 * lnlistsize / 3);
- sd1 := 2 * leftside/listsize - 1;
- sd2 := sqrt(lnlistsize * samplesize
- * (listsize - samplesize)/listsize);
- sd := multiplier * sd2 * sd1;
- tempreal := samplesize/listsize;
- altleft := k - (leftside * tempreal) + sd;
- newleft := larger(left,ROUND(altleft));
- altright := k + ((listsize - leftside) * tempreal) + sd;
- newright := smaller(right,ROUND(altright));
- dummy := select(list,newleft,newright,k)
- END;
-
- {comment : the following code partitions list[left..right] about"estimate".}
-
- estimate := list[k];
- leftpart := left;
- rightpart := right;
- exchange(list[left],list[k]);
- IF list[right] > estimate THEN exchange(list[right],list[left]);
- WHILE leftpart < rightpart DO
- BEGIN
- exchange(list[leftpart],list[rightpart]);
- leftpart := leftpart + 1;
- rightpart := rightpart - 1;
- WHILE list[leftpart] < estimate DO leftpart := leftpart + 1;
- WHILE list[rightpart] > estimate DO rightpart := rightpart - 1;
- END;
- IF list[left] = estimate THEN exchange(list[left],list[rightpart])
- ELSE BEGIN
- rightpart := rightpart + 1;
- exchange(list[rightpart],list[right])
- END;
- {comment : now adjust left & right so they surround the subset containing
- the (k - left + 1)th smallest element. }
- IF rightpart <= K THEN left := rightpart + 1;
- IF k <= rightpart THEN right := rightpart - 1;
- END;
- END; { of : if n < 1 }
- END; { of : function select }
-