🏠 Startseite

🔄 Array-Manipulation

Kopieren, Umkehren, Verschieben

Palindrom prüfen

Grundlagen der Programmierung

📋 Heute lernen wir

  • 📋 Array kopieren - Grundlage für viele Operationen
  • 🔄 Array umkehren (Reverse) - mit Zwei-Zeiger-Technik
  • ➡️ Elemente verschieben (Shift) - nach links und rechts
  • 🪞 Palindrom prüfen - kombiniert alles!

💡 Alle nutzen bekannte Konzepte: Schleifen, Arrays, Swap, Vergleiche

📋 Array kopieren - Warum?

Manchmal brauchen wir eine Kopie eines Arrays:

  • Original behalten, Kopie verändern
  • Sortieren ohne Original zu ändern
  • Backup vor riskanten Operationen

⚠️ Das funktioniert NICHT:

int original[5] = {1, 2, 3, 4, 5};
int kopie[5];

kopie = original;  // ❌ FEHLER! Arrays können nicht so kopiert werden!

📋 Array kopieren - Die Lösung

Wir müssen jedes Element einzeln kopieren:

#include <stdio.h>

int main()
{
    int original[5] = {10, 20, 30, 40, 50};
    int kopie[5];

    /* Element für Element kopieren */
    for (int i = 0; i < 5; i++)
    {
        kopie[i] = original[i];
    }

    /* Kopie verändern - Original bleibt unverändert! */
    kopie[0] = 999;

    printf("Original[0]: %d\n", original[0]);  // 10
    printf("Kopie[0]: %d\n", kopie[0]);        // 999

    return 0;
}

📋 Array kopieren - Visualisierung

Original:

10[0]
20[1]
30[2]
40[3]
50[4]

⬇️ kopiere jedes Element ⬇️

Kopie:

10[0]
20[1]
30[2]
40[3]
50[4]
✅ Muster: kopie[i] = original[i] für alle i

🔄 Array umkehren (Reverse)

Aufgabe: Die Reihenfolge der Elemente umdrehen

Vorher:

1[0]
2[1]
3[2]
4[3]
5[4]

🔄

Nachher:

5[0]
4[1]
3[2]
2[3]
1[4]

🔄 Die Zwei-Zeiger-Technik

Idee: Zwei Index-Variablen ("Zeiger") - einer am Anfang, einer am Ende

left
1[0]
2[1]
3[2]
4[3]
5[4]
right

Warum ist das clever?

  • Effizient: Nur n/2 Durchläufe statt n
  • Kein Extra-Speicher: In-place Manipulation
  • Vielseitig: Reverse, Palindrom, Suche...

Algorithmus-Muster:

  1. Verarbeite Elemente bei left und right
  2. left++, right--
  3. Wiederhole bis left >= right

🔄 Reverse: Schritt für Schritt

1

left=0, right=4: Tausche arr[0] ↔ arr[4]

1
2
3
4
5
5
2
3
4
1
2

left=1, right=3: Tausche arr[1] ↔ arr[3]

5
2
3
4
1
5
4
3
2
1
3

left=2, right=2: left >= right → FERTIG!

5
4
3
2
1

🔄 Reverse im Code

#include <stdio.h>

int main()
{
    int arr[5] = {1, 2, 3, 4, 5};
    int n = 5;
    int left = 0;
    int right = n - 1;
    int temp;

    while (left < right)
    {
        /* Swap arr[left] und arr[right] */
        temp = arr[left];
        arr[left] = arr[right];
        arr[right] = temp;

        left++;   // Nach rechts bewegen
        right--;  // Nach links bewegen
    }

    printf("Umgekehrt: %d %d %d %d %d\n",
           arr[0], arr[1], arr[2], arr[3], arr[4]);

    return 0;
}
Umgekehrt: 5 4 3 2 1

❓ Warum left < right?

Gerade Anzahl (4 Elemente)

A
B
C
D

left=0, right=3 → Tausch

left=1, right=2 → Tausch

left=2, right=1 → STOP (2 > 1)

