Informatik A Zusammenfassung

Werbung
Informatik A
Zusammenfassung
1. Daten und Zahlen
 2-er Komplement
 Komplexitätsklassen
 Variablen
 Konstantenbezeichner
 Rechnen mit Binärzahlen
 Gleitkommazahlen
2. Java
 Kontrollstrukturen
 Algorithmus
 Methode
 Obkektorientierte Programmierung
 Binden (statisch, dynamisch)
3. Endliche Automaten
 formale Definition
 Bsp.: Binärzahl durch 3 teilbar ?
4. Rekursion
 Türme von Hanoi
5. Halteproblem
6. Sortieren
 Komplexität-Übersicht
 SelectionSort
 BubbleSort/ShakerSort
 MergeSort
 QuickSort
 BucketSort/RadixSort
 HeapSort
 Heap
7. Abstrakte Datentypen
 Liste
 Keller
 Schlange
 (binärer) Baum
 Suchbaum
 AVL-Baum
 Traversierungen
 Intervallinorder
 Mengen verwalten
 Spielbaum
8. Hashing
 Ofenes Hashing
 Geschlossenes Hashing
 Laufzeit
9. Graphen
 gerichteter/ungerichteter Graph
 Implementationen
 Adjazenzmatrizen
 Adjazenzlisten
 Typische Probleme für Graphen
 Traversieren, Hamiltonkreis, Traveling Salesman
 All-pairs-shortest-path, Single-source-shortest-path
 Topologisches Sortieren, Chinese Postman
10. Suchen
 Tiefensuche
 Breitensuche
11.Wichtige Algorithmen
Codierung ganze Zahlen
im 2-er Komplement
0
0
0
0
0
0
0
0
1
1
1
1
1
1
1
1
1
1
1
1
0
0
0
0
1
1
1
1
0
0
0
0
1
1
0
0
1
1
0
0
1
1
0
0
1
1
0
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
7
6
5
4
3
2
1
0
-1
-2
-3
-4
-5
-6
-7
-8
Komplexitätsklassen:
log n
n
n * log n
n2
n3
2n
n!
binäre Suche
lineare Suche
schlaues Sortieren
dummes Sortieren
Gleihungssystem lösen
alle Teilmengen
alle Permutationen
Variablen:
Konstantenbezeichner
Was sorgt für Speicherverwaltung?  einfache Datentypen (float, char, int)
Konstante  Schlüsselwort „final“
Datentyp legt fest:
Wertbereich
Operationen
Eingabe (char) in weiterverwendbare Zahlen (int)
umwandeln:
Jedem Zeichen ist ein ASCII-code zugewiesen
Char c;
(int) c  liefert ASCII-Nummer in integer form
Negative Zahl berechen:
Gegeben –x :
Finde
+x :
Inverieren :
Addiere 1 :
-4
0100
1011
1100
Bei Addition: Überlauf beachten!
 Trick: Vorzeichenbit verdoppeln, müssen nach Addition identisch sein:
00111
7
+ 00001
1
01000
Ergebnis undefiniert
00011
3
11011
-5
11110
-2
Ergebnis ok!
[[ Gleitkommazahlen ]]
Darstellung: x = m * 2e
Standart: float, double
Verfahren:
x =
0,
1,
0,
1,
1,
13,5
6875
3750
7500
5000
0000
=
1,6875 * 23
verdoppeln
verdoppeln
verdoppeln
verdoppeln
 Reduzierte Mantisse: [1 0 1 1] = 0.6875
 Exponent:
