Ответ на этот вопрос зависит от того, что именно вы хотите узнать.
Python и Ruby
Часто предлагаются языки высокого уровня, такие как Python и Ruby, потому что они высокоуровневые и их синтаксис вполне читаем. Однако все эти языки имеют абстракции для общих структур данных. Ничто не мешает вам реализовать свои собственные версии в качестве обучающего упражнения, но вы можете обнаружить, что строите структуры данных высокого уровня поверх других структур данных высокого уровня, что не обязательно полезно.
Кроме того, Ruby и Python - это языки с динамической типизацией. Это может быть хорошо, но также может сбивать с толку новичка, и может быть труднее (изначально) отловить ошибки, поскольку они обычно не проявляются до времени выполнения.
C
C - другая крайность. Это хорошо, если вы хотите изучить действительно низкоуровневые детали, такие как управление памятью, но управление памятью внезапно становится важным соображением, например, при правильном использовании malloc () / free (). Это может отвлекать. Кроме того, C не является объектно-ориентированным. Это неплохо, но стоит просто отметить.
C ++
Был упомянут C ++. Как я уже сказал в комментарии, я считаю, что это ужасный выбор. C ++ ужасающе сложен даже в простом использовании и имеет смехотворное количество "ошибок". Кроме того, C ++ не имеет общего базового класса. Это важно, потому что структуры данных, такие как хеш-таблицы, зависят от наличия общего базового класса. Вы можете реализовать версию для номинального базового класса, но это будет немного менее полезно.
Ява
Также упоминалась Java. Многим людям нравится ненавидеть Java, и это правда, что язык чрезвычайно многословен и лишен некоторых более современных языковых функций (например, закрытий), но на самом деле все это не имеет значения. Java статически типизирована и имеет сборку мусора. Это означает, что компилятор Java перехватит множество ошибок, которые не будут обнаруживаться в динамически типизированных языках (до времени выполнения), и не будет иметь дело с ошибками сегментации (это не означает, что вы не можете утечки памяти в Java; очевидно, что вы можете). Я считаю, что Java - отличный выбор.
C #
C # язык похож на более современную версию Java. Как и Java, это управляемый (сборщик мусора) промежуточный компилируемый язык, работающий на виртуальной машине. Все остальные языки, перечисленные здесь, кроме C / C ++, также работают на виртуальной машине, но Python, Ruby и т. Д. Интерпретируются напрямую, а не компилируются в байт-код.
В основном C # имеет те же плюсы и минусы, что и Java.
Haskell (и т. Д.)
Наконец, у вас есть функциональные языки: Haskell, OCaml, Scheme / Lisp, Clojure, F # и т. Д. Они думают обо всех проблемах по-разному, и их стоит изучить в какой-то момент, но опять же все сводится к тому, что вы хотите изучить: функциональное программирование или структуры данных? Я бы предпочел изучать одну вещь за раз, чем запутывать проблему. Если вы в какой-то момент выучите функциональный язык (что я бы порекомендовал), Haskell - безопасный и прекрасный выбор.
Мой совет
Выберите Java или C #. У обоих есть бесплатные отличные IDE (Eclipse, Netbeans и IntelliJ Community Edition для Java, Visual Studio Express для C #, Visual Studio Community Edition), которые упрощают написание и выполнение кода. Если вы не используете собственную структуру данных, более сложную, чем массив, и любой объект, который вы пишете, вы узнаете в основном то же самое, что и в C / C ++, но без необходимости фактически управлять памятью.
Позвольте мне объяснить: размер расширяемой хеш-таблицы необходимо изменить, если добавлено достаточное количество элементов. В любой реализации это будет означать что-то вроде удвоения размера резервной структуры данных (обычно массива) и копирования существующих элементов. Реализация в основном одинакова для всех императивных языков, но в C / C ++ вы должны иметь дело с ошибками сегментации, когда вы не выделяете или не освобождаете что-то правильно.
Python или Ruby (неважно, какой именно) были бы моим следующим выбором (и очень близким к двум другим) только потому, что сначала динамическая типизация могла быть проблематичной.