Ungerade Anzahl (5 Elemente)

A
B
C
D
E

left=0, right=4 → Tausch

left=1, right=3 → Tausch

left=2, right=2 → STOP (gleich!)

💡 Das mittlere Element (bei ungerader Anzahl) muss nicht getauscht werden - es bleibt an seiner Stelle!

🔄 Alternative: Reverse mit for-Schleife

#include <stdio.h>

int main()
{
    int arr[5] = {1, 2, 3, 4, 5};
    int n = 5;
    int temp;

    /* Nur bis zur Mitte iterieren! */
    for (int i = 0; i < n / 2; i++)
    {
        /* Tausche arr[i] mit arr[n-1-i] */
        temp = arr[i];
        arr[i] = arr[n - 1 - i];
        arr[n - 1 - i] = temp;
    }

    printf("Umgekehrt: %d %d %d %d %d\n",
           arr[0], arr[1], arr[2], arr[3], arr[4]);

    return 0;
}
💡 Trick: n - 1 - i ist der "gespiegelte" Index

🔢 Wie funktioniert n - 1 - i?

Formel: gespiegelter_index = n - 1 - i

Bei n = 5 (Array mit 5 Elementen):

i n - 1 - i Rechnung Tausch
0 4 5 - 1 - 0 = 4 arr[0] ↔ arr[4]
1 3 5 - 1 - 1 = 3 arr[1] ↔ arr[3]
2 2 5 - 1 - 2 = 2 Mitte (kein Tausch)
1[0]
2[1]
3[2]
4[3]
5[4]
← i wächst n-1-i schrumpft →
💡 Merke: Wenn i von links nach rechts läuft, läuft n-1-i automatisch von rechts nach links!

➡️ Elemente verschieben (Shift)

⬅️ Shift Left

Alle Elemente nach links

1
2
3
4
5

⬇️

2
3
4
5
?

➡️ Shift Right

Alle Elemente nach rechts

1
2
3
4
5

⬇️

?
1
2
3
4
⚠️ Achtung: Bei Shift geht ein Element "verloren" und ein Platz wird frei!

⬅️ Shift Left im Code

#include <stdio.h>

int main()
{
    int arr[5] = {1, 2, 3, 4, 5};
    int n = 5;

    /* Erstes Element sichern (geht sonst verloren) */
    int erstes = arr[0];

    /* Alle Elemente nach links verschieben */
    for (int i = 0; i < n - 1; i++)
    {
        arr[i] = arr[i + 1];  // Kopiere rechten Nachbarn
    }

    /* Optional: Erstes Element ans Ende (Rotation) */
    arr[n - 1] = erstes;

    printf("Nach Shift Left: %d %d %d %d %d\n",
           arr[0], arr[1], arr[2], arr[3], arr[4]);

    return 0;
}
Nach Shift Left: 2 3 4 5 1

⬅️ Shift Left: Schritt für Schritt

Array: {1, 2, 3, 4, 5} → erstes = 1

1 i=0: arr[0] = arr[1] → arr[0] = 2
2 i=1: arr[1] = arr[2] → arr[1] = 3
3 i=2: arr[2] = arr[3] → arr[2] = 4
4 i=3: arr[3] = arr[4] → arr[3] = 5
5 arr[4] = erstes → arr[4] = 1
Ergebnis: {2, 3, 4, 5, 1} - Rotation nach links!

➡️ Shift Right im Code

#include <stdio.h>

int main()
{
    int arr[5] = {1, 2, 3, 4, 5};
    int n = 5;

    /* Letztes Element sichern */
    int letztes = arr[n - 1];

    /* Von HINTEN nach vorne verschieben! */
    for (int i = n - 1; i > 0; i--)
    {
        arr[i] = arr[i - 1];  // Kopiere linken Nachbarn
    }

    /* Optional: Letztes Element an den Anfang (Rotation) */
    arr[0] = letztes;

    printf("Nach Shift Right: %d %d %d %d %d\n",
           arr[0], arr[1], arr[2], arr[3], arr[4]);

    return 0;
}
Nach Shift Right: 5 1 2 3 4

