array_ext.sa
Generated by gen_html_sa_files from ICSI. Contact gomes@icsi.berkeley.edu for details
class ARRAY_EXT{ELT}
class ARRAY_EXT{ELT} is
delete_at(i:CARD, ar:ARRAY{ELT}):ARRAY{ELT} is
--a::=ar.copy;
--if i<a.size-1 then a.copy(i,a.size-1-i, i+1,a); end;
--a:=a.resize(a.size-1);
--return a;
a:ARRAY{ELT}:=#(ar.size-1);
if 0<i then a.copy(0,i,ar); end;
if i<ar.size-1 then a.copy(i,ar.size-i-1,i+1,ar); end;
return a;
end;
insert_at(i:CARD, ar:ARRAY{ELT}, e:ELT):ARRAY{ELT}
pre (i<=ar.size) is
if i=0 then res:ARRAY{ELT}:=#(ar.size+1);
res[0]:=e; res.copy(1,ar); return res;
elsif i=ar.size then return ar.append(|e|);
else
res:ARRAY{ELT}:=#(ar.size+1);
res.copy(0,i,ar); res[i]:=e; res.copy(i+1,ar.size-i,i,ar);
return res;
end;
end;
insert_at(i:CARD,ar0:ARRAY{ELT},ar1:ARRAY{ELT}):ARRAY{ELT}
pre (i<=ar0.size) is
if i=0 then return ar1.append(ar0);
elsif i=ar0.size then return ar0.append(ar1);
else res:ARRAY{ELT}:=#(ar0.size+ar1.size);
res.copy(0,i,ar0);
res.copy(i,ar1);
res.copy(i+ar1.size,ar0.size-i,i,ar0);
return res;
end;
end;
end;
class ARRAY_SORT{ELT}
class ARRAY_SORT{ELT} is
check_range(ar:ARRAY{ELT}, l,u:CARD):BOOL is
if void(ar) then return false; end;
return (l<=u)and(u<ar.size)
end ;
swap(inout ar:ARRAY{ELT}, i1,i2:CARD) is
t:ELT:=ar[i1]; ar[i1]:=ar[i2]; ar[i2]:=t;
end;
is_sorted(ar:ARRAY{ELT}, l,u:CARD, lt:ROUT{ELT,ELT}:BOOL):BOOL is
-- true if and only if "ar" is sorted as determined by "lt".
if ~check_range(ar,l,u) then return false; end;
loop
i:CARD:=(l+1).upto!(u);
if lt.call(ar[i],ar[i-1]) then return false; end;
end;
return true;
end;
is_sorted(ar:ARRAY{ELT}, lt:ROUT{ELT,ELT}:BOOL):BOOL is
if ar.size=0 then return true; end;
return is_sorted(ar,0,ar.size-1,lt);
end;
count(ar:ARRAY{ELT},lt:ROUT{ELT,ELT}:BOOL):CARD is
-- count different (partial) ordered element in the sense of "lt".
if ar.size<=1 then return ar.size; end;
c::=1; i::=1;
loop until!(i>=ar.size);
if lt.call(ar[i],ar[i-1]) /= lt.call(ar[i-1],ar[i]) then c:=c+1; end;
i:=i+1;
end;
return c;
end;
search(ar:ARRAY{ELT}, e:ELT, lt:ROUT{ELT,ELT}:BOOL):CARD is
-- assume "ar" is sorted by increasing order "<"(with lt).
-- binary search
i1:CARD:=ar.size; if i1=0 then return i1; end;
i0:CARD:=0;
loop until!(i0+1=i1); -- binary search
i2::=(i0+i1)/2; if lt.call(e,ar[i2]) then i1:=i2; else i0:=i2; end;
end;
if lt.call(e,ar[i0]) then i1:=i0; end;
return i1;
end;
sorted_insert(ar:ARRAY{ELT}, e:ELT):ARRAY{ELT} is
-- assume ar is sorted by increasing order "<".
lt:ROUT{ELT,ELT}:BOOL:=bind(_.is_lt(_)); return sorted_insert(ar,e,lt);
end;
sorted_insert(ar:ARRAY{ELT}, e:ELT, lt:ROUT{ELT,ELT}:BOOL):ARRAY{ELT} is
-- assume ar is sorted by increasing order "<"(with lt).
if ar.size=0 then return |e|; end;
i:CARD:=search(ar,e,lt);
res:ARRAY{ELT}:=ARRAY_EXT{ELT}::insert_at(i,ar,e);
return res;
end;
merge(ar1,ar2:ARRAY{ELT}, lt:ROUT{ELT,ELT}:BOOL):ARRAY{ELT} is
-- merge sort: Assume that ar1, ar2 are sorted.
res:ARRAY{ELT}:=#(ar1.size+ar2.size);
if ar1.size=0 then
loop
res.set!(ar2.elt!);
end;
return res;
end;
if ar2.size=0 then
loop
res.set!(ar1.elt!);
end;
return res;
end;
i1::=0; i2::=0; i3::=0; e:ELT;
loop
until!(i3>=res.size);
if i1>=ar1.size then e:=ar2[i2]; i2:=i2+1;
elsif i2>=ar2.size then e:=ar1[i1]; i1:=i1+1;
elsif lt.call(ar2[i2],ar1[i1]) then e:=ar2[i2]; i2:=i2+1;
else e:=ar1[i1]; i1:=i1+1;
end;
res[i3]:=e; i3:=i3+1;
end;
return res;
end;
lt_rev(a,b:ELT,lt:ROUT{ELT,ELT}:BOOL):BOOL is
-- ">" with respect to lt(<).
return lt.call(b,a);
end;
sorted_rev_insert(ar:ARRAY{ELT}, e:ELT):ARRAY{ELT} is
-- assume ar is sorted by decreasing order ">".
lt:ROUT{ELT,ELT}:BOOL:=bind(_.is_lt(_)); ltr:ROUT{ELT,ELT}:BOOL:=bind(lt_rev(_,_,lt));
return sorted_insert(ar,e,ltr);
end;
sorted_rev_insert(ar:ARRAY{ELT}, e:ELT, lt:ROUT{ELT,ELT}:BOOL):ARRAY{ELT} is
ltr:ROUT{ELT,ELT}:BOOL:=bind(lt_rev(_,_,lt)); return sorted_insert(ar,e,ltr);
end;
insertion_sort(inout ar:ARRAY{ELT}) post ar.is_sorted is
-- stable sort.
if ar.size>1 then insertion_sort_range(inout ar,0,ar.size-1); end;
end;
insertion_sort(inout ar:ARRAY{ELT},lt:ROUT{ELT,ELT}:BOOL) is
-- stable sort.
if ar.size>1 then insertion_sort_range(inout ar,0,ar.size-1,lt); end;
end;
insertion_sort_range(inout ar:ARRAY{ELT},l,u:CARD) is
lt:ROUT{ELT,ELT}:BOOL:=bind(_.is_lt(_)); insertion_sort_range(inout ar,l,u, lt);
end;
insertion_sort_range(inout ar:ARRAY{ELT},l,u:CARD, lt:ROUT{ELT,ELT}:BOOL) is
-- sort by increasing order "<" with respect to `lt'.
i0,i1:CARD;
loop i::=(l+1).upto!(u);
e:ELT:=ar[i]; i1:=i-1;
if lt.call(e,ar[i1]) then ; -- is_lt
if lt.call(e,ar[l]) then i1:=l; -- is_lt
else
i0:=l;
loop until!(i0+1=i1);
i2::=(i0+i1)/2; -- binary search
if lt.call(e,ar[i2]) then i1:=i2; else i0:=i2; end; -- is_lt
end;
end;
loop j::=i.downto!(i1+1); ar[j]:=ar[j-1]; end;
ar[i1]:=e; --insertion
end;
end;
end;
private const quicksort_limit:CARD:=20;
-- When to stop the quicksort recursion and switch to insertion sort.
quicksort_range(inout ar:ARRAY{ELT},l,u:CARD) is
lt:ROUT{ELT,ELT}:BOOL:=bind(_.is_lt(_)); quicksort_range(inout ar,l,u,lt);
end;
quicksort_range(inout ar:ARRAY{ELT}, l, u:CARD, lt:ROUT{ELT,ELT}:BOOL)
pre check_range(ar,l,u)
is
-- Use quicksort to sort the elements of self from `l' to `u'
if u>l+quicksort_limit then
r::=RANDOM::card(l+1,u-1); swap(inout ar, l,r); t:ELT:=ar[l]; m::=l;
loop i::=(l+1).upto!(u);
if lt.call(ar[i],t) then m:=m+1; swap(inout ar,m,i); end;
end;
swap(inout ar,l,m);
if l+1 < m then quicksort_range(inout ar,l,m-1,lt); end;
if m+1 < u then quicksort_range(inout ar,m+1,u,lt); end;
else
insertion_sort_range(inout ar, l,u,lt);
end;
end;
quick_sort(inout ar:ARRAY{ELT}, lt:ROUT{ELT,ELT}:BOOL) post ar.is_sorted_by(lt) is
-- Use quicksort to permute the elements of self so that
-- it is sorted by increasing order "<" with respect to `lt'. Self may be void.
if ar.size>1 then quicksort_range(inout ar, 0,ar.size-1,lt); end;
end;
quick_sort(inout ar:ARRAY{ELT}) is
-- Use quicksort to permute the elements of self so that
-- it is sorted by increasing order "<" with respect to `elt_lt'. Self may be void.
quick_sort(inout ar,bind(_.is_lt(_)));
end;
end;
class TEST_ARRAY_EXT
class TEST_ARRAY_EXT is
check_time1(n:INT, ar0:ARRAY{INT}) is
timer:TIMER:=#;
f1,f2,f3,f4:ELAPSED;
ite:CARD:=4;
loop ite.times!;
ar1::=ar0.copy; ar2::=ar0.copy; ar3::=ar0.copy; ar4::=ar0.copy;
timer.clear; ar1.sort; f1:=f1+timer.elapsed;
timer.clear; ARRAY_SORT{INT}::quick_sort(inout ar2); f2:=f2+timer.elapsed;
--t1.mark; ar3.stable_sort; f3:=f3+t1.elapsed;
--t1.mark; ARRAY_SORT{INT}::insertion_sort(inout ar4); f4:=f4+t1.elapsed;
assert ar1.is_sorted;
assert ar2.is_sorted;
--assert ar3.is_sorted; assert ar4.is_sorted;
end;
f1:=f1/ite; f2:=f2/ite;
--f3:=f3/#FLTD(ite); f4:=f4/#FLTD(ite);
#OUT+"sort="+f1.full_str+", quick/ext="+f2.full_str
-- +", stable_sort="+f3.str +", insertion/ext="+f4.str
+"\n";
end;
check_time(n:INT) is
#OUT+"n="+n.str+"\n"; #OUT.flush;
ar0:ARRAY{INT};
rnd::=#RANDOM;
ar0:=#(n.card);
-- randum
loop i::=ar0.ind!; ar0[i]:=rnd.int(0.int,n); end;
check_time1(n,ar0);
-- iterated sorted
loop i::=0.upto!(ar0.size/2); j::=1.up!; ar0[i]:=j.int; end;
loop i::=(ar0.size/2+1).upto!(ar0.size-1);j::=1.up!; ar0[i]:=j.int; end;
check_time1(n,ar0);
-- randum with many duplication
loop i::=ar0.ind!; ar0[i]:=rnd.int(0.int,n.sqrt); end;
check_time1(n,ar0);
-- same
--loop i::=ar0.ind!; ar0[i]:=1; end;
--check_time1(n,ar0);
end;
check_sorting_speed is
n:INT;
--n:=10; check_time(n);
--n:=20; check_time(n);
--n:=100; check_time(n);
n:=1000; check_time(n);
n:=10000; check_time(n);
--n:=100000; check_time(n);
--n:=1000000; check_time(n);
end;
check_sorted_insert is
rnd::=#RANDOM;
n::=10;
ar:ARRAY{INT};
loop 100.times!;
ar:=#;
loop i::=1.upto!(n);
ar:=ARRAY_SORT{INT}::sorted_insert(ar,rnd.int(0.int,n.int));
--#OUT+ar.str+"\n";
end;
assert ar.is_sorted;
end;
loop 100.times!;
ar:=#;
loop i::=1.upto!(n);
ar:=ARRAY_SORT{INT}::sorted_rev_insert(ar,rnd.int(0.int,n.int));
--#OUT+ar.str+"\n";
end;
ar:=ar.reverse; assert ar.is_sorted;
end;
end;
main is
check_sorting_speed;
check_sorted_insert;
end;
end;