[0 1 1] = 3
0
Vorzeichen
00000011
Exponent
10110000000000000000000
Reduzierte Mantisse
Multiplikation:
Addition:
Exponenten addieren
Mantisse multiplizieren
Exponenten angleichen
Mantisse addieren
12 * 20
=
3
4
(1,5 * 2 ) * (1,25 * 2 ) =
(1,5 * 1,25) * (23 * 24) =
1,875 * 27
=
12 + 20
(1,5 * 23) + (1,25 * 24)
(0,75 * 24) + (1,25 * 24)
(0,75 + 1,25) * 24
240
=
=
=
=
32
JAVA
Kontrollstrukturen:
Regeln dynamischen Ablauf der Anweisungsfolge eines Programms durch
Bedingungen, Verzweigungen und Schleifen
Abzählreim:
Algorithmus = endlich lange Vorschrift, bestehend aus Einzelanweisungen
Häufig benutzte Algorithmen  Methode (Klassen- oder Objektbezogen)
Schlüsselwort „static“  Klassenmethode
Aufrufmechanismus: call-by-value
Objektorientierte Programmierung:
Klasse
Objekt
Konstruktor
Datenfelder
Vererbung
Überschreiben
Überladen
Methoden
Auf Konstruktor der Oberklasse zugreifen
class Hund()
Hund hasso
Hasso = new hund()
Hasso.gewicht = 42
class Schlittenhund extend Hund { }
Hasso.sitz()
super()
Binden:
Wenn mehrere Methoden mit gleichem Namen und unterschiedlicher
Parameterliste existieren, ist die Methode überladen.
Statisches Binden bezeichnet den Vorgang, einem Objekt zur Übersetzungszeit
den Programmcode fest zuzuordnen; dynamisches Binden bezeichnet den
Vorgang, einem Objekt zur Laufzeit den Programmcode zuzuordnen.
Referenzen  modellieren Zeiger, Verweise
Endliche Automaten:
5-Tupel A = (S, ∑, δ, s0, F)
-
S == endliche Zustandsmenge
∑ == endliches Eingabealphabet
δ: S x ∑  S == Überführungsfunktion
s0 € S == Startzustand
F € S == Endzustände
Typische Überführungsfunktion im Code: z = delta[z] [ (int) eingabe – (int) ‘0‘]
Beispiel: „ist Binärzahl durch 3 teilbar?“
Überführungsfunktion:
Eingabe 
Zustände
↓
r0
r1
r2
r0 ist Start und Zielzustand
0
1
r0
r2
r1
r1
r0
r2
Java-Code
Zustandüberführung mit einem Feld:
Int [ ] [ ] delta = { (0,1),
(2,0),
(1,2) };
Zustand: s
0
1
2
Eingabe durchgehen:
For (int i=0; i < zeile.length; i++) {
Wende Überführungsfunktion an: s ist Zustand
switch(zeile[i]) {
case `0‘: s = delta[s] [0]; break;
case `1’: s = delta[s] [1]; break;
default………
}
Je nach dem ob also ne 0 oder 1 als Eingabe kommt gehe in unserem Feld in
den jeweiligen Zustand (in die jeweilige Zeile)
// delta[2] [0]  2. Reihe 0.te Spalte
[[ Suchen ]]
Lineare Suche == Kompletter Durchlauf eines Arrays bis gefunden
 Worst case: O(n)
𝑛
Average case: O( )
2
Binäre Suche == Suche in geordneter Reihe, immer Mitte der noch zu
durchsuchenden Reihe betrachten und entscheiden ob rechts oder links
weitergesucht werden muss.
 Immer: O( log n )
Rekursion:
Erneuter Aufruf einer Methode aus dem Methodenrumpf heraus
Typischerweise werden dabei die aktuellen Parameter so modifiziert, dass die
Problemgröße schrumpft, damit nach mehrmaligem Wiederholen dieses
Prinzips schließlich kein weiterer Aufruf erforderlich ist und die Rekursion
abbrechen kann.
Jeder rekursive Algorithmus lässt sich auch iterativ implementieren
[[ Türme von Hanoi ]]
n Scheiben mit abnehmender Größe liegen auf Startort A
Sie sollen in derselben Reihenfolge auf Zielort C zu liegen kommen
Die Regeln für den Transport lauten:
1.) Jede Scheibe muss einzeln transportiert werden
2.) Es darf nie eine größere Scheibe auf einer kleineren liegen
3.) Es darf ein Hilfsort B zum Zwischenlagern verwendet werden
funktion bewege (Zahl i, Stab a, Stab b, Stab c) {
falls (i > 0) {
bewege(i-1, a, c, b); // n-1 von Start nach Zwischen
verschiebe oberste Scheibe von a nach c;
bewege(i-1, b, a, c); // n-1 Scheiben von Zwischen nach Ziel
}
}
n-1 von Start nach Zwischen
erste Scheibe von Start nach Ziel
n-1 Scheiben von Zwischen nach Ziel
Beweis durch Induktion
Laufzeit: 𝑂(2𝑛 − 1)
Induktionsverankerung: f(0) = 0 = 20 − 1
Induktionsschritt: Sei bis n − 1 bewiesen:
f(n) = 2 · f(n − 1) + 1 = 2 · (2n−1 − 1) + 1
= 2n − 2 + 1 = 2n – 1
Rekursionsgleichung
Induktionsannahme
Halteproblem
Beh.: Es gibt kein Programm, welches entscheidet, ob ein gegebenes
Programm, angesetzt auf einen gegebenen Input, anhält.
Beweis durchWiderspruch
Annahme: Es gibt eine Methode haltetest in der Klasse Fee:
public class Fee {
public static boolean haltetest (char[]s, char[]t) {
//
//
//
//
liefert true, falls das durch die Zeichenkette s dargestellte
Java-Programm bei den durch die Zeichenkette t dargestellten
Eingabedaten anhaelt;
liefert false, sonst
}
}
Dann lässt sich folgendes Java-Programm in der Datei Quer.java konstruieren:
import AlgoTools.IO;
public class Quer {
public static void main(String[] argv) {
char[] s = IO.readChars();
if (Fee.haltetest(s,s)) while (true);
}
}
Sei q der String, der in der Datei Quer.java steht.
Was passiert, wenn das Programm Quer.class auf den String q angesetzt
wird ? D.h.
java Quer < Quer.java
1. Fall: Hält an  haltetest(q,q) == false
 Quer angesetzt auf q hält nicht!
