#data-structures #haskell #map #functional-programming
#структуры данных #haskell #словарь #функциональное программирование
Вопрос:
Вполне может быть, что ответ на этот вопрос очевиден и громкий «такой вещи не существует», но я попробую: существует ли функциональная структура данных, подобная карте, которая более эффективна, чем стандартная карта, когда ключи имеют произвольный, часто очень большой, размер?
Для большей конкретности рассмотрим тип Haskell
(Ord k) => Map [k] v
в которой поиск может занять очень много времени, если списки необходимо сравнивать до глубокого уровня. Я думаю, о хешировании также не может быть и речи из-за произвольной длины списков. Я все еще не могу отделаться от мысли, что там могла бы быть умная структура данных.
Комментарии:
1. Я подозреваю, что использование вектора (векторного пакета) вместо списка в качестве ключа было бы огромным выигрышем для этой цели.
Ответ №1:
О хешировании не может быть и речи? У ключевой структуры нет префикса, который можно было бы эффективно вычислить?
Если нет, как насчет hashmap? Возьмите очень большой ключ, уменьшите его до чего-то очень маленького, используйте это как индекс в структуре.
Комментарии:
1. Ах, вы правы. Думаю, я неправильно думал о коллизиях хэшей для произвольно больших данных. Спасибо.
Ответ №2:
Три?
Если у вас есть два почти идентичных длинных ключа, Map сравнит их оба с самого начала, но trie сравнит только те суффиксы, которые еще не были устранены предыдущими сравнениями (если вы понимаете, что я имею в виду). Таким образом, trie в этой ситуации был бы более экономичным по времени.
Попытки можно оптимизировать различными способами, и вы также можете захотеть взглянуть на троичные деревья.
Ответ №3:
Вот один:
module ListMap where
import Data.Map as M
data ListMap k v = ListMap { ifEmpty :: Maybe v, ifFull :: Maybe k (ListMap k v) }
empty :: ListMap k v
empty = ListMap Nothing M.empty
singleton :: [k] -> v -> ListMap k v
singleton [] v = ListMap.empty { ifEmpty = Just v }
singleton (k:ks) v = ListMap.empty { ifFull = M.singleton k (ListMap.singleton ks v) }
lookup :: Ord k => [k] -> ListMap k v -> Maybe v
lookup [] lm = ifEmpty lm
lookup (k:ks) lm = M.lookup k (ifFull lm) >>= ListMap.lookup ks
insert :: Ord k => [k] -> v -> ListMap k v -> ListMap k v
insert [] v lm = lm { ifEmpty = Just v }
insert (k:ks) v lm = lm { ifFull = M.alter (Just . insertion) k (ifFull lm) }
where insertion = maybe (ListMap.singleton ks v) (ListMap.insert ks v)
По сути, это создает дерево префиксов для элементов списка, поэтому вы сравниваете только по мере необходимости.