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

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

  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. }

huffman 编码的更多相关文章

  1. [老文章搬家] 关于 Huffman 编码

    按:去年接手一个项目,涉及到一个一个叫做Mxpeg的非主流视频编码格式,编解码器是厂商以源代码形式提供的,但是可能代码写的不算健壮,以至于我们tcp直连设备很正常,但是经过一个UDP数据分发服务器之后 ...

  2. Huffman编码

    #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <cstdio> #include <cstri ...

  3. 【数据压缩】Huffman编码

    1. 压缩编码概述 数据压缩在日常生活极为常见,平常所用到jpg.mp3均采用数据压缩(采用Huffman编码)以减少占用空间.编码\(C\)是指从字符空间\(A\)到码字表\(X\)的映射.数据压缩 ...

  4. 优先队列求解Huffman编码 c++

    优先队列小析      优先队列的模板: template <class T, class Container = vector<T>,class Compare = less< ...

  5. Huffman编码实现电文的转码与译码

    //first thing:thanks to my teacher---chenrong      Dalian Maritime university /* 构造Huffman Tree思路: ( ...

  6. 基于二叉树和数组实现限制长度的最优Huffman编码

    具体介绍详见上篇博客:基于二叉树和双向链表实现限制长度的最优Huffman编码 基于数组和基于链表的实现方式在效率上有明显区别: 编码256个符号,符号权重为1...256,限制长度为16,循环编码1 ...

  7. uvalive 2088 - Entropy(huffman编码)

    题目连接:2088 - Entropy 题目大意:给出一个字符串, 包括A~Z和_, 现在要根据字符出现的频率为他们进行编码,要求编码后字节最小, 然后输出字符均为8字节表示时的总字节数, 以及最小的 ...

  8. Jcompress: 一款基于huffman编码和最小堆的压缩、解压缩小程序

    前言 最近基于huffman编码和最小堆排序算法实现了一个压缩.解压缩的小程序.其源代码已经上传到github上面: Jcompress下载地址 .在本人的github上面有一个叫Utility的re ...

  9. DS二叉树--Huffman编码与解码

    题目描述 1.问题描述 给定n个字符及其对应的权值,构造Huffman树,并进行huffman编码和译(解)码. 构造Huffman树时,要求左子树根的权值小于.等于右子树根的权值. 进行Huffma ...

随机推荐

  1. javac命令详解(下)

    摘自http://blog.csdn.net/hudashi/article/details/7058999 javac命令详解(下)                             -ver ...

  2. 通用线程:POSIX 线程详解,第 3 部分 条件互斥量(pthread_cond_t)

    使用条件变量提高效率 本文是 POSIX 线程三部曲系列的最后一部分,Daniel 将详细讨论如何使用条件变量.条件变量是 POSIX 线程结构,可以让您在遇到某些条件时“唤醒”线程.可以将它们看作是 ...

  3. 使用SqlBulkCopy批量插入数据

    static void Main(string[] args) { //定义与目标表结构相同的DataTable DataTable dataTable = new DataTable(); data ...

  4. SqlServer2008数据库透明加密

    前几天研究了一下sql数据库的透明加密,记下来加深一下理解. 用脚本创建文件夹 --查文件夹有没有 EXEC master.dbo.xp_fileexist 'D:\DATA\storedcerts' ...

  5. 四个常用.NET的SqlHelper的方法

    至于我为什么要写这篇文章,也许很多人觉得网上大把的sqlhelper的封装类,的确,网上是有很多,我也看过网上很多的版本,但是我发现大多数都是代码生成器生成的,比如动软.CodeSmith等生成的,其 ...

  6. First Bad Version

    You are a product manager and currently leading a team to develop a new product. Unfortunately, the ...

  7. SQL Performance Improvement Techniques(转)

    原文地址:http://www.codeproject.com/Tips/1023621/SQL-Performance-Improvement-Techniques This article pro ...

  8. java之集合类框架的简要知识点:泛型的类型擦除

    这里想说一下在集合框架前需要理解的小知识点,也是个人的肤浅理解,不知道理解的正不正确,请大家多多指教.这里必须谈一下java的泛型,因为它们联系紧密,我们先看一下这几行代码: Class c1 = n ...

  9. oracle表空间使用率统计查询

    今天发现有一张采样表从1月5号开始不记录数据了,所以想查看一下表空间使用率,在网上零零散散找了很多资料,现在记录如下,也不知道哪一个最准确.还有一个就是网上拷贝的sql代码格式太乱了,不好看,找到一个 ...

  10. 诺基亚 Lumia 1020的价格

       大部分的中国人心中,都有一个诺基亚情节.经典的1110,耐摔程度强得惊人,相信很多人都知道它的厉害.    虽说这些年诺基亚由于没有跟上Android这一波智能机的浪潮,在智能机时代被三星苹果等 ...