Generizität: Difference between revisions

From Alda
Jump to navigationJump to search
No edit summary
No edit summary
Line 4: Line 4:




  Algorihmen und Datenstrukturen so zu entwerfen und implementieren, dass sie möglichst<br/> vielvältig verwendbar sind.
  Algortihmen und Datenstrukturen so zu entwerfen und implementieren, dass sie möglichst<br/> vielvältig verwendbar sind.


""Gemeint sind :""
=== Gemeint sind : ===


*verschiedene Anwendungen                         
*verschiedene Anwendungen                         
Line 17: Line 17:




Beispiel : Kopieren eines Containers
'''Beispiel : ''' Kopieren eines Containers
 




==== 1.Variante: ====


  def copyArray(a):
  def copyArray(a):
Line 29: Line 29:




==== 2.Variante: ====


  class Node :
  class Node :
Line 36: Line 37:
   return k
   return k


 
==== 3.Variante: ====


  def copyArrayToList(a) :
  def copyArrayToList(a) :
     if len(a) == 0 : return None
     if len(a) == 0 : return None
    first = last = Node (a[0], None)
      first = last = Node (a[0], None)
     for k in a[1:]  :
     for k in a[1:]  :
    last.next = Node(k, None)
      last.next = Node(k, None)
    last = last.next
      last = last.next
     return first
     return first


 
==== 4.Variante: ====
  def copyListToArray(l):
  def copyListToArray(l):
     r = []
     r = []
Line 56: Line 57:




'''Beobachtung''' :
==== '''Beobachtung''' : ====


Für N Datenstrukuren ist der Implementaionsaufwand <math>O({N^2})</math>.
Für '''N Datenstrukuren''' ist der Implementaionsaufwand <math>O({N^2})</math>.
Alle Funktionen machen das gleiche mit uninteressanten Unterschied
Alle Funktionen machen das gleiche mit uninteressanten Unterschied


Line 64: Line 65:
'''Verbesserung durch Verallgemeinerung zweier Aspekte''' :
'''Verbesserung durch Verallgemeinerung zweier Aspekte''' :


*Navigation durch die Quelldaten
*Navigation durch die Quelldaten
*Aufbauen der Zieldatenstruktur
*Aufbauen der Zieldatenstruktur




'''Wie kann man so zwischen einem Array und einer Liste navigieren, so dass man den Unterschied nicht mehr merkt?'''
Wie kann man so zwischen einem Array und einer Liste navigieren, so dass man den Unterschied nicht mehr merkt?


--> Vereinheitlichung der Zieldatenstruktur :
-->''' Vereinheitlichung der Zieldatenstruktur :'''


standardisierte Funktion "append"
*standardisierte Funktion "append"
 
*Array hat sie schon
*Array hat sie schon
*Liste : definiere Klasse DoublyLinkedList
*Liste : definiere Klasse DoublyLinkedList




Line 98: Line 98:
     self.size = 0
     self.size = 0


  def__len__(self): return self.size  #len(l)
def__len__(self): return self.size  #len(l)
  def append(self, value):
def append(self, value):
     DoublyLinkedNode(value, self.sentinel)
     DoublyLinkedNode(value, self.sentinel)
   def__iter__(self):
   def__iter__(self):
Line 105: Line 105:




2. Navigation in der Quelldatenstruktur(Iteration) soll für alle Datenstrukturen funktionieren
=== 2. Navigation in der Quelldatenstruktur(<u>Iteration</u>) soll<br/> für alle Datenstrukturen funktionieren ===


*Objekt, dass auf ein Element des Containers zeigt
*Objekt, dass auf ein Element des Containers zeigt
*zum nächsten Element weiter rücken kann
*zum nächsten Element weiter rücken kann
*anzeigt, wenn das Ende der Sequenz erreicht ist  
*anzeigt, wenn das Ende der Sequenz erreicht ist  




Line 118: Line 118:


  liste = genericCopy(array, DoublyLinkedList())
  liste = genericCopy(array, DoublyLinkedList())
  Statt copyArrayToList
  <u> Statt copyArrayToList </u>


  array2 = genericCopy(array,[])
  array2 = genericCopy(array,[])
  Statt copyArray
  <u> Statt copyArray </u>
 


  array3 = genericCopy(liste,[])
  array3 = genericCopy(liste,[])
  Statt copyListToArray
  <u> Statt copyListToArray </u>


was tun " for k in quelle":
   
   
iter = quelle__iter__()
'''was tun''' " for k in quelle":
 
iter = quelle__iter__()
try :
  try :
     while True :
     while True :
     k = iter.next()
     k = iter.next()
Line 151: Line 149:
       return ListIterator(self.node) # Pythonkonvention, Kopie des Iterators erzeugen
       return ListIterator(self.node) # Pythonkonvention, Kopie des Iterators erzeugen


besser stattdessen :
'''besser stattdessen''' :


       self__class__(self.node)
       self__class__(self.node)
Line 168: Line 166:




