Remove duplicate elements in an array, in-place
Simple, quadratic implementation that packs elements to the left of the array
Auteurs: Jean-Christophe Filliâtre / Martin Clochard
Catégories: Array Data Structure
Outils: Why3
see also the index (by topic, by tool, by reference, by year)
Removing duplicate elements in an array
Given an array a
of size n
, removes its duplicate elements,
in-place, as follows: return r
such that a[0..r-1]
contains the same
elements as a[0..n-1]
and no duplicate
Specification
module Spec use export int.Int use export array.Array predicate appears (v: 'a) (a: array 'a) (s: int) = exists i: int. 0 <= i < s /\ a[i] = v
v
appears in a[0..s-1]
predicate nodup (a: array 'a) (s: int) = forall i: int. 0 <= i < s -> not (appears a[i] a i)
a[0..s-1]
contains no duplicate element
end
Quadratic implementation, without extra space
module RemoveDuplicateQuadratic use Spec use ref.Refint type t val predicate eq (x y: t) ensures { result <-> x = y } let rec test_appears (ghost w: ref int) (v: t) (a: array t) (s: int) : bool requires { 0 <= s <= length a } ensures { result <-> appears v a s } ensures { result -> 0 <= !w < s && a[!w] = v } variant { s } = s > 0 && if eq a[s-1] v then begin w := s - 1; true end else test_appears w v a (s-1) let remove_duplicate (a: array t): int ensures { 0 <= result <= length a } ensures { nodup a result } ensures { forall v. appears v (old a) (length a) <-> appears v a result } = let n = length a in let r = ref 0 in let ghost from = make n 0 in let ghost to_ = make n 0 in for i = 0 to n - 1 do invariant { 0 <= !r <= i } invariant { nodup a !r } invariant { forall j: int. 0 <= j < !r -> 0 <= to_[j] < i /\ a[j] = (old a)[to_[j]] } invariant { forall j: int. 0 <= j < i -> 0 <= from[j] < !r /\ (old a)[j] = a[from[j]] } invariant { forall j: int. i <= j < n -> a[j] = (old a)[j] } let ghost w = ref 0 in if not (test_appears w a[i] a !r) then begin a[!r] <- a[i]; from[i] <- !r; to_[!r] <- i; incr r end else begin from[i] <- !w; () end done; !r end
download ZIP archive