huffman 编码

LINK : http://blog.csdn.net/zzran/article/details/9468167


huffman压缩是一种压缩算法,其中经典的部分就是根据字符出现的频率建立huffman树,然后根据huffman树的构建结果标示每个字符。huffman编码也称为前缀编码,就是每个字符的表示形式不是另一个字符表示的前缀。如果学过c语言版本的数据结构的话,那么会知道其上面的算法的时间复杂度是O(N^2), 也算是比较复杂的,那么首先贴上这个版本算法的代码:

[cpp]  view plain copy
  1. #include<iostream>  
  2. #include<string>  
  3. using namespace std;  
  4.   
  5. typedef struct huffman_node_s {  
  6.     int weight;  
  7.     int parent;  
  8.     int lchild;  
  9.     int rchild;  
  10. }huffman_node_t, *HuffmanTree;  
  11.   
  12. typedef char** HuffmanCode;  
  13.   
  14. void select(HuffmanTree ht, int n, int* s1, int* s2) {  
  15.     int i;  
  16.     int temp;  
  17.     *s1 = *s2 = 0;  
  18.     for (i = 1; i <= n; i++) {  
  19.         if (0 == ht[i].parent) {  
  20.             if (0 == *s1 && 0 == *s2) {  
  21.                 *s1 = i;  
  22.                 continue;  
  23.             } else if (0 == *s2) {  
  24.                 *s2 = i;  
  25.                 if (ht[*s1].weight > ht[*s2].weight) {  
  26.                     temp = *s1, *s1 = *s2, *s2 = temp;  
  27.                 }  
  28.                 continue;  
  29.             }  
  30.             if (ht[i].weight < ht[*s1].weight && ht[i].weight < ht[*s2].weight) {  
  31.                 *s2 = *s1;  
  32.                 *s1 = i;  
  33.             } else if (ht[i].weight > ht[*s1].weight && ht[i].weight < ht[*s2].weight) {  
  34.                 *s2 = i;  
  35.             }  
  36.         }  
  37.     }  
  38. }  
  39.   
  40. void HuffmanEncode(HuffmanTree* ht, HuffmanCode* hc, int* weight, int n) {  
  41.     int i, start;  
  42.     int s1, s2;  
  43.     int c, f;  
  44.     int m = 2 * n - 1;  
  45.     *ht = (huffman_node_t*)malloc((m + 1) * sizeof(huffman_node_t));  
  46.     for (i = 1; i <= m; i++) {  
  47.         if (i <= n) {  
  48.             (*ht)[i].weight = weight[i - 1];  
  49.         } else {  
  50.             (*ht)[i].weight = 0;  
  51.         }  
  52.         (*ht)[i].parent = 0;  
  53.         (*ht)[i].lchild = 0;  
  54.         (*ht)[i].rchild = 0;  
  55.     }  
  56.     for (i = n + 1; i <= m; i++) {  
  57.         select(*ht, i - 1, &s1, &s2);  
  58.         (*ht)[i].lchild = s1;  
  59.         (*ht)[i].rchild = s2;  
  60.         (*ht)[i].weight = (*ht)[s1].weight + (*ht)[s2].weight;  
  61.         (*ht)[s1].parent = (*ht)[s2].parent = i;  
  62.     }  
  63.     *hc = (char**)malloc((n + 1) * sizeof(char*));  
  64.     char* temp = (char*)malloc(n * sizeof(char));  
  65.     for (i = 1; i <= n; i++) {  
  66.         temp[n - 1] = '\0';  
  67.         start = n - 1;  
  68.         for (c = i, f = (*ht)[i].parent; f != 0; c = f, f = (*ht)[f].parent) {  
  69.             if (c == (*ht)[f].lchild)  
  70.                 temp[--start] = '0';  
  71.             else   
  72.                 temp[--start] = '1';  
  73.         }  
  74.         (*hc)[i] = (char*)malloc(n - start);  
  75.         strcpy((*hc)[i], temp + start);  
  76.     }  
  77. }  
  78.   
  79. int main(int argc, char* argv[]) {  
  80.     int weight[] = {5, 29, 7, 8, 14, 23, 3, 11};  
  81.     int length = sizeof(weight) / sizeof(int);  
  82.     HuffmanTree ht = NULL;  
  83.     HuffmanCode hc = NULL;  
  84.     HuffmanEncode(&ht, &hc, weight, length);  
  85.     int i;  
  86.     for (i = 1; i <= length; i++)  
  87.         cout << hc[i] << endl;  
  88.     for (i = 1; i <= length; i++)  
  89.         free(hc[i]);  
  90.     free(hc);  
  91.     cin.get();  
  92.     return 0;  
  93. }  

