Container: Difference between revisions

From Alda
Jump to navigationJump to search
Line 14: Line 14:
==mögliche Operationen==
==mögliche Operationen==


Welche Operationen hätte man denn gerne bei einer solchen Container-Datenstruktur? <br/>
Welche Operationen hätte man denn gerne bei einer solchen Container-Datenstruktur?
Was benötigt ein Algorithmus? Wie sollten die Daten organisiert sein, damit Algorithmen effizient damit arbeiten können? <br/>
Was benötigen Algorithmen häufig? Wie sollten die Daten organisiert sein, damit Algorithmen effizient damit arbeiten können? <br/>
Eine solche Anforderungsanalyse ist sehr aufwendig und kann sich über Jahre erstrecken, weil Erfahrungen gesammelt werden müssen, welche Anforderungen an Datenstrukturen in vielen Algorithmen immer wieder auftreten. <br/>
Eine solche Anforderungsanalyse ist sehr aufwendig und kann sich über Jahre erstrecken, weil Erfahrungen gesammelt werden müssen, welche Anforderungen an Datenstrukturen in vielen Algorithmen immer wieder auftreten. <br/>
Wir listen im folgenden nur das Resultat, also die wichtigsten Operationen von Container-Datenstrukturen auf.
Wir listen im folgenden nur das Resultat, also die wichtigsten Operationen von Container-Datenstrukturen auf.
Line 21: Line 21:
Sei c eine Container-Datenstruktur und v ein darin gespeicherter Wert:
Sei c eine Container-Datenstruktur und v ein darin gespeicherter Wert:


c.size() ist immer unterstützt
'''Lesender Zugriff'''
<br/>'''0.''' <tt>c.size()</tt> -- gibt die Anzahl der Elemente im Container an
<br/>'''1a.''' <tt>v = c.get(i)</tt> -- das i-te Element im Container lesen
<br/>'''1b.''' Variante: <tt>v = c.get(pos)</tt> -- das Element an Position <tt>pos</tt> lesen (<tt>pos</tt> ist ein geeignetes Hilfsobjekt, das in Abhängigkeit von der Art der Datenstruktur eine Position im Container referenziert. Im Falle <tt>v = c.get(i)</tt> ist <tt>pos</tt> eine natürliche Zahl, aber es gibt auch andere Möglichkeiten, die Position zu kodieren.)
<br/>'''1c.''' Variante: <tt>v = c.get(key)</tt> -- das Element mit dem Schlüssel <tt>key</tt> lesen (Beachte den Unterschied zu 1b: In 1b markiert <tt>pos</tt> eine Position im Container, hier in 1c bezieht sich <tt>key</tt> auf eine Eigenschaft der Datenelemente, die von der Position im Container unabhängig ist.)
<br/>'''2a.''' <tt>v = c.first()</tt> -- erstes Element lesen (äquivalent zu <tt>v = c.get(0)</tt>)
<br/>'''2b.''' <tt>v = c.last()</tt> -- letztes Element lesen (äquivalent zu <tt>v = c.get(v.size()-1)</tt>)
<br/>'''3a.''' <tt>v = c.smallest()</tt> -- das kleinste Element lesen (dies bezieht sich auf eine Eigenschaft der Datenelemente, im Unterschied zu 2a, wo es um die Position im Container geht.)
<br/>'''3b.''' <tt>v = c.largest()</tt> -- das größte Element lesen (dies bezieht sich auf eine Eigenschaft der Datenelemente bzw. Schlüssel, im Unterschied zu 2b, wo es um die Position im Container geht.)


    1 a) v = c.get(i) / b)v = c.get(pos)
'''Schreibender Zugriff'''
    i-tes Objekt suchen
<br/>'''4a.''' <tt>v.set(i, value)</tt> -- i-tes Element überschreiben, <tt>c.size()</tt> bleibt unverändert
 
<br/>'''4b.''' <tt>v.set(pos, value)</tt> -- Element an der Stelle <tt>pos</tt> überschreiben, <tt>c.size()</tt> bleibt unverändert
    2 v.set(i, value)
