C++ 编写一个将文本作为输入的程序,并生成一个复制该文本的程序

C++ 编写一个将文本作为输入的程序,并生成一个复制该文本的程序,c++,algorithm,compression,data-compression,lossless-compression,C++,Algorithm,Compression,Data Compression,Lossless Compression,最近我遇到了一个很好的问题,这个问题很容易理解,也很难找到解决的方法。问题是: 编写一个程序,从输入中读取文本并打印其他文本 程序输出。如果我们编译并运行打印的程序,它必须 输出原始文本 输入文本应该相当大(超过10000个字符) 唯一(也是非常严格的)要求是存档文件(即打印的程序)的大小必须严格小于原始文本的大小。这就产生了不可能的显而易见的解决方案,比如 std::string s; /* read the text into s */ std::cout << "#includ

最近我遇到了一个很好的问题,这个问题很容易理解,也很难找到解决的方法。问题是:

编写一个程序,从输入中读取文本并打印其他文本 程序输出。如果我们编译并运行打印的程序,它必须 输出原始文本

输入文本应该相当大(超过10000个字符)

唯一(也是非常严格的)要求是存档文件(即打印的程序)的大小必须严格小于原始文本的大小。这就产生了不可能的显而易见的解决方案,比如

std::string s;
/* read the text into s */
std::cout << "#include<iostream> int main () { std::cout<<\"" << s << "\"; }";
std::字符串s;
/*把课文读成s*/

std::cout您所描述的本质上是一个用于创建自解压zip存档的程序,与常规自解压zip存档将原始数据写入文件而不是stdout略有不同。如果你想自己制作这样一个程序,有很多压缩算法的实现,或者你可以自己实现(gzip使用的算法)。“外部”程序必须压缩输入数据并输出用于解压缩的代码,并将压缩数据嵌入该代码中

伪代码:

string originalData;
cin >> originalData;
char * compressedData = compress(originalData);
cout << "#include<...> string decompress(char * compressedData) { ... }" << endl;
cout << "int main() { char compressedData[] = {";
(output the int values of the elements of the compressedData array)
cout << "}; cout << decompress(compressedData) << endl; return 0; }" << endl;
字符串原始数据;
cin>>原始数据;
char*compressedData=压缩(原始数据);

很遗憾,这样的程序并不存在

要知道为什么会这样,我们需要做一点数学。首先,让我们计算长度为n的二进制字符串的数量。每个位都可以是0或1,这为每个位提供了两种选择之一。由于每比特和n比特有两种选择,因此总共有2n个长度为n的二进制字符串

现在,假设我们想要构建一个压缩算法,它总是将长度为n的位字符串压缩为长度小于n的位字符串。为了使其工作,我们需要计算长度小于n的不同字符串的数量。这是由长度为0的位串的数量,加上长度为1的位串的数量,加上长度为2的位串的数量,等等,一直到n-1。这个总数是

20+21+22+…+2n-1

通过一点数学运算,我们可以得出这个数字等于2n-1。换句话说,长度小于n的位字符串的总数比长度为n的位字符串的数量小一个

但这是一个问题。为了使无损压缩算法始终将长度为n的字符串映射到长度最多为n-1的字符串,我们必须有某种方式将长度为n的每个位字符串与某个较短的位字符串关联,这样长度为n的两个位字符串就不会与同一个较短的位流关联。通过这种方式,我们可以通过将字符串映射到相关的较短字符串来压缩字符串,也可以通过反转映射来解压缩字符串。限制长度为n的两个位字符串不能映射到同一个较短的字符串,这就是无损的原因——如果两个长度为n的位字符串映射到同一个较短的位字符串,那么当解压该字符串时,就无法知道我们压缩了两个原始位字符串中的哪一个

这就是我们遇到问题的地方。由于有2n个长度为n的不同位串,并且只有2n-1个较短的位串,因此我们无法将长度为n的每个位串与一些较短的位串配对,而不将至少两个长度为n的位串分配给同一较短的字符串。这意味着,无论我们多么努力,无论我们多么聪明,无论我们的压缩算法多么有创意,都有一个严格的数学限制,即我们不能总是将文本缩短

那么,这是如何映射到您的原始问题的呢?如果我们得到一个长度至少为10000的文本字符串,并且需要输出一个较短的程序来打印它,那么我们必须有某种方法将210000个长度为10000的字符串中的每一个映射到长度小于10000的210000-1字符串。该映射还有一些其他属性,即我们总是必须生成一个有效的程序,但这与此无关——根本没有足够短的字符串。因此,你想要解决的问题是不可能的

也就是说,我们可能会得到一个程序,它可以将长度为10000的字符串中除一个以外的所有字符串压缩为较短的字符串。事实上,我们可能会找到一种压缩算法来实现这一点,这意味着在概率为1-210000的情况下,任何长度为10000的字符串都可以被压缩。这是一个很高的概率,如果我们在整个宇宙的生命周期中不断地挑选弦,我们几乎肯定永远不会猜到一个坏弦


为了进一步阅读,信息论中有一个概念叫做,它是生成给定字符串所需的最小程序的长度。一些字符串很容易压缩(例如,abababab),而其他字符串则不容易压缩(例如,sdkjhdbvljkhwqe0235089)。存在被调用的字符串,该字符串不可能压缩到任何较小的空间中。这意味着任何打印该字符串的程序必须至少与给定字符串一样长。为了更好地介绍科尔莫戈罗夫复杂性,您可能想看看迈克尔·西普瑟(Michael Sipser)的“计算理论导论,第二版”第6章,该章对一些较酷的结果进行了极好的概述。为了更为深入和深入的阅读,考虑阅读“信息理论的要素”第14章。
希望这有帮助

如果我们谈论的是ASCII文本

我认为这实际上是可以做到的,而且我认为文本大小超过10000个字符的限制是有原因的(给你一个编码空间)

这里的人说
ASCII values    characters
0x00 .. 0x08    NUL, (other control codes)                                  
0x09 .. 0x0D    (white-space control codes: '\t','\f','\v','\n','\r')
0x0E .. 0x1F    (other control codes)
... rest of printable characters