C++ Lempel-Ziv-Welch算法的译码问题

C++ Lempel-Ziv-Welch算法的译码问题,c++,algorithm,compression,C++,Algorithm,Compression,我必须实现LZW算法,但我发现解码部分有一些问题。 我认为代码是正确的,因为它适用于我在web上找到的一个示例:如果我按照以下方式初始化字典 m_dictionary.push_back("a"); m_dictionary.push_back("b"); m_dictionary.push_back("d"); m_dictionary.push_back("n"); m_dictionary.push_back("_"); 我的输入文件中有字符串banana\u bandana,我得到以下

我必须实现LZW算法,但我发现解码部分有一些问题。 我认为代码是正确的,因为它适用于我在web上找到的一个示例:如果我按照以下方式初始化字典

m_dictionary.push_back("a");
m_dictionary.push_back("b");
m_dictionary.push_back("d");
m_dictionary.push_back("n");
m_dictionary.push_back("_");
我的输入文件中有字符串
banana\u bandana
,我得到以下结果:

compressed.txt
:1036045328

decompressed.txt
:香蕉

但是,如果我用所有255个ASCII字符初始化字典,解码过程就会失败。我认为问题在于代码中使用的位数,因为当我要解码时,我总是逐字符(8位)读取输入文件,而不是正确的位数,我猜

下面是我实现该算法的代码:

template <class T>
size_t toUnsigned(T t) {
  std::stringstream stream;
  stream << t;
  size_t x;
  stream >> x;
  return x;
}

bool LempelZivWelch::isInDictionary(const std::string& entry) {
  return (std::find(m_dictionary.begin(), m_dictionary.end(), entry) != m_dictionary.end());
}

void LempelZivWelch::initializeDictionary() {
  m_dictionary.clear();
  for (int i = 0; i < 256; ++i)
    m_dictionary.push_back(std::string(1, char(i)));
}

void LempelZivWelch::addEntry(std::string entry) {
  m_dictionary.push_back(entry);
}

size_t LempelZivWelch::encode(char *data, size_t dataSize) {    
  initializeDictionary();

  std::string s;
  char c;

  std::ofstream file;
  file.open("compressed.txt", std::ios::out | std::ios::binary);

  for (size_t i = 0; i < dataSize; ++i) {
    c = data[i];

    if(isInDictionary(s + c))
      s = s + c;
    else {
      for (size_t j = 0; j < m_dictionary.size(); ++j)
        if (m_dictionary[j] == s) {
          file << j;
          break;
        }

      addEntry(s + c);
      s = c;
    }
  }

  for (size_t j = 0; j < m_dictionary.size(); ++j)
    if (m_dictionary[j] == s) {
      file << j;
      break;
    }

  file.close();

  return dataSize;
}

size_t LempelZivWelch::decode(char *data, size_t dataSize) {    
  initializeDictionary();

  std::string entry;
  char c;
  size_t previousCode, currentCode;

  std::ofstream file;
  file.open("decompressed.txt", std::ios::out | std::ios::binary);

  previousCode = toUnsigned(data[0]);

  file << m_dictionary[previousCode];

  for (size_t i = 1; i < dataSize; ++i) {
    currentCode = toUnsigned(data[i]);

    entry = m_dictionary[currentCode];
    file << entry;
    c = entry[0];
    addEntry(m_dictionary[previousCode] + c);
    previousCode = currentCode;
  }

  file.close();

  return dataSize;
}
我猜解码问题在于将输入文件作为
char
数组读取和/或将
char
s作为
size\u t
写入压缩文件


提前谢谢

看起来您正在将字典索引输出为ASCII编码的数字。你将如何区分序列1,2,3和12,3或1,23。
您需要使用9位(10、11或其他)数字或某种无前缀代码(如哈夫曼编码)以明确的方式对数据进行编码。

这里的实际问题是什么?听起来你对它为什么不起作用有一个理论;您是否尝试过调试以查看其是否正确?当您读入要解码的数据时,您当然需要读取与所写数据相同大小的数据块,因此,如果(例如)您使用9位代码进行编码,则您也需要在解码时读取9位代码。@Jerry,这就是我所想的,但我应该如何做?逐位读取压缩文件,而不是逐字节读取,或者在文件加载到内存后处理数据?我会将块读入缓冲区,并保留指向下一位的点,以便从缓冲区读取。要从缓冲区读取,请读取到下一个字节的末尾,在9位块的其余部分适当移位,
,并将指针向前移动到后面的位。以这种方式操作数据的最佳方式是什么?是否有任何库可以对文件执行按位操作?如果选择9位数字,您可以创建一个base-72编码(lcm(9,8)==72;因此使用8个9位标记的组,并将它们作为9个8位字符输出),其工作方式与base-64编码相同
void Compression::readFile(std::string filename) {
  std::ifstream file;
  file.open(filename.c_str(), std::ios::in | std::ios::binary | std::ios::ate);

  if (!file.is_open())
    exit(EXIT_FAILURE);

  m_dataSize = file.tellg();
  m_data = new char [m_dataSize];

  file.seekg(0, std::ios::beg);
  file.read(m_data, m_dataSize);
  file.close();
}