Verallgemeinerung auf Funktionen die " etwas tun":
'''Verallgemeinerung auf Funktionen die " etwas tun":'''


  <code>def sumArray(a):
  <code>def sumArray(a):
Line 183: Line 181:
         l =l.next
         l =l.next


===3.Funktoren===


Zur Verallgemeinerung werden Funktoren eingerichtet:
'''Zur Verallgemeinerung werden Funktoren eingerichtet:'''


*Funktor muss "callable" sein :
*Funktor muss "callable" sein :
  falls f Funktor: v = f(a1, a2)
falls f Funktor: v = f(a1, a2)
callable ist z.B. eine Funktion
'''callable''' ist z.B. eine Funktion


*Objekt wo __call___ definiert
*Objekt wo __call___ definiert




  def doSomethingGeneric(functor, iterator, for k in iterator: intial):
  def doSomethingGeneric(functor, iterator, for k in iterator: intial):
  initial = functor(initial, k)
    initial = functor(initial, k)
  return initial
    return initial
 
m = doSomethingGeneric(max,list -1111111)
statt maxList
 
def add(x,y) return x+y
  s = doSomethingGeneric(add, array,o)
statt sumArray
 
  def append(x,y):
      x.append(y)
    return x
 
array4 = doSomethingGeneric(append, array[])
<u>Statt genericCopy</u>
 
*'''doSomethingGeneric'''() gibt es in vielen Programmiersprachen
 
**in Python : reduce      in C++ : accumulate
 
'''verwandte generische Funkionen'''
 
map: [x1, x2,...] --> [f(x1),f(x2),...]    alle funktionalen Sprachen ( Haskell,Lisp,...)
 
map  ist in C++ "transform"
 
 
===Offered Interface versus Required Interface===
 
 
'''Interface:'''
 
 
*standardisierte Schnittstelle zwischen Algorithmen und Datenstruktur
 
 
====Offered Interface:====
 
*Funktionalität, die eine Datenstruktur anbietet.
*Die Datensruktur sollte möglichst vielseitig sein.
 
'''z.B. PythonList:'''
 
* dynamisches Array
* stack
* deque
* linkedList
 
*standardisiert durch abstrakte Datentypen
 
 
 
====Required Interface:====
 
 
*Funktionalität, die Algorihmus benutzt
*das '''required Interface''' ist meist weniger als '''das offered Interface'''
 
z.B.:
 
'''RI''' lesender Zugriff
'''OI''' lesender Zugriff  schreibender Zugriff  Konstruktor remove...
 
 
* standardisiert über Konzepte
* ADT sind Sammlungen zusammengehörender Konzepte
* RI sollten <u>minimal</u> sein
 
 
 
====Konzepte ( + Hierarchie)====
 
*copy Constructible ( P: copy.deepcopy)
*Default Constructible
 
v1 = v.__class__()  # DoublylinkedNode
 
*EqualityComparable('=='), LessThanComparable('<')
 
ThreeWayComparable(__cmp__)
 
 
* Indexable("a[k]")
* Mapping("a[key]")
 
 
* Iteratoren : Forward(next), BidirektionalIterator(next, prev), RandomAccessIterator(nex(k))
 
* Container : Sequence
 
 
 
====Mathematische Konzepte :====
 
Addable(__add__)
Subtractable(__sub__)
Multiplyable(__mul__)
Dividable(__div__)
 
 
 
 
'''Ein offered Interface is mehr als ein required Interface.'''

Revision as of 17:04, 14 June 2008


Definition in der Informatik :

Algortihmen und Datenstrukturen so zu entwerfen und implementieren, dass sie möglichst
vielvältig verwendbar sind.

Gemeint sind :

  • verschiedene Anwendungen
  • mit vielen Kombinationsmöglichkeiten
  • als wiederverwendbare Bibliothek

--> ohne Neuimplemenation

  • Code austauschen in Bibliotheken


Beispiel : Kopieren eines Containers


1.Variante:

def copyArray(a):
  r =[]
  for k in a
  r.append(k)
return k


2.Variante:

class Node :
 def__init__(self,data,next)
    self.data = data
    self.next = next
 return k

3.Variante:

def copyArrayToList(a) :
   if len(a) == 0 : return None
      first = last = Node (a[0], None)
   for k in a[1:]  :
      last.next = Node(k, None)
      last = last.next
   return first

4.Variante:

def copyListToArray(l):
    r = []
    while l is not in None :
        r.append(l.data)
        l = l.next
    return r


Beobachtung :

Für N Datenstrukuren ist der Implementaionsaufwand <math>O({N^2})</math>. Alle Funktionen machen das gleiche mit uninteressanten Unterschied


Verbesserung durch Verallgemeinerung zweier Aspekte :

  • Navigation durch die Quelldaten
  • Aufbauen der Zieldatenstruktur


Wie kann man so zwischen einem Array und einer Liste navigieren, so dass man den Unterschied nicht mehr merkt?

--> Vereinheitlichung der Zieldatenstruktur :

  • standardisierte Funktion "append"
  • Array hat sie schon
  • Liste : definiere Klasse DoublyLinkedList