<br/>'''4c.''' <tt>v.set(key, value)</tt> -- Element mit dem Schlüssel <tt>key</tt> überschreiben, <tt>c.size()</tt> bleibt unverändert
    i-tes Objekt überschreiben
<br/>'''5.''' <tt>c.append(v)</tt> -- Objekt am Ende anhängen, <tt>c.size()</tt> erhöht sich um Eins
 
<br/>'''6.''' <tt>c.prepend(v)</tt> -- Objekt am Anfang einfügen, <tt>c.size()</tt> erhöht sich um Eins
    3 a) v = c.first()/last()
<br/>'''7a.''' <tt>c.insert(i, v)</tt> -- Objekt als i-tes in den Container einfügen (Werte ab <tt>i</tt> werden eine Position nach hinten verschoben)
    erstes bzw. letztes Objekt erhalten
<br/>'''7b.''' <tt>c.insert(pos, v)</tt> -- Objekt an Position <tt>pos</tt> in den Container einfügen (Werte ab <tt>pos</tt> werden eine Position nach hinten verschoben)
 
<br/>'''7c.''' <tt>c.insert(key, v)</tt> -- Objekt unter dem Schlüssel <tt>key</tt> in den Container einfügen (Wenn der Schlüssel schon vergeben war, kann man einen Fehler signalisieren, oder man überschreibt das bisher mit diesem Schlüssel verknüpfte Objekt.)
    4 v = c.largest()/smallest()
<br/>'''8a.''' <tt>c.remove(i)</tt> -- i-tes Element aus dem Container löchen (Werte ab <tt>pos</tt> werden eine Position nach vorn verschoben)
    Das größte bzw. kleinste Objekt erhalten
<br/>'''8b.''' <tt>c.insert(pos)</tt> -- Objekt an Position <tt>pos</tt> aus dem Container löchen  (Werte ab <tt>pos</tt> werden eine Position nach hinten verschoben)
 
<br/>'''8c.''' <tt>c.insert(key)</tt> -- Objekt unter dem Schlüssel <tt>key</tt> aus dem Container löchen  (Wenn der Schlüssel nicht vergeben war, kann man einen Fehler signalisieren, oder dies einfach ignorieren.)
    5 v = c.get(key)
<br/>'''9a.''' c.removeFirst() -- das erste Element aus dem Container entfernen (äquivalent zu <tt>c.remove(0)</tt>)
    Verallgemeinerung von 1 für beliebige Schlüssel (nicht nur integer)
<br/>'''9b.''' c.removeLast() -- das letzte Element aus dem Container entfernen (äquivalent zu <tt>c.remove(c.size()-1)</tt>)
    den Key(Schlüssel) einer Value(Wert) erhalten.
<br/>'''10a.''' c.removeSmallest() -- das kleinste Element aus dem Container entfernen (dies bezieht sich auf eine Eigenschaft der Datenelemente bzw. Schlüssel, im Unterschied zu 9a, wo es um die Position im Container geht.)
 
<br/>'''10b.''' c.removeLargest() -- das größte Element aus dem Container entfernen (dies bezieht sich auf eine Eigenschaft der Datenelemente bzw. Schlüssel, im Unterschied zu 9b, wo es um die Position im Container geht.)
    6 c.append(v)
    Objekt am Ende anhängen (mit c.set() verwandt)
 
    7 c.prepend(v)
    Objekt vorne einfügen
 
    8 c.insert(i, v)
    Objekt an beliebiger Position einfügen (Werte werden ab i verschoben)
 
    9 c.insert(key, v)
    Ein Schlüssel-Wert Paar einfügen
 
    10 c.removeFirst()/Last()
    Das erste bzw. letzte Objekt entfernen
 
    11 c.remove(i)
    Das Objekt an Position i entfernen
 
    12 c.remove(key)
    Einen Schlüssel entfernen
 
    13 c.removeSmallest()/Largest()
    das kleinste bzw. größte Objekt entfernen


==Facts==
==Facts==

Revision as of 15:33, 8 May 2008

