Die Antwort auf diese Frage hängt genau davon ab, was Sie lernen möchten.
Python und Ruby
Hochsprachen wie Python und Ruby werden häufig empfohlen, da sie Hochstufensprachen sind und die Syntax gut lesbar ist. Diese Sprachen haben jedoch alle Abstraktionen für die gemeinsamen Datenstrukturen. Nichts hindert Sie daran, Ihre eigenen Versionen als Lernübung zu implementieren, aber Sie stellen möglicherweise fest, dass Sie Datenstrukturen auf hoher Ebene auf anderen Datenstrukturen auf hoher Ebene aufbauen, was nicht unbedingt nützlich ist.
Außerdem sind Ruby und Python dynamisch typisierte Sprachen. Dies kann gut sein, aber es kann auch für den Anfänger verwirrend sein und es kann (anfangs) schwieriger sein, Fehler zu erkennen, da sie normalerweise erst zur Laufzeit sichtbar werden.
C.
C ist am anderen Extrem. Es ist gut, wenn Sie wirklich einfache Details wie die Verwaltung des Speichers erfahren möchten, aber die Speicherverwaltung ist plötzlich eine wichtige Überlegung, wie bei der korrekten Verwendung von malloc () / free (). Das kann ablenken. Außerdem ist C nicht objektorientiert. Das ist keine schlechte Sache, aber einfach erwähnenswert.
C ++
C ++ wurde erwähnt. Wie ich im Kommentar sagte, halte ich dies für eine schreckliche Wahl. C ++ ist selbst bei einfacher Verwendung schrecklich kompliziert und hat eine lächerliche Menge an "Fallstricken". Außerdem hat C ++ keine gemeinsame Basisklasse. Dies ist wichtig, da Datenstrukturen wie Hash-Tabellen von einer gemeinsamen Basisklasse abhängen. Sie könnten eine Version für eine nominelle Basisklasse implementieren, diese ist jedoch etwas weniger nützlich.
Java
Java wurde ebenfalls erwähnt. Viele Leute hassen Java gerne und es ist wahr, dass die Sprache extrem ausführlich ist und einige der moderneren Sprachfunktionen (z. B. Abschlüsse) fehlen, aber nichts davon ist wirklich wichtig. Java ist statisch typisiert und verfügt über eine Garbage Collection. Dies bedeutet, dass der Java-Compiler viele Fehler abfängt, die dynamisch typisierte Sprachen (bis zur Laufzeit) nicht haben, und dass Segmentierungsfehler nicht behoben werden (was nicht heißt, dass Sie in Java keinen Speicher verlieren können; offensichtlich können Sie dies). Ich denke, Java ist eine gute Wahl.
C #
C # Die Sprache ist wie eine modernere Version von Java. Wie Java ist es eine verwaltete (durch Müll gesammelte) kompilierte Zwischensprache, die auf einer virtuellen Maschine ausgeführt wird. Alle anderen hier aufgeführten Sprachen außer C / C ++ werden ebenfalls auf einer virtuellen Maschine ausgeführt, aber Python, Ruby usw. werden direkt interpretiert und nicht zu Bytecode kompiliert.
C # hat im Grunde die gleichen Vor- und Nachteile wie Java.
Haskell (etc)
Schließlich haben Sie funktionale Sprachen: Haskell, OCaml, Scheme / Lisp, Clojure, F # usw. Diese denken über alle Probleme auf eine ganz andere Art und Weise nach und sind es wert, irgendwann gelernt zu werden, aber es kommt wieder darauf an, was Sie lernen möchten: funktionale Programmierung oder Datenstrukturen? Ich würde mich daran halten, jeweils eine Sache zu lernen, anstatt das Thema zu verwirren. Wenn Sie irgendwann eine funktionale Sprache lernen (was ich empfehlen würde), ist Haskell eine sichere und gute Wahl.
Mein Rat
Wählen Sie Java oder C #. Beide verfügen über kostenlose, hervorragende IDEs (Eclipse, Netbeans und IntelliJ Community Edition für Java, Visual Studio Express für C #, Visual Studio Community Edition), mit denen das Schreiben und Ausführen von Code zum Kinderspiel wird. Wenn Sie keine native Datenstruktur verwenden, die komplexer als ein Array ist, und jedes Objekt, das Sie selbst schreiben, lernen Sie im Grunde das Gleiche wie in C / C ++, ohne jedoch den Speicher tatsächlich verwalten zu müssen.
Lassen Sie mich erklären: Die Größe einer erweiterbaren Hash-Tabelle muss geändert werden, wenn genügend Elemente hinzugefügt werden. In jeder Implementierung bedeutet dies, dass beispielsweise die Größe der Hintergrunddatenstruktur (normalerweise ein Array) verdoppelt und die vorhandenen Elemente kopiert werden. Die Implementierung ist grundsätzlich in allen zwingenden Sprachen gleich, aber in C / C ++ müssen Sie mit Segmentierungsfehlern umgehen, wenn Sie etwas nicht richtig zuweisen oder freigeben.
Python oder Ruby (es spielt keine Rolle, welche) wären meine nächste Wahl (und sehr nahe an den beiden anderen), nur weil die dynamische Eingabe zunächst problematisch sein könnte.