2. Fall: Hält nicht  haltetest(q,q) == true
 Quer angesetzt auf q hält an!
 Also kann es die Methode haltetest nicht geben!
SORTIEREN
Motivation für Sortieren:
1. Häufiges Suchen
Einmal sortieren, dann jeweils log n Aufwand.
2. Tritt ein Element in zwei Listen L1, L2 auf?
Sortiere L1 · L2, dann nach Doppelten suchen!
Eine Obere Schranke bezieht sich auf einen konkreten Algorithmus......wie
lange dieser braucht um das Problem zu lösen
Untere Schranke sagt aus wieviele Durchläufe jeder Algorithmus für ein
Problem mindestens durchlaufen muss.
 Also eine untere Schranke heisst, es kann keinen Algorithmus geben, der das
Problem in einer schnelleren Laufzeit lösen kann
O(n * log n ) ist untere Schranke für sortieren durch vergleichen, weil ein
binärer Baum mit n! Blättern hat mindestens die Höhe
[[ SelectionSort ]]
jeweils das kleinste nach vorne
O(n2)
[[ BubbleSort ]]
Jeweils unterschiedliche Paare
vertauschen
O(n2)
Variation: ShakerSort: einmal
von vorne, einmal von hinten
𝒏
𝟒
∗ 𝒍𝒐𝒈 𝒏.
[[ MergeSort ]]
Divide&Conquer: sortiere 1.
Hälfte, sortiere 2. Hälfte und
vereinige
Merge-Methode nimmt
jeweils das kleinere aus
beiden Mengen bis eine leer,
dann Rest der anderen
anhängen.
O(n * log n)
[[ QuickSort ]]
Partitioniere die
Folge in eine
elementweise
größere und eine
elementweise
kleinere
O(n * log n)
Quicksort: im ungünstigsten Fall O(n2)  kann verhindert werden durch
Bestimmung des Medians. (aber wenig sinnvoll)
[[ BucketSort ]]
Sortieren durch Verteilen
auf einzelne Fächer
(Buckets), Alphabet muss
bekannt sein!
O(n)
[[ RadixSort ]]
Sortieren von Strings über
endlichen Alphabet, durch
mehrmaliges anwenden von
BucketSort
O(n)
[[ HeapSort ]]
Benutze Heap und entferne
immer wieder die Wurzel
(kleinstes Element) bis leer
Binärer Baum == entweder leer
oder er besteht aus einem
Knoten, dem 2 weitere Knoten
zugeordnet sind  Vater,
Söhne, Wurzel, Blätter
Heap == bis auf die letzte Ebene
vollständiger binärer Baum, die
einzelnen Knoten enthalten
Schlüssel. Der Schlüssel eines
Knotens ist stets kleiner als der
seiner Söhne
O(n * log n)
Heap Implementation?
 Array
