In Vorlesung 3 habt ihr drei Algorithmen kennengelernt: den Münzwechsel, den Gauß-Trick und den Palindrom-Check. Außerdem in Vorlesung 2 die Datentypen und Eingabe/Ausgabe in C.
Heute setzt ihr beides um — aber mit einer wichtigen Drehung:
printf.Algorithmus in Klartext aufschreiben, bevor Code entsteht
Münzwechsel, Gauß-Trick, Palindrom selbst implementieren
Schleife vs. Formel — wie viel macht der Algorithmus aus?
Wann %d, wann %f? Was passiert bei 30/7?
Ziel: Sich daran gewöhnen, einen Algorithmus auf Papier zu denken — bevor man Code schreibt.
Wähle eine dieser Alltagsaufgaben:
Schreibe den Pseudocode dafür — 5 bis 10 Schritte. Achte auf:
Tausch deinen Pseudocode mit jemandem aus. Versucht, den jeweils anderen Algorithmus „im Kopf auszuführen". Funktioniert er? Welche Schritte sind unklar?
Aus VL3: Du arbeitest an der Kasse. Ein Kunde soll Wechselgeld zurückbekommen — mit so wenigen Münzen wie möglich.
Schreibe selbst den Pseudocode auf, bevor du den Code anschaust. Tipp: die Strategie heißt Greedy — „nimm immer das Größte zuerst".
Setze deinen Pseudocode in Code um. Bevorzugt C, aber wenn du eine andere Sprache flüssiger sprichst — auch gut.
Teste mit:
#include <stdio.h>
void wechselgeld(int cent) {
int muenzen[] = {200, 100, 50, 20, 10, 5, 2, 1};
for (int i = 0; i < 8; i++) {
while (cent >= muenzen[i]) {
printf("%d Cent\n", muenzen[i]);
cent -= muenzen[i];
}
}
}
int main() {
int betrag;
printf("Betrag in Cent: ");
scanf("%d", &betrag);
wechselgeld(betrag);
return 0;
}
Erklärung: Äußere for-Schleife geht durch alle Münzsorten von groß nach klein. Innere while-Schleife nimmt so viele Stück dieser Sorte, wie noch in den Restbetrag passen.
Aus VL3: die berühmte Aufgabe vom kleinen Gauß. Berechne die Summe 1 + 2 + 3 + … + N.
Implementiere zwei Versionen, die dasselbe Ergebnis liefern, aber unterschiedlich vorgehen:
n * (n+1) / 2Schreibe beide Funktionen. Beide sollen für n=100 dasselbe Ergebnis liefern (5050).
Nutze clock() aus <time.h>, um die Dauer zu messen — bei n = 1.000.000.000 (eine Milliarde).
#include <time.h>
clock_t start = clock();
// ... Algorithmus läuft ...
clock_t ende = clock();
double sek = (double)(ende - start) / CLOCKS_PER_SEC;
printf("Dauer: %.6f Sekunden\n", sek);
<time.h> — die Standard-C-Bibliothek für alles rund um Zeit (Datum, Uhrzeit, Stoppuhr).clock() — fragt das Betriebssystem: „wie viele CPU-Ticks hat mein Programm seit dem Start verbraucht?". Ein „Tick" ist eine kleine, fixe Zeiteinheit der CPU.clock_t — der Datentyp, in dem diese Tick-Zahl steckt (intern meist ein long). Wir können damit rechnen wie mit jedem Integer.CLOCKS_PER_SEC — eine vom Compiler vorgegebene Konstante, die sagt, wie viele Ticks pro Sekunde gezählt werden (typisch 1.000.000 auf macOS/Linux).ende - start — Differenz: wie viele Ticks ist mein Algorithmus gelaufen?(double)(ende - start) — Cast zu double! Ohne das würde C eine Ganzzahl-Division machen und Nachkommastellen abschneiden (siehe Aufgabe 5)./ CLOCKS_PER_SEC — Ticks geteilt durch Ticks-pro-Sekunde = Sekunden.Kurzformel: Sekunden = Ticks ÷ Ticks-pro-Sekunde.
(double) weglässt? Probier's aus — und du verstehst sofort, warum Aufgabe 5 wichtig ist.
Schreibe in 1-2 Sätzen auf:
#include <stdio.h>
#include <time.h>
long long summe_schleife(long long n) {
long long summe = 0;
for (long long i = 1; i <= n; i++) {
summe += i;
}
return summe;
}
long long summe_gauss(long long n) {
return n * (n + 1) / 2;
}
int main() {
long long N = 1000000000LL; // 1 Milliarde
clock_t s1 = clock();
long long r1 = summe_schleife(N);
double t1 = (double)(clock() - s1) / CLOCKS_PER_SEC;
clock_t s2 = clock();
long long r2 = summe_gauss(N);
double t2 = (double)(clock() - s2) / CLOCKS_PER_SEC;
printf("Schleife: %lld in %.6f s\n", r1, t1);
printf("Gauß: %lld in %.6f s\n", r2, t2);
return 0;
}
Typische Ergebnisse: Schleife ~ 2-3 Sekunden, Gauß < 0,000001 Sekunden. Faktor: ~ 3.000.000×. Gleiche Sprache, gleicher Compiler, gleicher Rechner — nur die Idee ist besser.
Wichtig: long long brauchen wir, weil das Ergebnis (5×10¹⁷) nicht in einen normalen int passt.
Aus VL3: ein Wort ist ein Palindrom, wenn es vorwärts und rückwärts gleich gelesen wird (ANNA, OTTO, RACECAR).
1 wenn Palindrom, 0 sonstSchreibe den Algorithmus auf Papier. Tipp aus VL3: vergleiche das erste mit dem letzten, dann das zweite mit dem vorletzten, …
Teste mit: ANNA, OTTO, HALLO, RACECAR, HTW.
char. strlen(wort) aus <string.h> gibt dir die Länge.
#include <stdio.h>
#include <string.h>
int ist_palindrom(char wort[]) {
int n = strlen(wort);
int links = 0;
int rechts = n - 1;
while (links < rechts) {
if (wort[links] != wort[rechts]) {
return 0; // sofort abbrechen
}
links++;
rechts--;
}
return 1; // alle Paare passten
}
int main() {
char *tests[] = {"ANNA", "OTTO", "HALLO", "RACECAR", "HTW"};
for (int i = 0; i < 5; i++) {
printf("%-10s: %s\n", tests[i],
ist_palindrom(tests[i]) ? "Palindrom ✓" : "kein Palindrom");
}
return 0;
}
Idee: zwei Variablen wandern aufeinander zu. Sobald ein Paar nicht passt → raus.
Aus VL2: verschiedene Datentypen, verschiedene Format-Specifier. Hier die typischen Stolperfallen.
Schreibe ein Programm casting.c, das folgende Berechnungen ausgibt:
30 / 7 als %d (int)30.0 / 7 als %f (double)(double)30 / 7 als %f30 / 7 als %f ← Achtung!Schreibe für jede Zeile vorher auf, was du erwartest. Dann probier's aus. Wer hat recht?
int / int in C → das Ergebnis ist int (Rest wird abgeschnitten)int / double oder double / int → double%d erwartet int, %f erwartet double — niemals mischen!30/7 als %f) so eine seltsame Zahl raus? Hinweis: printf liest die falschen Bytes als double.
#include <stdio.h>
int main() {
printf("30 / 7 (als %%d): %d\n", 30 / 7);
printf("30.0 / 7 (als %%f): %f\n", 30.0 / 7);
printf("(double)30 / 7: %f\n", (double)30 / 7);
printf("30 / 7 (als %%f): %f ← undefined behavior!\n", 30 / 7);
return 0;
}
Erwartete Ausgabe:
30 / 7 (als %d): 4 30.0 / 7 (als %f): 4.285714 (double)30 / 7: 4.285714 30 / 7 (als %f): 0.000000 ← oder Müll, je nach Compiler
Lehre: in C musst du immer wissen, welchen Typ deine Werte haben. Das ist anders als z.B. in Python, wo der Interpreter das automatisch macht — aber dafür ist C schneller und deterministischer.
Ziel: aus einer Alltagsbeschreibung den passenden Algorithmus erkennen — die Brille der Algorithmen-Welt aufsetzen.
Zu jedem Szenario: welcher Algorithmus aus VL3 passt? (Münzwechsel/Greedy · Gauß-Formel · Palindrom-Check · keiner)
Für Szenario 4 (Google Maps): das ist ein Graph-Algorithmus — dazu kommen wir später. Aber kannst du raten, was die Knoten und Kanten in Google Maps sind?
Bonus: in Google Maps sind Knoten = Kreuzungen, Kanten = Straßenabschnitte (mit Länge/Zeit als Gewicht). Der Algorithmus heißt Dijkstra — wir lernen ihn in VL11.
FizzBuzz ist eine berühmte Aufgabe in Bewerbungsgesprächen. Sie testet, ob du in Algorithmen denken kannst.
Schreibe ein Programm, das die Zahlen von 1 bis 100 ausgibt — mit folgender Regel:
1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 ...
% gibt dir den Rest einer Division. 15 % 3 ergibt 0 → also durch 3 teilbar.
#include <stdio.h>
int main() {
for (int i = 1; i <= 100; i++) {
if (i % 15 == 0) { // erst die spezifischste Bedingung!
printf("FizzBuzz\n");
} else if (i % 3 == 0) {
printf("Fizz\n");
} else if (i % 5 == 0) {
printf("Buzz\n");
} else {
printf("%d\n", i);
}
}
return 0;
}
Pointe: wir prüfen i % 15 zuerst, weil 15 = 3 × 5. Wenn du das nicht machst und mit i % 3 startest, kriegst du nie „FizzBuzz" — sondern immer nur „Fizz".
Reflexion: derselbe Algorithmus in Python wäre fast identisch — nur mit weniger Klammern. Die Idee ist die Sprache.
%d und wann %f brauchstBevor du gehst, beantworte für dich:
→ Diese Reflexion ist freiwillig, aber sie zementiert das Gelernte.
Passwörter werden im Lab durch die Lehrkraft bekannt gegeben — bitte erst probieren, dann vergleichen.
| Aufgabe | Thema | Passwort |
|---|---|---|
| Aufgabe 1 | Pseudocode-Übung | keine Lösung — eigene Antwort |
| Aufgabe 2 | Münzwechsel (Greedy) | wechsel |
| Aufgabe 3 | Summe 1..N (Gauß) | gauss |
| Aufgabe 4 | Palindrom-Check | anna |
| Aufgabe 5 | Datentypen-Praxis | cast |
| Aufgabe 6 | Algorithmus erkennen | algorithmus |
| Aufgabe 7 | FizzBuzz (Bonus) | fizzbuzz |
© 2026 HTW Berlin · Prof. Dr. Alexandra Mikityuk