Чтобы ответить на часть вопроса о типах данных: в общем смысле, тип данных, наиболее подходящий для поиска вещей за время O (log n) (при сохранении производительности O (1) для вставок и удалений!), Представляет собой двоичное дерево.Вы можете найти что-то в этом, приняв ряд лево-правых решений, что очень похоже на то, как вы выполняете бинарный поиск в линейном списке, но (IMO) немного более концептуально интуитивно.Судя по тому, что я мало знаю о Python, двоичные деревья, похоже, не входят в стандартную библиотеку языка.Для вашего приложения, вероятно, было бы бесполезно включать реализацию только для этой цели.
Наконец, и двоичные деревья, и двоичный поиск в отсортированном списке позволят вам сократить поиск на один шаг:не нужно искать ключевой элемент и затем возвращаться к его предшественнику.Вместо этого на каждом шаге сравнения, если вы встретите значение ключа, действуйте так, как если бы оно было слишком большим.Это приведет к тому, что ваш поиск закончится на следующем меньшем значении.Сделанный аккуратно, это также может помочь с проблемой «почти равное значение с плавающей запятой», упомянутой bart.