Abstrakte Datentypen

Haskell – Seminar
Abstrakte Datentypen
Nils Bardenhagen
ms2725
Gliederung
z
z
z
z
z
z
z
Konzept
Queue
Module
Sets
Bags
Flexible Arrays
Fazit
Abstrakte Datentypen (ADT)
Definition:
„Eine Zusammenfassung von Operationen,
die auf einer Menge von Objekten
durchgeführt werden, wird als abstrakter
Datentyp bezeichnet.“
Alternative Bezeichnung: Klasse, Modul
ADT: Eigenschaften
z
z
z
z
z
Universalität: Verwendung in verschiedenen
Programmen
Präzise Beschreibung: Interface muss eindeutig
und vollständig sein
Kapselung: Der Anwender soll wissen was der ADT
tut, aber nicht wie
Schutz: Der Anwender kann nicht in die interne
Datenstruktur eingreifen.
Modularität: Einfacher Austausch, Fehlersuche,
Verbesserung
=> Objektorientierung
ADT: Beispiele
z
z
z
z
z
Float
Tree
List
Queue
Stack
Queue
Operationen:
empty
:: Queue a
join
:: a ö Queue a ö Queue a
front
:: Queue a ö a
back
:: Queue a ö Queue a
isEmpty
:: Queue a ö Bool
z
Queue: Axiome
isEmpty empty
isEmpty (join x xq)
front (join x empty)
front (join x (join y xq))
back (join x empty)
back (join x (join y xq))
= True
= False
=x
= front (join y xq)
= empty
= join x (back (join y xq))
isEmpty (join x bottom) = isEmpty ┴ = ┴
Queue: Implementierung 1
joinc
joinc x xs
:: a ö [a] ö [a]
= xs ++ [x]
emptyc
emptyc
:: [a]
= []
isEmptyc
isEmptyc xs
:: [a] ö Bool
= null xs
frontc
frontc (x:xs)
:: [a] ö a
=x
backc
backc (x:xs)
:: [a] ö [a]
= xs
abstr
:: [a] ö Queue a
abstr
= foldr join empty . Reverse
reprn
:: Queue a ö [a]
reprn empty
= []
reprn (join x xq)
= reprn xq ++ [x]
Queue: Implementierung 2
valid
:: ([a],[a]) ö Bool
valid (xs,ys)
= not (null xs) v null ys
abstr
abstr
:: ([a],[a]) ö Queue a
(xs,ys) = (foldr join empty . reverse) (xs ++ reverse ys)
Queue: Implementierung 2
emptyc
= ([],[])
isEmptyc (xs,ys) = null xs
joinc x (xs,ys)
= mkValid (ys, x:zs)
frontc (x:xs, ys)
=x
backc (x:xs,ys)
= mkValid (xs,ys)
mkValid
:: ([a],[a]) ö ([a],[a])
mkValid (xs, ys) = if null xs then (reverse ys,[]) else (xs,ys)
Module
module Queue (Queue, empty, isEmpty, join, front, back)
where newtype Queue a = MkQ ([a],[a])
isEmpty
isEmpty (MkQ (xs:ys))
:: Queue a ö Bool
= null xs
empty
empty
:: Queue a
= MkQ([],[])
join
join x (MkQ (ys,xs))
:: a ö Queue a ö Queue a
= mkValid(ys,x:xs)
front
front (MkQ (x:xs, ys))
:: Queue a ö a
=x
back
back (MkQ(x:xs, ys))
:: [a] ö [a]
= mkValid(xs,ys)
mkValid
mkValid (xs, ys)
:: ([a],[a]) ö Queue a
= if null xs then MkQ (reverse ys, []) else mkQ (xs, ys)
Module (2)
import Queue
toQ
:: [a] ö Queue a
toQ
= foldr join empty . Reverse
fromQ
:: Queue a ö [a]
fromQ q = if isEmpty q then [] front q:fromQ (back q)
? join 1 (join 2 empty)
([2],[1])
? join 1 (join 2 empty) == join 2 (join 1 empty)
False
Sets
z
Ausgewählte Operationen:
empty
isEmpty
member
insert
delete
:: Set a
:: Set a ö Bool
:: Set a ö a ö Bool
:: a ö Set a ö Set a
:: a ö Set a ö Set a
union
meet
minus
:: Set a ö Set a ö Set a
:: Set a ö Set a ö Set a
:: Set a ö Set a ö Set a
Sets: Axiome
insert x (insert x xs)
insert x (insert y xs)
= insert x xs
= insert y (insert x xs)
isEmpty empty
isEmpty (insert x xs)
= True
= False
member empty y
= False
member (insert x xs) y = (x=y) v member xs y
delete x empty
delete x (insert y xs)
= empty
= if x = y then delete x xs else insert y (delete x xs)
union xs empty
union xs (insert y ys)
= xs
= insert y (union xs ys)
meet xs empty
meet xs (insert y ys)
= empty
= if member xs y then insert y (meet xs ys) else meet xs ys
minus xs empty
= xs
minus xs (insert y ys) = minus (delete y xs) ys
Sets: Implementierung als Liste
abstr
abstr
:: [a] ö Set a
= foldr insert empty
valid xs
valid xs
= True
= nonduplicated xs
member xs x
insert x xs
delete x xs
union xs ys
minus xs ys
= some (==x)
= x:xs
= filter (≠x) xs
= xs ++ ys
= filter (not . member ys) xs
some
some p
:: (a ö Bool) ö [a] ö Bool
= or . map p
Sets: Implementierung als Liste
insert x xs
union xs ys
= x:filter (≠ x) xs
= xs ++ filter (not . Member xs) ys
member xs x
= if null ys then False else (x == head ys)
where ys = dropWhile (<x) xs
union [] ys
= ys
union (x:xs) [] = x:xs
union (x:xs)(y:ys)
| (x < y)
= x:union xs (y:ys)
| (x==y)
= x:union xs ys
| (x > y)
= y:union (x:xs) ys
Sets: Implementierung als Baum
Data Stree a = Null | Fork (Stree a) a (Stree a)
empty
empty
:: Set a
= Null
isEmpty
isEmpty Null
isEmpty (Fork xt y yt)
:: Set a ö Bool
= True
= False
member
member Null x
member (Fork xt y yt) x
| (x < y)
| (x == y)
| (x > y)
:: (Ord a) => Stree a ö a ö Bool
= False
insert
insert x Null
insert x (Fork xt y zt)
| (x < y)
| (x == y)
| (x > y)
= member xt x
= True
= member zt x
:: (Ord a) => a ö Stree a ö Stree a
= Fork Null x Null
= Fork (insert x xt) y zt
= Fork xt y zt
= Fork xt y (insert x zt)
Sets: Implementierung als Baum
delete
::(Ord a) => a ö Stree a ö Stree a
delete x Null
= Null
delete x (Fork xt y zt)
| (x < y)
= Fork (delete x xt) y zt
| (x == y)
= join xt zt
| (x > y)
= Fork xt y (delete x zt)
join
join xt yt
:: Stree a ö Stree a ö Stree a
= if isEmpty yt then xt else Fork xt y zt
where (y,zt) = splitTree xt
splitTree
splitTree (Fork xt y zt)
:: Stree a ö (a, Stree a)
= if isEmpty xt then (y,zt) else (u, Fork vt y zt)
where (u,vt) = splitTree xt
Bags / Multisets
z
{[1,2,2,3]} ={[3,2,1,2]} aber {[1,2,2]} != {[1,2]}
z
Operationen
mkBag :: [a] ö Bag a
isEmpty :: Bag a ö Bool
union
:: Bag a ö Bag a ö Bag a
minBag :: Bag a ö a
delMin :: Bag a ö Bag a
Bags: Axiome
isEmpty (mkBag xs)
union (mkBag xs) (mkBag ys)
minBag (mkBag xs)
delMin (mkBag xs)
= null xs
= mkBag (xs++ys)
= minlist xs
= mkBag (deleteMin xs)
Bags: Implementierung (Heap)
data Htree a = Null | Fork Int a (Htree a) (Htree a)
fork
fork x yt zt
:: a ö Htree a ö Htree a
= if m < n then Fork p x zt yt else Fork p x yt zt
where m = size yt
n = size zt
p=m+n+1
size
size Null
size (Fork n x yt zt)
:: Htree a ö Int
=0
=n
isEmpty
:: Htree a ö Bool
isEmpty Null
= True
isEmpty (Fork n x yt zt) = False
minBag
:: Htree a ö a
minBag (Fork n x yt zt) = x
delMin
:: Htree a ö Htree a
delMin (Fork n x yt zt) = union yt zt
Bags: Implementierung (Heap)
union
union Null yt
union (Fork m u vt wt) Null
:: Htree a ö Htree a ö Htree a
= yt
= Fork m u vt wt
union (Fork m u vt wt) (Fork n x yt zt)
| (u § x)
= fork u vt (union wt (Fork n x yt zt))
| (x < u)
= fork x yt (union (Fork m u vt wt) zt)
mkBag
mkBag xs
:: [a] ö Htree a
= fst (mkTwo (length xs) xs)
mkTwo
mkTwo n xs
| (n == 0)
| (n == 1)
| otherwise
where (xt, ys)
(yt,zs)
m
:: Int ö [a] ö (Htree a, [a])
= (Null, xs)
= (fork (head xs) Null Null, tail xs)
= (union xt yt, zs)
= mkTwo m xs
= mkTwo (n-m) ys
= n div 2
Flexible Arrays
z
Operationen
empty
isEmpty
access
update
hiext
hirem
loext
lorem
:: Flex a
:: Flex a ö Bool
:: Flex a ö Int ö a
:: Flex a ö Int ö a ö Flex a
:: a ö Flex a ö Flex a
:: Flex a ö Flex a
:: a ö Flex a ö Flex a
:: Flex a ö Flex a
Flexible arrays: Axiome
hiext x . loext y
hirem empty
hirem (hiext x xf)
hirem (loext x empty)
hirem (loext x (hiext y xf))
hirem (loext x (loext y xf))
access ampty k
access (loext x xf) 0
access (hiext x xf) (k + 1)
access (hiext x xf) k
| (k < n)
= access xf k
| (k == n)
=x
| (k > n)
= error
where n = length xf
= loext y hiext x
= error
= xf
= empty
= loext x xf
= loext x (hirem(loext y xf))
= error „out of range“
=x
= access xf k
Flexible Arrays: Implementierung
data Flex a = Null | Leaf a | Fork Int (Flex a) (Flex a)
…
access
access (Leaf x) 0
access (Fork n xt yt) k
size
size Null
size (Leaf x)
size (Fork n xt yt)
…
:: Flex a ö Int a
=x
= if k < m then access xt k
else access yt (k – m)
where m = size xt
:: Flex a ö Int
=0
=1
=n
Fazit