[[Heap]]
Ein Heap ist ein binärer Baum
(Konstruktion von Heap  O(n))
Der kleinste Schlüssel bildet die Wurzel des Baumes und alle Nachfolger sind größer.
Insert: neues Element an das Ende der Heaps  Element, solange nach oben
schieben bis es in der Wurzel steht oder der Schlüssel des Vaters kleiner als der
des Elementes selbst ist.
delete: Wurzel entfernen und an seine Stelle das am Ende des Heaps
befindliche Element setzen.  Element solange nach unten schieben, (mit
kleinstem Schlüssel tauschen) bis es Blatt ist oder die Kinder größere Schlüssel
als das Element selbst besitzen.
get: einfach Schlüssel aus Wurzel holen. O(1)
(nur Minimum !)
In welcher Reihenfolge werden die Elemente in dem Array gespeichert?
der Breite nach
Wurzel: Nummer 0
linker Sohn von Knoten i: 2*i +1
rechter Sohn von Knoten i: 2*i + 2
Welche Methoden sollte ein Interface Heap ankündigen?
Object min( )
void delete( )
void insert(Object)
Im obigen Array implementiert .....heapify durch tauschen im Array
Kann man gut ein bestimmtes Element im Heap suchen oder herauslöschen?
nein
Wie wird der Heap aufgebaut? Warum ist Laufzeit hierfür O(n), obwohl
eigentlich n mal mit Aufwand O(log n) repariert werden muss?
mehr Knoten in unteren Ebenen
[[ Externes Sortieren ]]
Sortieren auf Medien mit sequentiellem Lese- und Schreibzugriff durch
wiederholtes Mischen von bereits sortierten Folgen
Lauf == monoton nicht fallende Teilfolge
ADT == Abstrakter Datentyp (Datenstruktur + Operationen)
Interface == Schnittstelle, die nur abstrakte Methodenköpfe und Konstanten
enthält, muss implementiert werden
[[ Liste ]]
Liste == Folge von Elementen mit einem sog. Aktuellen Element
Operationen:
empty( )
endpos( )
reset( )
advance( )
elem( )
insert(Object x)
delete ( )
Liefert true, falls leer
Liefert true, wenn Liste abgearbeitet
Das erste Listenelement wird zum aktuellen
Der Nachfolger des akt. wird zum aktuellen
Liefert das aktuelle Element
Fügt vor das aktuelle Element ein Element ein; das
neu eingefügte wird zum aktuellen Element
Löscht das aktuelle Element
[[ Keller ]]
Keller == Folge von Elementen mit einem sog. Top-Element (Last in – First out)
Operationen:
empty( )
push(Object x )
top( )
pop( )
Liefert true, falls Keller leer ist
Legt Element auf Keller
Liefert oberstes Element
Entfernt oberstes Element
[[ Schlange ]]
Schlange = Folge von Elementen mit einem sog. Front-Element (First in – First
out)
O(log n) ?
Operationen:
enq(Object x )
deq( )
front( )
empty( )
Fügt x hinten ein
Entfernt vorderstes Element
Liefert vorderstes Element
Liefert true, falls leer
[[ Baum ]]
(binärer) Baum = … ist entweder leer oder besteht aus einem Knoten, dem ein
Element und 2 binäre Bäume (Söhne) zugeordnet sind
Operationen:
empty( )
left( )
right( )
value( )
Liefert true, falls Baum leer ist
Liefert linken Teilbaum
Liefert rechten Teilbaum
Liefert Wurzelelement
was implementieren Bäume?  Menge
Die Höhe eines Baumes hängt logarithmisch von de Anzahl seiner Elemente
ab
[[ Suchbaum ]]
(links < rechts)
O(log n)
Suchbaum
Suchbaumoperationen:
lookup(Compareable x)
insert(Compareable x)
delete(Compareable x)
sucht x in Menge
liefert Comparable-Objekt falls gefunden
liefert null sonst
versucht x in Menge einzufügen
liefert true, falls erfolgreich
liefert false sonst
versucht x aus Menge zu entfernen
liefert true falls erfolgreich
liefert false sonst
public Comparable lookup(Comparable x)