der Begriff Container stammt ursprünglich aus der Schiffahrt, Container kann mehrere Bedeutungen annehmen.

in der Schiffahrt:
Behälter der Güter lagern und transportieren kann.

in der Datenverarbeitung:
- Computertechnik: eine Dateiformat die verschiedenartige Datenformate enthalten kann. (siehe Containerformat)
- Server: Teil einer Server-Software und Enterprise Java Beans (EJB) verwaltet. Der Container speichert die Daten und prüft die Verfügbarkeit für jeden autorisierten Client. (siehe EJB-Container)
- in Programmiersprachen: Einige Programmiersprachen wie Java oder C++ verfügen über Containerklassen. In C++ sind sie in der Stardbibliothek C++Standardbibliothek
- in der Informatik (und bei uns in der Vorlesung): ein abstraktes Objekt, das Elemente des gleichen Typs speichert (Array, Liste, Dictionary,...) siehe auch Datenstrukturen


mögliche Operationen

Welche Operationen hätte man denn gerne bei einer solchen Container-Datenstruktur? Was benötigen Algorithmen häufig? Wie sollten die Daten organisiert sein, damit Algorithmen effizient damit arbeiten können?
Eine solche Anforderungsanalyse ist sehr aufwendig und kann sich über Jahre erstrecken, weil Erfahrungen gesammelt werden müssen, welche Anforderungen an Datenstrukturen in vielen Algorithmen immer wieder auftreten.
Wir listen im folgenden nur das Resultat, also die wichtigsten Operationen von Container-Datenstrukturen auf.

Sei c eine Container-Datenstruktur und v ein darin gespeicherter Wert:

Lesender Zugriff
0. c.size() -- gibt die Anzahl der Elemente im Container an
1a. v = c.get(i) -- das i-te Element im Container lesen
1b. Variante: v = c.get(pos) -- das Element an Position pos lesen (pos ist ein geeignetes Hilfsobjekt, das in Abhängigkeit von der Art der Datenstruktur eine Position im Container referenziert. Im Falle v = c.get(i) ist pos eine natürliche Zahl, aber es gibt auch andere Möglichkeiten, die Position zu kodieren.)
1c. Variante: v = c.get(key) -- das Element mit dem Schlüssel key lesen (Beachte den Unterschied zu 1b: In 1b markiert pos eine Position im Container, hier in 1c bezieht sich key auf eine Eigenschaft der Datenelemente, die von der Position im Container unabhängig ist.)
2a. v = c.first() -- erstes Element lesen (äquivalent zu v = c.get(0))
2b. v = c.last() -- letztes Element lesen (äquivalent zu v = c.get(v.size()-1))
3a. v = c.smallest() -- das kleinste Element lesen (dies bezieht sich auf eine Eigenschaft der Datenelemente, im Unterschied zu 2a, wo es um die Position im Container geht.)
3b. v = c.largest() -- das größte Element lesen (dies bezieht sich auf eine Eigenschaft der Datenelemente bzw. Schlüssel, im Unterschied zu 2b, wo es um die Position im Container geht.)