class SentinelTag : pass     # keine Daten

class DoublyLinkedNode:
 def__init__(self,data = sentinelTag(), next = None)
    if next is None:
    self.prev = self.next = self
   else :
    self.next = next
    self.prev = next.prev
    next.prev.next = self
    next.prev = self
def isSentinel(self) : return isinstance(self.data, sentinelTag)


class DoublyLinkedList :
  def__init__(self):
    self.sentinel = DoublyLinkedNode()
    self.size = 0
def__len__(self): return self.size   #len(l)
def append(self, value):
   DoublyLinkedNode(value, self.sentinel)
 def__iter__(self):
      return ListIterator(self.sentinel.next)


2. Navigation in der Quelldatenstruktur(Iteration) soll
für alle Datenstrukturen funktionieren

  • Objekt, dass auf ein Element des Containers zeigt
  • zum nächsten Element weiter rücken kann
  • anzeigt, wenn das Ende der Sequenz erreicht ist


def genericCopy(quelle, ziele) :
   for k in quelle :
    ziel.append(k)
  return ziel
liste = genericCopy(array, DoublyLinkedList())
 Statt copyArrayToList 
array2 = genericCopy(array,[])
 Statt copyArray 
array3 = genericCopy(liste,[])
 Statt copyListToArray 


was tun " for k in quelle":
iter = quelle__iter__()
 try :
    while True :
    k = iter.next()
    ...# Schleifeninhalt
    except StopIteration: pass


class ListIterator:
   def__init__(self, node):
       self.node = node
   def next(self):
       if self.node.isSentinel():
          raise StopIteraion()       #Python Konvention
       v = self.node.data
       self.node = self.node.next    # zeigt Ende der Sequenz
       return v                      # Pythonkonvention, gebe vorigen Wert zurück
   def__iter__(self):
      return ListIterator(self.node) # Pythonkonvention, Kopie des Iterators erzeugen

besser stattdessen :

     self__class__(self.node)


class ReverseListIterator(ListIterator)
  def next(self):
      if self.node isSentinel(): raise StopIteration()
      r = self.node.data
      self.node = self.node.prev
      return r


revarray = genericCopy(list, reverseIter()[]),
revlist = genericCopy(reversed(array), DoublyLinkedList())


Verallgemeinerung auf Funktionen die " etwas tun":

def sumArray(a):
        s = 0
        for k in a :
            s+=a       # s = add(s,k)
      return s 


def maxList(l):
   m = -1111111
   while l is not None [not l is Sentinel(l)]
        m = max(m, l.data)                    # max ist eingebaute Funkion in Python
        l =l.next

3.Funktoren

Zur Verallgemeinerung werden Funktoren eingerichtet:

  • Funktor muss "callable" sein :

falls f Funktor: v = f(a1, a2) callable ist z.B. eine Funktion

  • Objekt wo __call___ definiert


def doSomethingGeneric(functor, iterator, for k in iterator: intial):
   initial = functor(initial, k)
   return initial
m = doSomethingGeneric(max,list -1111111)
statt maxList
def add(x,y) return x+y
  s = doSomethingGeneric(add, array,o)
statt sumArray
def append(x,y):
     x.append(y)
   return x
array4 = doSomethingGeneric(append, array[])
Statt genericCopy
  • doSomethingGeneric() gibt es in vielen Programmiersprachen
    • in Python : reduce in C++ : accumulate

verwandte generische Funkionen

map: [x1, x2,...] --> [f(x1),f(x2),...] alle funktionalen Sprachen ( Haskell,Lisp,...)

map ist in C++ "transform"


Offered Interface versus Required Interface

Interface:


  • standardisierte Schnittstelle zwischen Algorithmen und Datenstruktur


Offered Interface:

  • Funktionalität, die eine Datenstruktur anbietet.
  • Die Datensruktur sollte möglichst vielseitig sein.

z.B. PythonList:

  • dynamisches Array
  • stack
  • deque
  • linkedList
  • standardisiert durch abstrakte Datentypen


Required Interface:

  • Funktionalität, die Algorihmus benutzt
  • das required Interface ist meist weniger als das offered Interface

z.B.:

RI lesender Zugriff OI lesender Zugriff schreibender Zugriff Konstruktor remove...


  • standardisiert über Konzepte
  • ADT sind Sammlungen zusammengehörender Konzepte
  • RI sollten minimal sein


Konzepte ( + Hierarchie)

  • copy Constructible ( P: copy.deepcopy)
  • Default Constructible

v1 = v.__class__() # DoublylinkedNode

  • EqualityComparable('=='), LessThanComparable('<')

ThreeWayComparable(__cmp__)


  • Indexable("a[k]")
  • Mapping("a[key]")


  • Iteratoren : Forward(next), BidirektionalIterator(next, prev), RandomAccessIterator(nex(k))
  • Container : Sequence


Mathematische Konzepte :

Addable(__add__)
Subtractable(__sub__)
Multiplyable(__mul__)
Dividable(__div__)



Ein offered Interface is mehr als ein required Interface.