Beginnt bei Wurzel
Solange Knoten vorliegt
Vergleiche x mit Knoteninhalt
Dann je nach Vergleich entweder
In linken Teilbaum oder rechten Teilbaum weitermachen
[[ AVL-Baum ]]
(ausgeglichen)
O(log n)
AVL-Baum == ausgeglichener Suchbaum (Höhen seiner Söhne unterscheiden
sich um höchstens 1)
bal(x) = höherechts – höhelinks
Höhe eines AVL-baums ist ≤ 1,45 * log n
also höchstebns 45% größer als erforderlich
Einfügen: höchstens 1 Rotation
Löschen: höchstens x Rotationen mit x = Anzahl der Knoten auf dem Weg zur
Wurzel  O(log n)
Suchen: O(log n)
[[ Traversierungen ]]
Rekursive Implementierungen
inOrder( knoten ):
if knoten.links ≠ null then
inOrder( knoten.links )
print( knoten )
if knoten.rechts ≠ null then
inOrder( knoten.rechts )
preOrder( knoten ):
print( knoten )
if knoten.links ≠ null then
preOrder( knoten.links )
if knoten.rechts ≠ null then
preOrder( knoten.rechts
)
postOrder( knoten ):
if knoten.links ≠ null then
postOrder( knoten.links
)
if knoten.rechts ≠ null then
postOrder( knoten.rechts
)
print( knoten )
Iterative Implementierung von Traversierungen
 mit Zuhilfenahme von Kellern
Intervallinorder:
(abfangen)
Intervall-inOrder( knoten ):
if knoten.links ≠ null
+
if knoten.links > intervallanfang
inOrder( knoten.links )
if knoten < intervallende
{
print( knoten )
if knoten.rechts ≠ null then
inOrder( knoten.rechts )
}
Intervallpreorder  Tiefensuche im Intervall
//
Preorder iterativ  Tiefensuche....
then
Mengen verwalten
Was für Sachen muss man den mit Daten so machen wenn man sie
verwaltet?
speichern, wiederfinden, löschen
Angenommen, ein Kunde will die Implementation einer Menge, wie
realisiere ich das?
Hashing oder Suchbaum.
[[ Spielbaum ]]
Spielbaum == Baum mit zwei Typen von Knoten: Minimum und Maximum
Wert eines Blattes durch statische Stellungsbewertung
Wert eines min-Knotens: min der Söhne
Wert eines max-Knotens: max der Söhne
Zur Implementation: der Baum ist nicht binär, daher hat jeder Knoten einen
Verweis auf eine Liste von Söhnen
[[ Hashing ]]
Offened Hashing == Einträge werden in einem Array von Buckets verwaltet,
mehere Elemente können also den selben Hashwert belegen. Bei N Buckets
und n Einträgen enthält jede Liste durchschnittlich
n
N
Buckets
Geschlossenes Hashing == Beschränkte Anzahl von Plätzen
Verwaltung durch ein
Comparable[] inhalt und ein
byte[] zustand
verschiedene Sondierfunktionen zum Behandeln von Kollisionen
Falls 𝑦 = 𝑓(𝑥) schon belegt ist, so suche für x einen Alternativplatz
- Lineares Sondieren: y, y+1, y+2, y+3, .....
- Quadratisches Sondieren: y, y+1, y+4, y+9, .....
- Rehashing: y, y+f2(x), ......
Laufzeit:
n = Anzahl der gespeicherten Objekte,
N = Anzahl der Speicherpositionen,
𝑛
= α = Auslastungsfaktor
𝑁
erfolglose Suche:
erfolgreiche Suche:
1
1− 𝛼
−ln(1− 𝛼)
𝛼
= 5,0
(für α = 0,8)
= 2,01
(für α = 0,8)
 In 2 Schritten wird von 1.000.000 Elementen aus einer 1.250.000 großen
