计算二进制字符串的Lempel-Ziv(LZ)复杂度(也称序列复杂度)

时间:2011-02-09 15:09:44

标签: algorithm binary compression complexity-theory sequence

我需要计算二进制字符串的LZ复杂度。 LZ复杂度是从开始到结束查看流时遇到的差异子串的数量。举个例子:

s = 1001111011000010

在不同的子串中标记序列复杂度c(s)= 6: s = 1/0/101 / 1110/1100/20010 /

有人可以指导我找到一个简单的解决方案吗?我确信这个众所周知的问题应该有一些非常简单的实现,但我很难找到它们。可以通过构造后缀树或类似的东西来完成。如果是,究竟如何?我该怎么办?

任何人都知道要完成任务的任何c / c ++源代码吗?

提前感谢。

澄清答案中建议的树的构造。这棵树看起来像这样吗?

         o
       /   \
      o     o
     / \   / \
    o   o o   o
       /     /
      o     o

7 个答案:

答案 0 :(得分:1)

下面是如何使用树计算LZ复杂度的快速示例。为方便起见 - 我的;不是你的 - 这段代码实现了一个固定大小的预分配树,并且是为什么void *指针难以使用且难以维护的一个主要例子。按原样输入此代码,您的讲师可能会对您开枪:)

#include <stdlib.h>
#include <stdio.h>

int LZComplexity(char *p_binarySequence, int p_maxTreeNodes)
{
 void **patternTree;
 void **currentNode;
 void **nextFreeNode;
 int nodeCount;
 int sequenceIndex;
 int currentDigit;

 nodeCount = 0;
 patternTree = malloc(sizeof(void*) * (p_maxTreeNodes << 1));
 currentNode = patternTree;
 nextFreeNode = patternTree + (sizeof(void*) << 1);
 currentNode[0] = NULL;
 currentNode[1] = NULL;
 sequenceIndex = 0;

 while (p_binarySequence[sequenceIndex])
 {
  currentDigit = p_binarySequence[sequenceIndex] - 48;
  if (NULL == currentNode[currentDigit])
  {
   currentNode[currentDigit] = nextFreeNode;
   nextFreeNode[0] = NULL;
   nextFreeNode[1] = NULL;
   nextFreeNode += (sizeof(void*) << 1);
   currentNode = patternTree;
   nodeCount++;
  }
  else
  {
   currentNode = currentNode[currentDigit];
  }
  sequenceIndex++;
 }

 free(patternTree);
 return nodeCount;
}


int main(int argc, char *argv[])
{
 printf("%u\n", LZComplexity("10100101001011101011", 1000));
 return 0;
}

答案 1 :(得分:1)

1 0 01 11 10 110 00 010
序列的复杂性是8,因为分区是8而不是6 - 1/0/01/11/10/110/00/010

答案 2 :(得分:1)

@Arash和@Sanchit Gupta:你可能会对LZ76复杂性和LZ78复杂性感到困惑。 Arash所指的是LZ76的复杂性,另一个是LZ78的复杂性。你可以参考文章“通过Lempel-Ziv复杂性估算穗列车的熵率”一节。

答案 3 :(得分:1)

Guillermo Valle的实现产生正确的答案(与当前的Wikipedia代码不同)。

例如,

0001的复杂度为2:0 001

010的复杂度为3:0 1 0

答案 4 :(得分:0)

创建一个二叉树,其中左边是0,右边是1.对于每个位,尝试在树中查找序列。如果它在那里,连接下一位,冲洗,重复。如果不存在,请将其添加到树中继续。 LZ Complexity是树中路径的总数(不仅仅是#叶节点)。

顺便问一下,这是homework吗?

答案 5 :(得分:0)

这应该是Python中的技巧(来自:Kaspar,F。Schuster,H。易于计算的时空模式复杂度。物理评论A,第36卷,第2页,p 842。)

#!/usr/bin/python


def lz_complexity(s):
    i, k, l = 0, 1, 1
    k_max = 1
    n = len(s) - 1
    c = 1
    while True:
        if s[i + k - 1] == s[l + k - 1]:
            k = k + 1
            if l + k >= n - 1:
                c = c + 1
                break
        else:
            if k > k_max:
               k_max = k
            i = i + 1
            if i == l:
                c = c + 1
                l = l + k_max
                if l + 1 > n:
                    break
                else:
                    i = 0
                    k = 1
                    k_max = 1
            else:
                k = 1
    return c


def main():
    lz = lz_complexity('1001111011000010')
    assert lz == 6 
    print lz


if __name__ == '__main__':

    main()

答案 6 :(得分:0)

这可能与您相关。它是并行实现 计算LZ复杂度的算法LZMP 在CUDA中并在nVidia GPU上运行。

http://www.ariel.ac.il/sites/ratsaby/Code/LZMP.zip