我认为一个高效的数据库将是一个修改过的trie,具有双向链接[可以从叶子到根重构单词],并且每个终止节点将有额外的“值”字段。
您还需要一个multimap [即一个map,在其中每个值都是一组地址]。
键将按树形排列,而值集将基于哈希。
[在Java中,它应该类似于TreeMap<Integer,HashSet<Node>>
]
伪代码:[好吧,非常伪...它只显示了每个操作的一般思想]。
Insert(key):
1. Insert a word into the trie
2. add the value `1` to the terminating node.
3. add the terminating field to the multimap [i.e. map.add(1,terminating_node_address)]
Increment(key):
1. read the word in the trie, and store the value from the terminating node as temp.
2. delete the entree (temp,terminating_node_address) from the multimap.
3. insert the entree (temp+1,terminating_node_address) to the multimap.
4. increase the value of the terminating node's address by 1.
Find(key):
1. find the terminating node for the key in the trie, return its value.
Select(part_of_key):
1. go to the last node you can reach with part_of_key.
2. from this node: do BFS and retrieve all possible words [store them in an empty set you will later return].
Max(i):
1. find the i'th biggest element key in the multimap.
2. choose an arbitrary address, and return get the relevant terminating word node.
3. build the string by following the uplinks to the root, and return it.
复杂度:
假设有n
个字符串,最大值为k
,每个字符串的长度为S
。
插入:O(S) [trie插入是O(S)]。将地图中最小的元素(1)缓存,因此可以在O(1)的时间内访问。
递增:O(S+logk):在Trie中查找字符串需要O(S),在哈希集合中删除元素需要O(1),查找树中的下一个元素也是O(logk) [实际上可以是O(1),基于skip-list的映射],插入值需要O(1)。注意,通过将节点链接到地图中的相关键,复杂度甚至可以提高到O(S),因为实际上不需要搜索。
查找:O(S):在trie中查找并返回值。
选择:O(S*n):在最坏的情况下,您需要检索所有元素,这迫使您遍历整个trie以查找所有单词。
最大值:O(logk+S):在排序地图中查找键,重构单词。
注意,在这里,我假设对于find(i),您想要第i个不同的最大元素。如果不是这种情况,您需要稍微修改一下集合,并使用允许重复键的multimap [而不是将set作为值]。这将使所有基于树的操作都是O(logn)而不是O(logk),在我看来仍然是高效的...