Tabelle das richtige gefunden (AVL benötigt ezwa 20 Vergleiche)
 Bei höherem α steigt die Anzahl der Schritte stark an (exponentiell?)
[[ Graphen ]]
Gerichteter Graph:
G = (V,E)
E
V (Knotenmenge),
V x V (Kantenmenge)  Kanten
sind einseitig
Hier:
V = {a,b,c,d}
E = {(a,c),(a,b),(c,b),(c,d),(d,b),(b,d)}
Ungerichteter Graph:
G = (V,E)
E
V (Knotenmenge)
P2(V) = 2-elementige Teilmenge
von V
Kanten können über eine
Kostenfunktion gewichtet sein
c: E  {Reele Zahlen}
Mit Graphen können binäre beziehungen zwischen Objekten modelliert
werden. Die Objekte werden durch die Knoten, die Beziehungen durch die
Kanten modelliert.
Implmentationsmöglichkeiten:
(1) durch Adjazenzmatrizen:
- Platzbedarf: O( |𝑉|2 )
- Zugriff auf einzelne Knoten in konstanter Zeit möglich
- Kein effizientes Verarbeiten von Nachbaknoten
- sinnvoll bei dicht besetzten Graphen und bei Algorithmen die wahlfreien
Zugriff auf eine Kante benötigen
Unbewertete Kanten:
Bewertete kanten:
(2) durch Adjazenzlisten:
- Platzbedarf: O( |E| )
- kein effizienter Zugriff auf Kanten möglich
- sinnvoll bei dünn besetzten Graphen und bei Algorithmen die auf Nachbarn
eines Knotens zugreifen müssen
[[ Typische Probleme für Graphen ]]
Traversieren:
jeden Knoten genau einmal besuchen (Hamilton-Path)
All-pairs-shortest-path-Problem:
günstigster Weg für jede Start-Ziel-Variante  n x n Matrix
 in Polynomialzeit lösbar
Multiplikation zweier n x n-Matrizen  O(n3) oder hoch2,7
Single-source-shortest-path-Problem:
Von einem bestimmeten Knoten  kürzester Weg zu allen Knoten
 in Polynomialzeit lösbar
Weg von a nach f: bestens 10
Sequenz: a b  d  c  e  f
Laufzeit: O( |E| * log(|V|) )
auf Grund von Heapsortierungen (Anwendung)
Hamilton-Kreis:
Jeden Ort besuchen, Rückkehr an Ausgangsort
Laufzeit:
O(2n)
Travelling Salesman:
Günstigster Hamilton-Kreis
Topologisches Sortieren:
Nummerierung der Knoten, dass jeder Knoten eine Zahl ∈ {0, … , 𝑛 − 1} erhält
 Suche 𝑓 ∶ 𝑉 → {0, … , 𝑛 − 1} mit 𝑓(𝑥) < 𝑓(𝑦) falls
(𝑥 , 𝑦) ∈ 𝐸
Laufzeit: O( |E| )  jeden Knoten einmal ansehen  konstant
Chinese Postman
Jeden Weg (Kante) einmal ablaufen (Eulerweg)
Laufzeit: O( nk )
[[ Tiefensuche ]]
1. Bestimme den Knoten an dem die Suche beginnen soll
2. Expandiere den Knoten und speichere alle Nachfolger in einem Keller
3. Rufe rekursiv für jeden der Knoten in dem Stack Tiefensuche auf
o Falls der Keller leer sein sollte, tue nichts
o Falls das gesuchte Element gefunden worden sein sollte, brich die
Suche ab und liefere ein Ergebnis
Tiefensuche im Intervall
1. Bestimme den Knoten, an dem die Suche
beginnen soll, und bestimme die maximale
Suchtiefe
2. Prüfe, ob der aktuelle Knoten innerhalb
der maximalen Suchtiefe liegt
o Falls nein: Tue nichts
o Falls ja:
1. Expandiere den Knoten und
speichere alle Nachfolger in
einem Keller
2. Rufe rekursiv für jeden der
Knoten des Keller
Tiefensuche im Intervall auf
und gehe zu Schritt 2
Tiefensuche auf Baum mittels Keller:
1. Baum in Keller
2. Baum aus Keller
3. Wurzel pop  return
4. Rechter Sohn? Ja  Keller
5. Linker Sohn ? Ja  3.
 bis nichts mehr im Keller
