鱼C论坛

 找回密码
 立即注册
查看: 3834|回复: 2

[技术交流] 再看Huffman树,以及游程编码

[复制链接]
发表于 2014-3-6 15:47:19 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 andalousie 于 2014-3-25 22:51 编辑

原来写的《两种风格的Huffman树》增加了一个二进制流bitstream,用于一位位的读写,自己写的~
原理如图 捕获.JPG
  1. #if !defined BITSTREAM
  2. #define BITSTREAM
  3. //Alexander Misel 2014, Oschina
  4. //Open Source, free to copy

  5. #include <iostream>
  6. #include <fstream>
  7. #include <string>
  8. #include <cstdio>

  9. static const int READ_MODE = std::ios::in | std::ios::binary;
  10. static const int WRITE_MODE = std::ios::out | std::ios::binary;

  11. class bitostream
  12. {
  13.         struct bit{
  14.                 bit() : _next(0) {};
  15.                 bit & operator=(unsigned char v)
  16.                 {
  17.                         _bit = v;
  18.                         return *this;
  19.                 }
  20.                 unsigned char _bit;
  21.                 bit * _next;
  22.         };
  23. public:
  24.         bitostream(std::string const & nameFile)
  25.                 : _stream(nameFile.c_str(), WRITE_MODE),
  26.                 _head(0), _byte(0), buffer(0), N(-1)
  27.         {}
  28.         //OUTPUT
  29.         void allocate();
  30.         void writeChar(unsigned char v);
  31.         void writeBool(bool b);
  32.         void bitout();
  33. private:
  34.         std::ofstream _stream;
  35.         bit * _head;
  36.         bit * _byte;
  37.         unsigned char buffer;
  38.         int    N;
  39. };

  40. inline void bitostream::allocate()
  41. {
  42.         if(!_head)
  43.         {
  44.                 bit * newByte = new bit;
  45.                 _head = newByte;
  46.                 _byte = newByte;
  47.                 * _byte = 0;
  48.                 buffer = 0;
  49.         }
  50.         else
  51.         {
  52.                 _byte->_next = new bit;
  53.                 _byte = _byte->_next;
  54.                 * _byte = 0;
  55.                 buffer = 0;
  56.         }
  57. }

  58. inline void bitostream::writeChar(unsigned char v)
  59. {
  60.         if(N == -1 || N == 8)
  61.         { allocate(); N=0; }
  62.         if(!N)
  63.         {
  64.                 N = 8;
  65.                 * _byte = v;
  66.                 return;
  67.         }
  68.         unsigned char tmp = v >> N;
  69.         unsigned char pmt = v << (8-N);
  70.         int save = N;
  71.         buffer += tmp;
  72.         N = 0;
  73.         writeChar(buffer);
  74.         N = -1;
  75.         writeChar(pmt);
  76.         buffer = pmt;
  77.         N = save;
  78. }

  79. inline void bitostream::writeBool(bool b)
  80. {
  81.         if(N == -1 || N == 8)
  82.         { allocate(); N=0; }
  83.         unsigned char tmp = b ? 1 : 0;
  84.         tmp = tmp << (7-N);
  85.         buffer += tmp;
  86.         if(N == 7)
  87.         {
  88.                 int save = N;
  89.                 N = 0;
  90.                 writeChar(buffer);
  91.                 N = save;
  92.         }
  93.         N++;
  94. }

  95. inline void bitostream::bitout()
  96. {
  97.         bit * outByte = _head;
  98.         while(outByte)
  99.         {
  100.                 _stream.write(reinterpret_cast<char *>(outByte), 1);
  101.                 outByte = outByte->_next;
  102.         }
  103.         _head = 0;
  104.         _byte = 0;
  105.         buffer = 0;
  106.         _stream.flush();
  107. }

  108. class bitistream
  109. {
  110. public:
  111.         bitistream(std::string const & nameFile)
  112.                 : _stream(nameFile.c_str(), READ_MODE),
  113.                 inbuf(0), inN(0)
  114.         {
  115.                 if(!_stream.is_open())
  116.                         throw "couldn't open file";
  117.                 pbuf = _stream.rdbuf();
  118.         }
  119.         //INPUT
  120.         void get_in();
  121.         bool isEmpty()
  122.         {
  123.                 return (pbuf->sgetc() == EOF) && (inN == 8 || inN == 0);
  124.         }
  125.         unsigned char readChar();
  126.         bool readBool();
  127. public:
  128.         std::ifstream _stream;
  129.         std::streambuf * pbuf;
  130.         unsigned char  inbuf;
  131.         int    inN;
  132. };

  133. inline void bitistream::get_in()
  134. {
  135.         if(pbuf->sgetc() != EOF)
  136.                 inbuf = pbuf->sbumpc();
  137. }

  138. inline unsigned char bitistream::readChar()
  139. {
  140.         if(!inN || inN == 8)
  141.         {
  142.                 get_in();
  143.                 inN = 0;
  144.                 return inbuf;
  145.         }
  146.         unsigned char tmp = inbuf << inN;
  147.         inbuf = 0;
  148.         get_in();
  149.         unsigned char pmt = inbuf >> (8-inN);
  150.         tmp += pmt;
  151.         return tmp;
  152. }

  153. inline bool bitistream::readBool()
  154. {
  155.         if(!inN || inN == 8)
  156.         {
  157.                 get_in();
  158.                 inN = 0;
  159.         }
  160.         unsigned char tmp = inbuf << inN;
  161.         inN++;
  162.         return (tmp & 0x80)>0;
  163. }

  164. #endif