❓ Warum rückwärts bei Shift Right?

❌ Vorwärts (falsch)

for (i = 0; i < n-1; i++)
    arr[i+1] = arr[i];

{1,2,3,4,5} → {1,1,1,1,1}
Wert wird überschrieben bevor kopiert!

✅ Rückwärts (richtig)

for (i = n-1; i > 0; i--)
    arr[i] = arr[i-1];

{1,2,3,4,5} → {?,1,2,3,4}
Jeder Wert wird kopiert bevor überschrieben!

💡 Merke:
  • Shift Left: Von vorne nach hinten (i++)
  • Shift Right: Von hinten nach vorne (i--)

🪞 Was ist ein Palindrom?

Ein Palindrom liest sich vorwärts und rückwärts gleich!

✅ Palindrome

  • {1, 2, 3, 2, 1}
  • {5, 5, 5, 5}
  • {7}
  • {1, 2, 2, 1}

❌ Keine Palindrome

  • {1, 2, 3, 4, 5}
  • {1, 2, 3, 2, 5}
  • {5, 4, 3, 2, 1}
  • {1, 2, 3}

❓ Warum ist Palindrom-Prüfung wichtig?

Es geht nicht nur um Palindrome! Die Technik dahinter ist das Wichtige:

🎯 Die Zwei-Zeiger-Technik

  • Von beiden Enden gleichzeitig arbeiten
  • Elemente vergleichen oder manipulieren
  • Effizient: nur n/2 Durchläufe

💼 Echte Anwendungen

  • DNA-Analyse: Palindrom-Sequenzen in Genen
  • Datenvalidierung: Symmetrische Codes, Binärdaten
  • Textverarbeitung: Symmetrie erkennen

🧠 Hauptgrund: Coding-Interviews!

Palindrom-Aufgaben sind sehr beliebt in Bewerbungsgesprächen bei Tech-Firmen (Google, Amazon, etc.) - sie testen Ihr Verständnis der Zwei-Zeiger-Technik!

💡 Merke: Wer Palindrome versteht, kann auch: Arrays umkehren, Symmetrie prüfen, zwei sortierte Arrays zusammenführen, und vieles mehr!

🪞 Palindrom prüfen: Die Idee

Wieder die Zwei-Zeiger-Technik!

left
1[0]
2[1]
3[2]
2[3]
1[4]
right

💡 Algorithmus:

  1. Vergleiche arr[left] mit arr[right]
  2. Wenn ungleich → Kein Palindrom!
  3. Wenn gleich → left++, right--, weiter
  4. Wenn left >= right → Ist ein Palindrom!

🪞 Palindrom: Schritt für Schritt

Prüfe: {1, 2, 3, 2, 1}

1
left=0, right=4: arr[0]==arr[4]? → 1==1 ✅
2
left=1, right=3: arr[1]==arr[3]? → 2==2 ✅
3
left=2, right=2: left >= right → Palindrom!

Prüfe: {1, 2, 3, 4, 1}

1 left=0, right=4: arr[0]==arr[4]? → 1==1 ✅
2 left=1, right=3: arr[1]==arr[3]? → 2≠4 ❌ Kein Palindrom!

🪞 Palindrom im Code

#include <stdio.h>

int main()
{
    int arr[5] = {1, 2, 3, 2, 1};
    int n = 5;
    int left = 0;
    int right = n - 1;
    int istPalindrom = 1;  // Annahme: ist Palindrom

    while (left < right)
    {
        if (arr[left] != arr[right])
        {
            istPalindrom = 0;  // Kein Palindrom!
            break;
        }
        left++;
        right--;
    }

    if (istPalindrom)
        printf("Ist ein Palindrom!\n");
    else
        printf("Kein Palindrom.\n");

    return 0;
}

🔄 vs 🪞 Reverse und Palindrom

🔄 Reverse

while (left < right)
{
    /* TAUSCHEN */
    temp = arr[left];
    arr[left] = arr[right];
    arr[right] = temp;
    left++; right--;
}