Laufzeit:
entspricht  preorder
[[ Breitensuche ]]
1. Bestimme den Knoten, an dem die Suche beginnen soll, und speichere
ihn in einer Warteschlange ab.
2. Entnimm einen Knoten vom Beginn der Warteschlange und markiere
ihn.
o Falls das gesuchte Element gefunden wurde, brich die Suche ab
und liefere „gefunden“ zurück.
o Anderenfalls hänge alle bisher unmarkierten Nachfolger dieses
Knotens, die sich noch nicht in der Warteschlange befinden, ans
Ende der Warteschlange an.
3. Wiederhole Schritt 2.
4. Wenn die Warteschlange leer ist, dann wurde jeder Knoten bereits
untersucht. Beende die Suche und liefere „nicht gefunden“ zurück.
Laufzeit:
Breitensuche auf einem Baum mit
Hilfe einer Schlange
1. Baum in Schlange
2. Baum aus Schlange
3. Wurzel deq  return
4. Linker Sohn ? Ja  Schlange
5. Rechter Sohn? Ja  Schlange
6. Gehe zu 2.
 bis nichts mehr in Schlange
Unterschied:
Markieren mus nicht gemacht werden,
da im Baum keine Schleifen möglich
sind.
Beliebiger Knotennachbar bei Graph
[[ wichtige Algorithmen ]]
Collatz:
while (x != 1)
{
if(x%2==0) x/=2;
else 𝑥 = 𝑥 ∗ 3 + 1;
counter++;
}
//
wenn x gerade: x =
𝑥
2
sonst:
𝑥 =𝑥∗3+1
Fakultät:
int fak = 1;
for (i=1; i <= n;
i++)
fak
*=
rekursiv:
static int fak(int n) {
if(n==0) return 1;
else return n * fak(n-1);
}
GGT
while(y!=0)
z=x%y;
x=y;
y=z;
}
{
rekursiv
static int ggt(int x, int y)
if(y==0) return x;
else return gt(y,x%y);
}
{
i;
Dezimal  Dual
Positive ganze Zahlen:
while(x!=0)
{
if(x%2==0) System.out.println(“0“);
else System.out.println(“1“);
x/=2;
}
obacht bits werden rückwärts generiert
Mantisse:
for(int i = 0; i<23; i++) {
f*=2;
if(f>=1) {
System.out.println(“1“);
f--;
}
else System.out.println(“0“);
}
Sieb des Eratosthenes
int n = 1000
//willkürliche Obergrenze
boolean[] sieb = new boolean[n];
for(int i=2; i<n; i++) sieb[i]=true;
for(int i=2; i<n; i++) {
if(sieb[i]) System.out.println(i);
for(int j = i+1; j<n; j+=i) sieb[i]=false;
//streiche alle Vielfachen der gefundenen Primzahl
}
}
Binäre Suche
int[] a = {1,2,3,4,5,6,7,8,9};
int mitte, links, rechts;
mitte = links = 0;
rechts = a.length-1;
while(links<=rechts) {
mitte = (links + rechts) / 2;
if(a[mitte]==x) break;
//falls gefunden: fertig
if(a[mitte]<x) links=mitte+1 //zu weit links?
else rechts = mitte-1;
//zu weit rechts?
}
//Sprung in die Mitte, weiter suchen links oder rechts. Dort wieder Sprung in
die Mitte
Fibonacci
static int fib(int n) {
if(n<=1) return 1;
else return fib(n-1)+fib(n-2);
}
// 1 1 2 3 5 8 13
Herunterladen