Schreibender Zugriff
4a. v.set(i, value) -- i-tes Element überschreiben, c.size() bleibt unverändert
4b. v.set(pos, value) -- Element an der Stelle pos überschreiben, c.size() bleibt unverändert
4c. v.set(key, value) -- Element mit dem Schlüssel key überschreiben, c.size() bleibt unverändert
5. c.append(v) -- Objekt am Ende anhängen, c.size() erhöht sich um Eins
6. c.prepend(v) -- Objekt am Anfang einfügen, c.size() erhöht sich um Eins
7a. c.insert(i, v) -- Objekt als i-tes in den Container einfügen (Werte ab i werden eine Position nach hinten verschoben)
7b. c.insert(pos, v) -- Objekt an Position pos in den Container einfügen (Werte ab pos werden eine Position nach hinten verschoben)
7c. c.insert(key, v) -- Objekt unter dem Schlüssel key in den Container einfügen (Wenn der Schlüssel schon vergeben war, kann man einen Fehler signalisieren, oder man überschreibt das bisher mit diesem Schlüssel verknüpfte Objekt.)
8a. c.remove(i) -- i-tes Element aus dem Container löchen (Werte ab pos werden eine Position nach vorn verschoben)
8b. c.insert(pos) -- Objekt an Position pos aus dem Container löchen (Werte ab pos werden eine Position nach hinten verschoben)
8c. c.insert(key) -- Objekt unter dem Schlüssel key aus dem Container löchen (Wenn der Schlüssel nicht vergeben war, kann man einen Fehler signalisieren, oder dies einfach ignorieren.)
9a. c.removeFirst() -- das erste Element aus dem Container entfernen (äquivalent zu c.remove(0))
9b. c.removeLast() -- das letzte Element aus dem Container entfernen (äquivalent zu c.remove(c.size()-1))
10a. c.removeSmallest() -- das kleinste Element aus dem Container entfernen (dies bezieht sich auf eine Eigenschaft der Datenelemente bzw. Schlüssel, im Unterschied zu 9a, wo es um die Position im Container geht.)
10b. c.removeLargest() -- das größte Element aus dem Container entfernen (dies bezieht sich auf eine Eigenschaft der Datenelemente bzw. Schlüssel, im Unterschied zu 9b, wo es um die Position im Container geht.)

Facts

  • Jede dieser Operationen kann sehr effizient implementiert werden.
  • Keine Datenstruktur ist bekannt, die alle diese Operationen effizient implementiert.

Beispiele

Je nachdem welche Operation effizient sein soll, wird eine andere Container Datenstruktur ausgewählt


  • Array
    Das Array ist die einfachste Datenstruktur, in einem Array können Variablen gespeichert werden. Die Größe ist nicht veränderbar
    das Array unterstützt die ersten 3 Operationen
  • Dynamisches Array:
    die Größe ist veränderbar also die unterstützen Operationen sind dieselben wie die des Arrays, zusätzlich unterstützt das dynamische Array c.append & c.removeLast
  • Dictionary
    Ein Dictionary besteht aus einem Key(Schlüssel) und einem Value(Wert). Jeder Schlüssel bekommt einen Wert zugewiesen.
    Es unterstützt dieselben Operationen wie das Array ausserdem noch c.get(key), c.insert(key,value), c.remove(key)
  • Verkettete Liste
    Im Gegensatz zum Array müssen die Speicherzellen nicht nacheinenander im Speicher abgelegt sein.
    Sie unterstützt die Operationen: c.first(), c.insert(pos, value), c.remove(pos), c.get(pos)
  • Doppelt verkettete Liste:
    Im Gegensatz zur verketteten Liste, hat jedes Element einen Zeiger auf das vorherige Objekt sowie auf das darauffolgende Objekt
    Sie unterstützt dieselben Operationen wie die Liste + ...
  • Stack(Stapelspeicher)
    speichert/stapelt die Objekte mit push in einen Speicher wiederrum mit pop kann das oberste Element herausgeholt werden: LIFO (Last In First Out)
    Operationen: c.last(), c.append(), c.removeLast()
  • Queue
    Eine Queue ist wie eine Warteschlange an der Kasse im Supermarkt, bedient wird derjenige der als erster an die Kasse kommt: FIFO (First In First Out)
    Operationen: c.first(), c.append(), c.removeFirst()
  • Deque
    (Double Ended Queue) wie STACK + QUEUE, Objekte können an beiden Enden entfernt oder eingefügt werden
  • MinPriorityQueue
    Warteschlange, die die schnellsten Jobs vorzieht (z.B. an der Kasse im Supermarkt diejenigen, die die wenigsten Produkte kaufen möchten)
    Mögliche Operationen: c.smallest(), c.removeSmallest(), c.insert()
  • MaxPriorityQueue
    Warteschlange, die die größten Jobs vorzieht
    Unterstützte Operationen sind: c.largest(), c.removeLargest(), c.insert()
  • MinMaxPriorityQueue
    MinPriorityQueue + MaxPriorityQueue kombiniert die 2 vorherigen Verfahren