Хотя сложность определения длины сжатого текста должна составлять O(n)
(с использованием простого len
), сложность по времени для завершения кодирования должна составлять O(nlog(n))
.Алгоритм выглядит следующим образом:
t1 = FullTree
for each character in uncompressed input do: #O(n)
tree_lookup(t1, character) #O(log(n))
Цикл по несжатому входу равен O(n)
, тогда как поиск узла в сбалансированном двоичном дереве равен O(log(n))
(O(n)
наихудший случай или нет).Таким образом, результат равен n*O(log(n)) => O(nlog(n))
.Также обратите внимание, что O(log 2n)
для сложности поиска точен, так как по правилам логарифмов может быть упрощен до O(log(2)+log(n)) => O(k + log(n)), for some constant k.
Однако, поскольку Big-O проверяет только худшие приближения, O(k+log(n)) => O(log(n))
.
Вы можете улучшить свое двоичное дерево, создав более простой поиск в своем дереве:
from collections import Counter
class Tree:
def __init__(self, node1, node2):
self.right = node1
self.left = node2
self.value = sum(getattr(i, 'value', i[-1]) for i in [node1, node2])
def __contains__(self, _node):
if self.value == _node:
return True
return _node in self.left or _node in self.right
def __lt__(self, _node): #needed to apply sorted function
return self.value < getattr(_node, 'value', _node[-1])
def lookup(self, _t, path = []):
if self.value == _t:
return ''.join(map(str, path))
if self.left and _t in self.left:
return ''.join(map(str, path+[0])) if isinstance(self.left, tuple) else self.left.lookup(_t, path+[0])
if self.right and _t in self.right:
return ''.join(map(str, path+[1])) if isinstance(self.right, tuple) else self.right.lookup(_t, path+[1])
def __getitem__(self, _node):
return self.lookup(_node)
s = list('abaccab')
r = sorted(Counter(s).items(), key=lambda x:x[-1])
while len(r) > 1:
a, b, *_r = r
r = sorted(_r+[Tree(a, b)])
compressed_text = ''.join(r[0][i] for i in s)
Вывод:
'10110000101'