Algorithmen und Datenstrukturen in Java: vom Anfänger zum erfahrenen Entwickler
Java ist eine der beliebtesten Programmiersprachen der Welt, und die Kenntnis von Algorithmen und Datenstrukturen ist eine zwingende Fähigkeit für jeden Java-Entwickler. Unabhängig davon, ob Sie sich auf ein Vorstellungsgespräch in einem großen IT-Unternehmen vorbereiten oder einfach nur effizienteren Code schreiben möchten, das Verständnis grundlegender Datenstrukturen und Algorithmen in Java wird Ihnen neue Möglichkeiten eröffnen. In diesem Artikel werden wir die wichtigsten Konzepte behandeln, die jeder Entwickler kennen sollte, und ihre Implementierung in Java mit praktischen Beispielen zeigen.
1. Grundlegende Datenstrukturen in Java
Datenstrukturen sind Möglichkeiten zur Organisation und Speicherung von Daten. Java bietet eine umfangreiche Sammlung integrierter Collections, aber das Verständnis, wie sie "unter der Haube" funktionieren, hilft Ihnen, die richtigen Architekturentscheidungen zu treffen.
1.1 Arrays
Ein Array ist die einfachste Datenstruktur, die Elemente desselben Typs in einem zusammenhängenden Speicherbereich speichert. In Java haben Arrays eine feste Länge.
// Deklaration und Initialisierung eines Arraysint[] numbers = new int[5];numbers[0] = 10;numbers[1] = 20;numbers[2] = 30;numbers[3] = 40;numbers[4] = 50;
// Oder direkt mit WertenString[] fruits = {"Apfel", "Banane", "Orange"};
// Durchlaufen eines Arraysfor (int i = 0; i < fruits.length; i++) { System.out.println(fruits[i]);}
// Verbesserte for-each-Schleifefor (String fruit : fruits) { System.out.println(fruit);}Vorteile: schneller Zugriff über Index (O(1)).
Nachteile: feste Größe, aufwändiges Einfügen und Löschen von Elementen.
1.2 Verkettete Listen (LinkedList)
Eine verkettete Liste besteht aus Knoten, die jeweils Daten und einen Verweis auf den nächsten (oder vorherigen) Knoten enthalten. In Java gibt es die integrierte Implementierung java.util.LinkedList.
import java.util.LinkedList;
LinkedList<String> list = new LinkedList<>();list.add("Erster");list.add("Zweiter");list.addFirst("Nullter"); // Einfügen am Anfanglist.addLast("Dritter"); // Einfügen am Ende
System.out.println("Erstes Element: " + list.getFirst());System.out.println("Letztes Element: " + list.getLast());System.out.println("Größe der Liste: " + list.size());
// Löschen eines Elementslist.remove("Zweiter");Vorteile: schnelles Einfügen und Löschen am Anfang/Ende der Liste (O(1)).
Nachteile: langsamer Zugriff über Index (O(n)).
1.3 Stack
Ein Stack arbeitet nach dem LIFO-Prinzip (Last In, First Out) – zuletzt hinein, zuerst heraus. Java bietet die Klasse Stack und das Interface Deque für die Arbeit mit einem Stack.
import java.util.Stack;
Stack<Integer> stack = new Stack<>();
// Hinzufügen von Elementenstack.push(10);stack.push(20);stack.push(30);
// Anzeigen des obersten Elements ohne EntfernenSystem.out.println("Oberstes Element: " + stack.peek()); // 30
// Entfernen des obersten Elementsint top = stack.pop();System.out.println("Entfernt: " + top); // 30System.out.println("Neues oberstes Element: " + stack.peek()); // 20
// Prüfen, ob der Stack leer istSystem.out.println("Ist der Stack leer? " + stack.isEmpty()); // falseEin Stack wird häufig verwendet, um die Korrektheit von Klammerausdrücken zu prüfen, Bäume zu durchlaufen und "Zurück/Vorwärts"-Algorithmen in Browsern zu implementieren.
1.4 Queue
Eine Queue arbeitet nach dem FIFO-Prinzip (First In, First Out) – zuerst hinein, zuerst heraus. In Java wird eine Queue über das Interface Queue und die Klasse LinkedList implementiert.
import java.util.LinkedList;import java.util.Queue;
Queue<String> queue = new LinkedList<>();
// Hinzufügen am Ende der Queuequeue.offer("Kunde 1");queue.offer("Kunde 2");queue.offer("Kunde 3");```