复制代码
改代码花去了好多时间。尤其是C++的char型默认是有符号的,大家知道,有符号的位运算有诸多的不方便。还有,关于流缓冲的内容,大家也可以参考一下rdbuf的相关用法。
huffman.cpp
  1. #include <iostream>
  2. #include <string>
  3. #include "GPQ.h"
  4. #include "bitstream.h"
  5. const int R = 256;

  6. class Huffman
  7. {
  8.         class Node
  9.         {
  10.         public:
  11.                 const unsigned char _ch;
  12.                 const int    _freq;
  13.                 Node *_left, *_right;

  14.                 Node(unsigned char ch, int freq, Node* left, Node* right)
  15.                         : _ch(ch), _freq(freq), _left(left), _right(right)
  16.                 {}
  17.                 bool isLeaf() { return !_left && !_right; }
  18.                 bool compareTo(Node *that)  { return _freq > that->_freq; }
  19.         };
  20.         struct buf
  21.         {
  22.                 buf(): _id(-1) {}
  23.                 int index() { _id++; return _id; }
  24.                 int _id;
  25.         }id;
  26. public:
  27.         void expand(bitistream& trie, std::string& s, int N)
  28.         {
  29.                 id._id = -1;
  30.                 Node *root = readTrie(trie);

  31.                 id._id = -1;
  32.                 for (int i = 0; i < N; ++i)
  33.                 {
  34.                         Node *x = root;
  35.                         while (!(x->isLeaf()))
  36.                         {
  37.                                 if(s[id.index()] == '0')
  38.                                         x = x->_left;
  39.                                 else  x = x->_right;
  40.                         }
  41.                         std::cout << x->_ch;
  42.                 }
  43.         }
  44.         void writeTrie(Node* x, bitostream& b)
  45.         {
  46.                 if(x->isLeaf())
  47.                 {
  48.                         b.writeBool(true);
  49.                         b.writeChar(x->_ch);
  50.                         return;
  51.                 }
  52.                 b.writeBool(false);
  53.                 writeTrie(x->_left, b);
  54.                 writeTrie(x->_right, b);
  55.         }
  56.         Node* readTrie(bitistream& trie)
  57.         {
  58.                 if(trie.readBool())
  59.                 {
  60.                         unsigned char c = trie.readChar();
  61.                         Node *fresh = new Node(c, 0, 0, 0);
  62.                         return fresh;
  63.                 }
  64.                 Node *x = readTrie(trie);
  65.                 Node *y = readTrie(trie);
  66.                 Node *fresh = new Node('\0', 0, x, y);
  67.                 return fresh;
  68.         }
  69.         void compress(std::string& s, bitostream& b)
  70.         {
  71.                 // Tabulate frequency counts.
  72.                 int freq[R] = {0};
  73.                 for (int i = 0; i < s.size(); ++i)
  74.                         freq[s[i]]++;

  75.                 // Build Huffman code trie.
  76.                 Node *root = buildTrie(freq);

  77.                 std::string *st = new std::string [R];
  78.                 buildCode(st, root, "");

  79.                 // Print trie for decoder (recursive).
  80.                 writeTrie(root, b);

  81.                 // Use Huffman code to encode input.
  82.                 for (int id = 0; id < s.length(); id++)
  83.                 {
  84.                         std::string code = st[s[id]];
  85.                         std::cout << s[id] << " ";
  86.                         std::cout << code << std::endl;
  87.                 }
  88.         }
  89. private:
  90.         Node* buildTrie(int *freq)
  91.         {
  92.                 GenericPQ<Node*> pq(R);
  93.                 for (int i = 0; i < R; i++)
  94.                         if (freq[i] > 0)
  95.                                 pq.insert(new Node(i, freq[i], 0, 0));
  96.                 while (pq.size() > 1)
  97.                 {
  98.                         Node *x = pq.pop();
  99.                         Node *y = pq.pop();
  100.                         Node *parent = new Node('\0', x->_freq + y->_freq, x, y);
  101.                         pq.insert(parent);
  102.                 }
  103.                 return pq.pop();
  104.         }
  105.         std::string* buildCode(Node* root)
  106.         {
  107.                 std::string *st = new std::string[R];
  108.                 buildCode(st, root, "");
  109.                 return st;
  110.         }
  111.         void buildCode(std::string *st, Node *x, std::string s)
  112.         {
  113.                 if(x->isLeaf()) { st[x->_ch] = s; return; }
  114.                 buildCode(st, x->_left, s + '0');
  115.                 buildCode(st, x->_right, s + '1');
  116.         }
  117. };

  118. int main()
  119. {
  120.         Huffman code;
  121.         std::string sample = "ABRACADABRA!";
  122.         std::string coder  = "0111110010110100011111001010";
  123.         bitostream bin("huff.trie");
  124.         code.compress(sample, bin);
  125.         bin.bitout();
  126.         bitistream by("huff.trie");
  127.         code.expand(by, coder, 12);
  128.     return 0;
  129. }