Aktion: Elemente tauschen

🪞 Palindrom

while (left < right)
{
    /* VERGLEICHEN */
    if (arr[left] != arr[right])
    {
        istPalindrom = 0;
        break;
    }
    left++; right--;
}

Aktion: Elemente vergleichen

💡 Gleiche Struktur, andere Operation! Die Zwei-Zeiger-Technik ist sehr vielseitig.

🧠 Quiz: Array kopieren

Was gibt dieser Code aus?

int a[3] = {1, 2, 3};
int b[3];
for (int i = 0; i < 3; i++) b[i] = a[i];
a[0] = 99;
printf("%d", b[0]);

A) 99

B) 1

C) 0

D) Fehler

✅ Lösung: Array kopieren

Antwort B: 1

b ist eine echte Kopie - Änderungen an a beeinflussen b nicht!

Ablauf:

  1. a = {1, 2, 3}
  2. b wird kopiert: b = {1, 2, 3}
  3. a[0] wird auf 99 gesetzt: a = {99, 2, 3}
  4. b[0] ist immer noch 1!

🧠 Quiz: Reverse

Wie viele Swaps braucht man, um ein Array mit 6 Elementen umzukehren?

A) 6

B) 5

C) 3

D) 2

✅ Lösung: Reverse

Antwort C: 3

Wir tauschen nur bis zur Mitte: n/2 = 6/2 = 3 Swaps

Für {A, B, C, D, E, F}:

  • Swap 1: A ↔ F
  • Swap 2: B ↔ E
  • Swap 3: C ↔ D

→ {F, E, D, C, B, A} ✓

🧠 Quiz: Palindrom

Welches Array ist ein Palindrom?

A) {1, 2, 3, 4, 5}

B) {5, 4, 3, 4, 5}

C) {1, 2, 2, 1, 1}

D) {3, 3, 3}

✅ Lösung: Palindrom

Antwort B und D!

Prüfung:

  • A) {1,2,3,4,5} rückwärts = {5,4,3,2,1} ❌
  • B) {5,4,3,4,5} rückwärts = {5,4,3,4,5} ✅
  • C) {1,2,2,1,1} rückwärts = {1,1,2,2,1} ❌
  • D) {3,3,3} rückwärts = {3,3,3} ✅
💡 Tipp: Ein Array mit nur gleichen Werten ist immer ein Palindrom!

📋 Zusammenfassung: Array kopieren

/* Array kopieren */
for (int i = 0; i < n; i++)
{
    kopie[i] = original[i];
}
  • ✅ Element für Element kopieren
  • ✅ Kopie ist unabhängig vom Original
  • kopie = original funktioniert NICHT!

📋 Zusammenfassung: Reverse

/* Array umkehren mit Zwei-Zeiger-Technik */
int left = 0, right = n - 1;
while (left < right)
{
    /* Swap */
    int temp = arr[left];
    arr[left] = arr[right];
    arr[right] = temp;
    left++;
    right--;
}
  • ✅ Zwei Zeiger: einer vorne, einer hinten
  • ✅ Nutzt Swap aus VL 9
  • ✅ Nur n/2 Swaps nötig

📋 Zusammenfassung: Shift

⬅️ Shift Left

int erstes = arr[0];
for (i = 0; i < n-1; i++)
    arr[i] = arr[i+1];
arr[n-1] = erstes; // optional

Von vorne nach hinten (i++)

➡️ Shift Right

int letztes = arr[n-1];
for (i = n-1; i > 0; i--)
    arr[i] = arr[i-1];
arr[0] = letztes; // optional

Von hinten nach vorne (i--)

📋 Zusammenfassung: Palindrom

/* Palindrom prüfen */
int left = 0, right = n - 1, istPalindrom = 1;
while (left < right)
{
    if (arr[left] != arr[right])
    {
        istPalindrom = 0;
        break;
    }
    left++;
    right--;
}
  • ✅ Gleiche Struktur wie Reverse
  • ✅ Statt Tauschen: Vergleichen
  • ✅ Bei Ungleichheit sofort abbrechen