还有另外一种算法,就是用爽队列的形式,可以把时间复杂度降到O(N*logN),算法的核心思想是:

1, 建立两个空的队列

2,为每一个字符建立一个节点,并按照字符出现的频率以非递减的方式放入第一个队列

3,每步要找出出现频率最小的两个字符,那么可以根据以下方法进行查找:

a,如果第二个队列为空,那么使第一个队列的头结点出列

b,如果第一个队列为空,那么使第二个队列的头结点出列

c,如果两个队列都不为空,那比较两个队列头结点字符出现的频率,使出现频率较小的头结点出列

4,创建一个新的临时节点,它的频率是第三步骤中出列两个节点所包含的字符的频率之和,然后将临时节点压入第二个队列,当第一个队列中不包含元素节点而第二个队列中只有一个元素节点的时候,停止算法,下面给出代码:

[cpp]  view plain copy
  1. #include<iostream>  
  2. #include<string>  
  3. using namespace std;  
  4.   
  5. typedef struct queue_node_s {  
  6.     char data;  
  7.     int frequent;  
  8.     struct queue_node_s* lchild;  
  9.     struct queue_node_s* rchild;  
  10. }queue_node_t;  
  11.   
  12. typedef struct queue_s {  
  13.     int front, rear;  
  14.     int capcity;  
  15.     queue_node_t** arr;  
  16. }queue_t;  
  17.   
  18. queue_node_t* createNode(char data, int frequent) {  
  19.     queue_node_t* node = (queue_node_t*)malloc(sizeof(queue_node_t));  
  20.     node->data = data;  
  21.     node->frequent = frequent;  
  22.     node->lchild = NULL;  
  23.     node->rchild = NULL;  
  24.     return node;  
  25. }  
  26.   
  27. queue_t* createQueue(int size)  {  
  28.     queue_t* queue = (queue_t*)malloc(sizeof(queue_t));  
  29.     queue->capcity = size;  
  30.     queue->front = queue->rear = -1;  
  31.     queue->arr = (queue_node_t**)malloc(size * sizeof(queue_node_t));  
  32.     if (NULL == queue->arr) {  
  33.         free(queue);  
  34.         return NULL;  
  35.     }  
  36.     return queue;  
  37. }  
  38.   
  39. bool isQueueEmpty(queue_t* queue) {  
  40.     if (-1 == queue->front && -1 == queue->rear)  
  41.         return true;  
  42.     return false;  
  43. }  
  44.   
  45. bool isContainOne(queue_t* queue) {  
  46.     if (queue->rear == queue->front && queue->front != -1)  
  47.         return true;  
  48.     return false;  
  49. }  
  50.   
  51. bool isQueueFull(queue_t* queue) {  
  52.     return queue->rear == queue->capcity - 1;  
  53. }  
  54.   
  55. void enQueue(queue_t* queue, queue_node_t* item) {  
  56.     if (isQueueFull(queue))  
  57.         return;  
  58.     queue->arr[++queue->rear] = item;  
  59.     if (-1 == queue->front)  
  60.         queue->front++;  
  61. }  
  62.   
  63. queue_node_t* deQueue(queue_t* queue) {  
  64.     if (isQueueEmpty(queue))  
  65.         return NULL;  
  66.     queue_node_t* temp = queue->arr[queue->front];  
  67.     if (queue->front == queue->rear)  
  68.         queue->front = queue->rear = -1;  
  69.     else  
  70.         queue->front++;  
  71.     return temp;  
  72. }  
  73.   
  74. queue_node_t* getFront(queue_t* queue) {  
  75.     if (isQueueEmpty(queue))  
  76.         return NULL;  
  77.     return queue->arr[queue->front];  
  78. }  
  79.   
  80. queue_node_t* findMin(queue_t* queueOne, queue_t* queueTwo) {  
  81.     if (isQueueEmpty(queueOne))  
  82.         return deQueue(queueTwo);  
  83.     if (isQueueEmpty(queueTwo))  
  84.         return deQueue(queueOne);  
  85.     if (getFront(queueOne)->frequent < getFront(queueTwo)->frequent)  
  86.         return deQueue(queueOne);  
  87.     return deQueue(queueTwo);  
  88. }  
  89.   
  90. void printArr(char* arr, int n) {  
  91.     int i;  
  92.     for (i = 0; i < n; i++)  
  93.         printf("%c", arr[i]);  
  94.     cout << endl;  
  95. }  
  96.   
  97. bool isLeaf(queue_node_t* node) {  
  98.     if (NULL == node->lchild && NULL == node->rchild)  
  99.         return true;  
  100.     return false;  
  101. }  
  102.   
  103. queue_node_t* buildHuffmanTree(char* data, int* frequents, int size) {  
  104.     queue_node_t* lchild;  
  105.     queue_node_t* rchild;  
  106.     queue_node_t* top;  
  107.     queue_t* queueOne = createQueue(size);  
  108.     queue_t* queueTwo = createQueue(size);  
  109.     int i;  
  110.     for (i = 0; i < size; i++)  
  111.         enQueue(queueOne, createNode(data[i], frequents[i]));  
  112.     while (!(isQueueEmpty(queueOne) && isContainOne(queueTwo))) {  
  113.         lchild = findMin(queueOne, queueTwo);  
  114.         rchild = findMin(queueOne, queueTwo);  
  115.         top = createNode('$', lchild->frequent + rchild->frequent);  
  116.         top->lchild = lchild;  
  117.         top->rchild = rchild;  
  118.         enQueue(queueTwo, top);  
  119.     }  
  120.     return deQueue(queueTwo);  
  121. }  
  122.   
  123. void printCodes(queue_node_t* node, char* arr, int top) {  
  124.     if (node->lchild) {  
  125.         arr[top] = '0';  
  126.         printCodes(node->lchild, arr, top + 1);  
  127.     }  
  128.     if (node->rchild) {  
  129.         arr[top] = '1';  
  130.         printCodes(node->rchild, arr, top + 1);  
  131.     }  
  132.     if (isLeaf(node)) {  
  133.         printf("%c:", node->data);  
  134.         printArr(arr, top);  
  135.     }  
  136. }  
  137.   
  138. void HuffmanCodes(char* data, int* frequents, int size) {  
  139.     queue_node_t* root = buildHuffmanTree(data, frequents, size);  
  140.     char* arr = (char*)malloc(size * sizeof(char));  
  141.     int top = 0;  
  142.     printCodes(root, arr, top);  
  143.     free(arr);  
  144. }  
  145.   
  146. int main(int argc, char* argv[]) {  
  147.     char data[] = {'a''b''c''d''e''f'};  
  148.     int freq[] = {5, 9, 12, 13, 16, 45};  
  149.     int size = sizeof(data) / sizeof(data[0]);  
  150.     HuffmanCodes(data, freq, size);  
  151.     cin.get();  
  152.     return 0;  
  153. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值