复制代码
我们输出的结果自然和从前一样,但是树结构就输出到了huff.trie文件里面。其实bitstream我做过好多次调试。
  1. 0,1,010000|00,0,0,1,010|00000,0,1,0|0100001,0|01000011|01,010100|00,1,01000|010.00000     wrong
  2. 0,1,010000|01,0,0,1,010|00100,0,1,0|0100001,0|01000011|01,010100|10,1,01000|010.00000     almost
  3. 0,1,010000|01,0,0,1,010|00100,0,1,0|0100001,1|01000011|01,010100|10,1,01000|010.00000     right
复制代码
因为需要一位一位的读写,所以就会面临各种问题。由于时间紧,没有来及写注释,改天会补上的。大家一定要支持,一定要支持哦~ 我写的bitstream算是开源的,大家用得着可以拿去使,:ton:。
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2014-3-6 18:29:10 | 显示全部楼层
本帖最后由 andalousie 于 2014-3-6 18:32 编辑

下午急匆匆的发表了,但是前面的解说不知道怎么没了。是在抱歉。大家来看看吧~ 有问题可以回帖。GPQ.h可以看以前的。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-3-25 22:50:27 | 显示全部楼层
同样,根据这个bitstream,对于成块的0或1比较普遍的数据,我们可以写出一个RunLength游程编码,如下:
  1. #include <iostream>
  2. #include <string>
  3. #include "bitstream.h"
  4. const int R = 256;

  5. class RunLength {
  6. public:
  7.         static void expand(std::string const & in, std::string const & out) {
  8.                 bitistream BinaryStdIn(in);
  9.                 bitostream BinaryStdOut(out);
  10.                 bool b = false;
  11.                 while (!BinaryStdIn.isEmpty()) {
  12.                         int run = BinaryStdIn.readChar();
  13.                         for (int i = 0; i < run; i++)
  14.                                 BinaryStdOut.writeBool(b);
  15.                         b = !b;
  16.                 }
  17.                 BinaryStdOut.bitout();
  18.         }

  19.         static void compress(std::string const & in, std::string const & out) {
  20.                 bitistream BinaryStdIn(in);
  21.                 bitostream BinaryStdOut(out);
  22.                 unsigned char run = 0;
  23.                 bool old = false;
  24.                 while (!BinaryStdIn.isEmpty()) {
  25.                         bool b = BinaryStdIn.readBool();
  26.                         if (b != old) {
  27.                                 BinaryStdOut.writeChar(run);
  28.                                 run = 1;
  29.                                 old = !old;
  30.                         }
  31.                         else {
  32.                                 if (run == R-1) {
  33.                                         BinaryStdOut.writeChar(run);
  34.                                         run = 0;
  35.                                         BinaryStdOut.writeChar(run);
  36.                                 }
  37.                                 run++;
  38.                         }
  39.                 }
  40.                 BinaryStdOut.writeChar(run);
  41.                 BinaryStdOut.bitout();
  42.         }
  43. };

  44. int main()
  45. {
  46.         RunLength::compress("huff.trie", "huff.trie.rle");
  47.         RunLength::expand("huff.trie.rle", "huff2.trie");
  48. }
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-4-19 14:23

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表