Заголовок кода Хаффмана C++
-
20-08-2019 - |
Вопрос
по сути, у меня есть таблица Хаффмана как
std::map<std::string, char> ciMap;
Где строка — это битовый шаблон, а char — значение, представленное указанным шаблоном.Проблема в том, как мне сохранить это как заголовок моего сжатого файла, чтобы я мог снова построить ту же карту, когда захочу ее декодировать?
Попытка сохранить его как двоичный:
size_t mapLen = ciMap.size();
outFile.write(reinterpret_cast<char*>(&mapLen), sizeof(size_t));
outFile.write(reinterpret_cast<char*>(&ciMap), sizeof(ciMap));
И позже постройка с:
inFile.read(reinterpret_cast<char*>(&mapLen), sizeof(size_t));
inFile.read(reinterpret_cast<char*>(&ciMap), sizeof(mapLen));
Не работает, получаю ошибку инициализации строки...что-то связанное с NULL.Какие-либо предложения?Если у вас есть лучший способ хранения битов и значений, я хотел бы услышать.
Решение
Вы можете сделать это самостоятельно, а можете сделать это с помощью boost: http://www.boost.org/doc/libs/1_37_0/libs/serialization/doc/index.html.Сейчас вы пытаетесь просто просмотреть карту как обычный старый тип данных, что по сути означает, что это тип данных C.Но это не так, поэтому не удается сохранить/загрузить.сериализация Boost делает это правильно.Посмотри на это.Если вы не хотите его использовать, вы можете сделать что-то вроде этого:
typedef std::map<std::string, char> my_map;
my_map ciMap;
// saving
std::ofstream stream("file.txt");
for(my_map::const_iterator it = ciMap.begin(); it != ciMap.end(); ++it) {
stream << it->first << " " << it->second << std::endl;
}
// loading
char c;
std::string bits;
std::ifstream stream("file.txt");
while(stream >> bits >> c)
ciMap.insert(std::make_pair(bits, c));
Обратите внимание, что приведенное выше требует некоторых изменений, если сохраненные символы также могут быть пробелами.По этой причине, вероятно, лучше всего сначала преобразовать в int перед записью, а затем читать как int при загрузке.На самом деле, я рекомендую повысить сериализацию и повысить iostreams (http://www.boost.org/doc/libs/1_37_0/libs/iostreams/doc/index.html), который включает поток сжатия, который также может прозрачно сжимать ваши данные.
Другие советы
Таким способом вы не можете просто сериализовать двоичные значения на диск.Представление в памяти — это не просто непрерывный блок памяти, и даже если бы оно было таковым, оно, скорее всего, будет содержать указатели, относящиеся к адресу блока.
Вам нужно перебрать карту и сериализовать каждый элемент индивидуально.Затем, чтобы вернуть их обратно, вы реконструируете карту, считывая элементы с диска один за другим и повторно вставляя их на карту.
Отличный вопрос.Проблема здесь в том, что контейнеры по умолчанию не поддерживают сериализацию — вам придется написать ее самостоятельно, это неприятно, но возможно.
Вот как вы можете сериализовать std::map
в текстовый формат.Вы можете адаптировать его для записи в любой необходимый вам двоичный формат.Просто замените <<
оператор с reads
и writes
.
template<typename K, typename V>
std::ostream &operator << (std::ostream &out, const std::map<K,V> &map) {
out << "map " << map.size() << "\n";
for (typename std::map<K,V>::const_iterator i = map.begin(); i != map.end(); ++i) {
out << (*i).first << "\n" << (*i).second << "\n";
}
return out;
}
template<typename K, typename V>
std::istream &operator >> (std::istream &in, std::map<K,V> &map) {
std::string mapkeyword;
size_t num;
in >> mapkeyword >> num;
for (size_t i = 0; i < num; ++i) {
K key; V value;
in >> key >> value;
map[key] = value;
}
return in;
}