Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
faecher:informatik:oberstufe:adt:set:implementationen:start [14.11.2021 19:42] – [Zahlbereichserweiterung] sbel | faecher:informatik:oberstufe:adt:set:implementationen:start [Unbekanntes Datum] (aktuell) – gelöscht - Externe Bearbeitung (Unbekanntes Datum) 127.0.0.1 | ||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
- | ====== Die Set-Implementationen im Detail ====== | ||
- | ===== Variante 1: ArrayList ===== | ||
- | |||
- | Die einfachste Lösung ist, wenn der ADT Set als interne Datenstruktur eine '' | ||
- | Beim Einfügen muss immer getestet werden, ob der Wert bereits in der '' | ||
- | |||
- | ==== Bewertung ==== | ||
- | |||
- | |||
- | === Vorteile: === | ||
- | |||
- | * Einfache Implementation | ||
- | * Speicherbedarf relativ gering (etwa proportional zur Anzahl der Werte) | ||
- | |||
- | |||
- | === Nachteile: === | ||
- | * Suche nach einem Element bei großen Mengen aufwendig (proportional zur Anzahl der Werte) | ||
- | |||
- | ===== Variante 2: Bitvektor ===== | ||
- | |||
- | Man kann eine Menge von Integer-Zahlen auch in eine einzelne Integer-Zahl verpackt darstellen, indem man die entsprechenden Bits in ihrer Binärdarstellung setzt. Man spricht dann von einem **Bitvektor**. | ||
- | |||
- | **Beispiel: | ||
- | |||
- | {{ : | ||
- | |||
- | Da eine Integer-Zahl in Java 32 Bit lang ist, kann man mit einer Integer-Zahl also für die Zahlen von 0 bis 31 darstellen, ob sie in einer Menge enthalten sind oder nicht. | ||
- | |||
- | ==== Ist eine Zahl in der Menge enthalten? ==== | ||
- | |||
- | Um herauszufinden, | ||
- | |||
- | <code java> | ||
- | int vier_gesetzt = 25 & 16; // Ergebnis: 16 | ||
- | int eins_gesetzt = 25 & 2; // Ergebnis: 0 | ||
- | </ | ||
- | |||
- | {{ : | ||
- | |||
- | Der binäre UND-Operator verknüpft zwei '' | ||
- | |||
- | Eine Zahl ist in der Menge enthalten, wenn bei der UND-Verknüpfung ein Wert herauskommt, | ||
- | |||
- | ==== Zahlen hinzufügen ==== | ||
- | |||
- | |||
- | Um einen Wert zu einem Bitvektor hinzufügen, | ||
- | |||
- | **Beispiel: | ||
- | <code java> | ||
- | | ||
- | </ | ||
- | {{ : | ||
- | |||
- | Der binäre ODER-Operator verknüpft zwei '' | ||
- | |||
- | Beim Setzen eines Bits muss nicht geprüft werden, ob es bereits gesetzt ist – der ODER-Operator verändert in diesem Fall den Bitvektor nicht. | ||
- | |||
- | ==== Bitmasken ==== | ||
- | |||
- | Zum lesen und setzen von Elementen benötigt man die entsprechenden Zahlen, letztlich in Binärdarstellung. Diese Zahlen, die man zum Auslesen oder Setzen von Bits verwendet werden als '' | ||
- | |||
- | Eine Maske, bei der als niederwertigstes Bit nur das n-te Bit von rechts gesetzt ist, entspricht der Zahl 2< | ||
- | |||
- | In Java wird eine solche Bitverschiebung ("bit shift" | ||
- | |||
- | <code java> | ||
- | int y = 1 << 7; // y ist 1*27 = 128 | ||
- | </ | ||
- | |||
- | Man kann auch andere Zahlen als die 1 verschieben: | ||
- | |||
- | <code java> | ||
- | int x = 13 << 3; // x ist 13*23 = 104 | ||
- | </ | ||
- | |||
- | {{ : | ||
- | |||
- | ==== Zahlbereichserweiterung ==== | ||
- | |||
- | Mit einer einzelnen 32-Bit-Zahl kann man Mengen der Zahlen 0 bis 31 abbilden. Will man größere Werte erlauben, benötigt man eine ArrayList von Integer-Zahlen. | ||
- | |||
- | Die k-te Zahl der ArrayList repräsentiert damit die Elemente mit den Werten 32·k bis 32·k+31. | ||
- | |||
- | {{ : | ||
- | |||
- | Das Element '' | ||
- | |||
- | Beim Einfügen muss die ArrayList ggf. um Elemente erweitert werden, so dass sie groß genug ist. | ||
- | |||
- | Pseudocode: | ||
- | |||
- | < | ||
- | einfuegen(n: | ||
- | k = n / 32 | ||
- | solange Länge von daten ≤ k: | ||
- | hänge 0 an daten an | ||
- | bit = n % 32 | ||
- | maske = 1 << bit | ||
- | daten[bit] = daten[bit] | maske | ||
- | </ | ||
- | |||
- | ==== Bewertung ==== | ||
- | |||
- | |||
- | === Vorteile: === | ||
- | |||
- | * Sehr speichereffizient, | ||
- | * Lesender Zugriff in konstanter Anzahl von Schritten möglich | ||
- | * Schreibender Zugriff meistens schnell möglich | ||
- | |||
- | === Nachteile: === | ||
- | |||
- | * Wenn nur wenige, aber große Werte gespeichert werden, wird Speicher verschwendet | ||
- | * Konzept ist nur zum Speichern von Integer-Zahlen anwendbar | ||
- | |||
- | |||
- | ===== Variante 3: Hashtable ===== | ||
- | |||
- | Die Hashtable verwendet ein Array, das die Werte der Menge enthält. | ||
- | |||
- | Das Problem ist, dass die Suche nach einem Wert unter Umständen sehr lange dauert – insbesondere, | ||
- | |||
- | Die Idee des Hashings ist, dass man einem Wert " | ||
- | Wir nehmen als erstes Beispiel ein Array mit 10 Plätzen: | ||
- | |||
- | {{ : | ||
- | |||
- | Um den Speicherort eines Wertes '' | ||
- | '' | ||
- | < | ||
- | einfuegen(42) → Position 42 mod 10 = 2, daten[2] = 42 | ||
- | einfuegen(77) → Position 77 mod 10 = 7, daten[7] = 77 | ||
- | </ | ||
- | |||
- | {{ : | ||
- | |||
- | Um herauszufinden, | ||
- | |||
- | < | ||
- | enthaelt(42) → Position 42 mod 10 = 2, daten[2] == 42 → ja | ||
- | enthaelt(23) → Position 23 mod 10 = 3, daten[3] ist leer → nein | ||
- | enthaelt(17) → Position 17 mod 10 = 7, daten[7] != 17 → nein | ||
- | </ | ||
- | |||
- | Dieses Vorgehen ist sehr schnell, da die Operationen nicht von der Anzahl der Werte in der Menge abhängig sind. | ||
- | |||
- | <WRAP center round box 90%> | ||
- | Die Funktion '' | ||
- | |||
- | Hashfunktionen bilden eine große Menge von Eingabewerten (hier: alle int-Zahlen) auf einen kleinen Bereich von Ausgabewerten ab (hier: die Zahlen von 0 bis 9). | ||
- | |||
- | Für unsere Datenstruktur ist die Hashfunktion | ||
- | |||
- | '' | ||
- | </ | ||
- | |||
- | ==== Kollisionen ==== | ||
- | |||
- | "Aber was macht man, wenn zwei Zahlen den gleichen Hashwert erhalten?" | ||
- | |||
- | Wenn zwei unterschiedliche Zahlen den gleichen Hashwert bekommen, spricht man von einer **Kollision**. Kollisionen sind bei Hashfunktionen unvermeidlich, | ||
- | |||
- | Im Beispiel würde die Zahl '' | ||
- | |||
- | Eine Möglichkeit ist, dass man an einer Stelle im Array nicht nur eine einzelne Zahl speichert, sondern mehrere (einen " | ||
- | |||
- | {{ : | ||
- | |||
- | Wenn man bestimmen will, ob ein Wert '' | ||
- | |||
- | * Bestimme den Index von x (z.B. '' | ||
- | * Untersuche alle Werte in diesem Behälter. Wenn einer davon gleich '' | ||
- | |||
- | Ein Behälter kann z.B. mit einer '' | ||
- | |||
- | Der Speicheraufwand ist etwas höher und auch das Durchsuchen der Behälter dauert etwas länger. | ||
- | |||
- | "Aber was haben wir damit jetzt gewonnen? Wir müssen immer noch die Behälter komplett durchsuchen!" | ||
- | |||
- | Das stimmt, allerdings ist es sehr unwahrscheinlich, | ||
- | |||
- | {{ : | ||
- | |||
- | Zudem kann man mit **Rehashing** die Elemente neu verteilen, wenn die Auslastung einen bestimmten Grenzwert (z.B. 75%) überschreitet. | ||
- | |||
- | Die Auslastung bezeichnet das Verhältnis der gespeicherten Werte zur Länge des Arrays. \\ Im Beispiel: 8 Elemente, 10 Plätze → Auslastung = 80% | ||
- | |||
- | {{ : | ||
- | |||
- | Man legt ein neues Array der Länge z.B. 21 an und sortiert die bestehenden Werte neu ein. Viele der Kollisionen treten jetzt nicht mehr auf, es können aber neue Kollisionen entstehen, die Behälter enthalten jetzt im Durchschnitt weniger als einen Wert. | ||
- | |||
- | Die Rehashing-Operation ist sehr zeitaufwendig, | ||
- | Im Durchschnitt ist der lesende und schreibende Zugriff auf die Werte in konstanter Zeit möglich, also unabhängig von der Anzahl der Elemente im Set. | ||
- | |||
- | Wenn man im Vorfeld bereits weiß, wie viele Elemente vermutlich gespeichert werden sollen, kann man bereits beim Erzeugen das Array entsprechend anlegen. | ||
- | |||
- | ==== Bewertung ==== | ||
- | |||
- | |||
- | === Vorteile: === | ||
- | |||
- | * Im Durchschnitt sehr schnell | ||
- | * Auf beliebige Datentypen anwendbar (in Java: Methode '' | ||
- | |||
- | === Nachteile: === | ||
- | |||
- | * Hoher Speicherbedarf | ||
- | * Kann in seltenen (konstruierten) Fällen langsam arbeiten |