huffman 编码
huffman压缩是一种压缩算法,其中经典的部分就是根据字符出现的频率建立huffman树,然后根据huffman树的构建结果标示每个字符。huffman编码也称为前缀编码,就是每个字符的表示形式不是另一个字符表示的前缀。如果学过c语言版本的数据结构的话,那么会知道其上面的算法的时间复杂度是O(N^2), 也算是比较复杂的,那么首先贴上这个版本算法的代码:
#include<iostream>
#include<string>
using namespace std; typedef struct huffman_node_s {
int weight;
int parent;
int lchild;
int rchild;
}huffman_node_t, *HuffmanTree; typedef char** HuffmanCode; void select(HuffmanTree ht, int n, int* s1, int* s2) {
int i;
int temp;
*s1 = *s2 = 0;
for (i = 1; i <= n; i++) {
if (0 == ht[i].parent) {
if (0 == *s1 && 0 == *s2) {
*s1 = i;
continue;
} else if (0 == *s2) {
*s2 = i;
if (ht[*s1].weight > ht[*s2].weight) {
temp = *s1, *s1 = *s2, *s2 = temp;
}
continue;
}
if (ht[i].weight < ht[*s1].weight && ht[i].weight < ht[*s2].weight) {
*s2 = *s1;
*s1 = i;
} else if (ht[i].weight > ht[*s1].weight && ht[i].weight < ht[*s2].weight) {
*s2 = i;
}
}
}
} void HuffmanEncode(HuffmanTree* ht, HuffmanCode* hc, int* weight, int n) {
int i, start;
int s1, s2;
int c, f;
int m = 2 * n - 1;
*ht = (huffman_node_t*)malloc((m + 1) * sizeof(huffman_node_t));
for (i = 1; i <= m; i++) {
if (i <= n) {
(*ht)[i].weight = weight[i - 1];
} else {
(*ht)[i].weight = 0;
}
(*ht)[i].parent = 0;
(*ht)[i].lchild = 0;
(*ht)[i].rchild = 0;
}
for (i = n + 1; i <= m; i++) {
select(*ht, i - 1, &s1, &s2);
(*ht)[i].lchild = s1;
(*ht)[i].rchild = s2;
(*ht)[i].weight = (*ht)[s1].weight + (*ht)[s2].weight;
(*ht)[s1].parent = (*ht)[s2].parent = i;
}
*hc = (char**)malloc((n + 1) * sizeof(char*));
char* temp = (char*)malloc(n * sizeof(char));
for (i = 1; i <= n; i++) {
temp[n - 1] = '\0';
start = n - 1;
for (c = i, f = (*ht)[i].parent; f != 0; c = f, f = (*ht)[f].parent) {
if (c == (*ht)[f].lchild)
temp[--start] = '0';
else
temp[--start] = '1';
}
(*hc)[i] = (char*)malloc(n - start);
strcpy((*hc)[i], temp + start);
}
} int main(int argc, char* argv[]) {
int weight[] = {5, 29, 7, 8, 14, 23, 3, 11};
int length = sizeof(weight) / sizeof(int);
HuffmanTree ht = NULL;
HuffmanCode hc = NULL;
HuffmanEncode(&ht, &hc, weight, length);
int i;
for (i = 1; i <= length; i++)
cout << hc[i] << endl;
for (i = 1; i <= length; i++)
free(hc[i]);
free(hc);
cin.get();
return 0;
}
还有另外一种算法,就是用爽队列的形式,可以把时间复杂度降到O(N*logN),算法的核心思想是:
1, 建立两个空的队列
2,为每一个字符建立一个节点,并按照字符出现的频率以非递减的方式放入第一个队列
3,每步要找出出现频率最小的两个字符,那么可以根据以下方法进行查找:
a,如果第二个队列为空,那么使第一个队列的头结点出列
b,如果第一个队列为空,那么使第二个队列的头结点出列
c,如果两个队列都不为空,那比较两个队列头结点字符出现的频率,使出现频率较小的头结点出列
4,创建一个新的临时节点,它的频率是第三步骤中出列两个节点所包含的字符的频率之和,然后将临时节点压入第二个队列,当第一个队列中不包含元素节点而第二个队列中只有一个元素节点的时候,停止算法,下面给出代码:
#include<iostream>
#include<string>
using namespace std; typedef struct queue_node_s {
char data;
int frequent;
struct queue_node_s* lchild;
struct queue_node_s* rchild;
}queue_node_t; typedef struct queue_s {
int front, rear;
int capcity;
queue_node_t** arr;
}queue_t; queue_node_t* createNode(char data, int frequent) {
queue_node_t* node = (queue_node_t*)malloc(sizeof(queue_node_t));
node->data = data;
node->frequent = frequent;
node->lchild = NULL;
node->rchild = NULL;
return node;
} queue_t* createQueue(int size) {
queue_t* queue = (queue_t*)malloc(sizeof(queue_t));
queue->capcity = size;
queue->front = queue->rear = -1;
queue->arr = (queue_node_t**)malloc(size * sizeof(queue_node_t));
if (NULL == queue->arr) {
free(queue);
return NULL;
}
return queue;
} bool isQueueEmpty(queue_t* queue) {
if (-1 == queue->front && -1 == queue->rear)
return true;
return false;
} bool isContainOne(queue_t* queue) {
if (queue->rear == queue->front && queue->front != -1)
return true;
return false;
} bool isQueueFull(queue_t* queue) {
return queue->rear == queue->capcity - 1;
} void enQueue(queue_t* queue, queue_node_t* item) {
if (isQueueFull(queue))
return;
queue->arr[++queue->rear] = item;
if (-1 == queue->front)
queue->front++;
} queue_node_t* deQueue(queue_t* queue) {
if (isQueueEmpty(queue))
return NULL;
queue_node_t* temp = queue->arr[queue->front];
if (queue->front == queue->rear)
queue->front = queue->rear = -1;
else
queue->front++;
return temp;
} queue_node_t* getFront(queue_t* queue) {
if (isQueueEmpty(queue))
return NULL;
return queue->arr[queue->front];
} queue_node_t* findMin(queue_t* queueOne, queue_t* queueTwo) {
if (isQueueEmpty(queueOne))
return deQueue(queueTwo);
if (isQueueEmpty(queueTwo))
return deQueue(queueOne);
if (getFront(queueOne)->frequent < getFront(queueTwo)->frequent)
return deQueue(queueOne);
return deQueue(queueTwo);
} void printArr(char* arr, int n) {
int i;
for (i = 0; i < n; i++)
printf("%c", arr[i]);
cout << endl;
} bool isLeaf(queue_node_t* node) {
if (NULL == node->lchild && NULL == node->rchild)
return true;
return false;
} queue_node_t* buildHuffmanTree(char* data, int* frequents, int size) {
queue_node_t* lchild;
queue_node_t* rchild;
queue_node_t* top;
queue_t* queueOne = createQueue(size);
queue_t* queueTwo = createQueue(size);
int i;
for (i = 0; i < size; i++)
enQueue(queueOne, createNode(data[i], frequents[i]));
while (!(isQueueEmpty(queueOne) && isContainOne(queueTwo))) {
lchild = findMin(queueOne, queueTwo);
rchild = findMin(queueOne, queueTwo);
top = createNode('$', lchild->frequent + rchild->frequent);
top->lchild = lchild;
top->rchild = rchild;
enQueue(queueTwo, top);
}
return deQueue(queueTwo);
} void printCodes(queue_node_t* node, char* arr, int top) {
if (node->lchild) {
arr[top] = '0';
printCodes(node->lchild, arr, top + 1);
}
if (node->rchild) {
arr[top] = '1';
printCodes(node->rchild, arr, top + 1);
}
if (isLeaf(node)) {
printf("%c:", node->data);
printArr(arr, top);
}
} void HuffmanCodes(char* data, int* frequents, int size) {
queue_node_t* root = buildHuffmanTree(data, frequents, size);
char* arr = (char*)malloc(size * sizeof(char));
int top = 0;
printCodes(root, arr, top);
free(arr);
} int main(int argc, char* argv[]) {
char data[] = {'a', 'b', 'c', 'd', 'e', 'f'};
int freq[] = {5, 9, 12, 13, 16, 45};
int size = sizeof(data) / sizeof(data[0]);
HuffmanCodes(data, freq, size);
cin.get();
return 0;
}
huffman 编码的更多相关文章
- [老文章搬家] 关于 Huffman 编码
按:去年接手一个项目,涉及到一个一个叫做Mxpeg的非主流视频编码格式,编解码器是厂商以源代码形式提供的,但是可能代码写的不算健壮,以至于我们tcp直连设备很正常,但是经过一个UDP数据分发服务器之后 ...
- Huffman编码
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <cstdio> #include <cstri ...
- 【数据压缩】Huffman编码
1. 压缩编码概述 数据压缩在日常生活极为常见,平常所用到jpg.mp3均采用数据压缩(采用Huffman编码)以减少占用空间.编码\(C\)是指从字符空间\(A\)到码字表\(X\)的映射.数据压缩 ...
- 优先队列求解Huffman编码 c++
优先队列小析 优先队列的模板: template <class T, class Container = vector<T>,class Compare = less< ...
- Huffman编码实现电文的转码与译码
//first thing:thanks to my teacher---chenrong Dalian Maritime university /* 构造Huffman Tree思路: ( ...
- 基于二叉树和数组实现限制长度的最优Huffman编码
具体介绍详见上篇博客:基于二叉树和双向链表实现限制长度的最优Huffman编码 基于数组和基于链表的实现方式在效率上有明显区别: 编码256个符号,符号权重为1...256,限制长度为16,循环编码1 ...
- uvalive 2088 - Entropy(huffman编码)
题目连接:2088 - Entropy 题目大意:给出一个字符串, 包括A~Z和_, 现在要根据字符出现的频率为他们进行编码,要求编码后字节最小, 然后输出字符均为8字节表示时的总字节数, 以及最小的 ...
- Jcompress: 一款基于huffman编码和最小堆的压缩、解压缩小程序
前言 最近基于huffman编码和最小堆排序算法实现了一个压缩.解压缩的小程序.其源代码已经上传到github上面: Jcompress下载地址 .在本人的github上面有一个叫Utility的re ...
- DS二叉树--Huffman编码与解码
题目描述 1.问题描述 给定n个字符及其对应的权值,构造Huffman树,并进行huffman编码和译(解)码. 构造Huffman树时,要求左子树根的权值小于.等于右子树根的权值. 进行Huffma ...
随机推荐
- iOS Get方式带中文不能请求网络
今天发现一个蛋疼的问题,使用ASIHTTPRequest Get方式请求数据时候带中文,iOS客户端不能正确进行网络请求. NSURL *url = [NSURL URLWithString:@htt ...
- 新一代分布式任务调度框架:当当elastic-job开源项目的10项特性
作者简介: 张亮,当当网架构师.当当技术委员会成员.消息中间件组负责人.对架构设计.分布式.优雅代码等领域兴趣浓厚.目前主导当当应用框架ddframe研发,并负责推广及撰写技术白皮书. 一.为什么 ...
- HEVC测试序列(百度云网盘分享)
巧妇难为无米之炊,身为一个码农怎能碗里没有米呢?想必很多朋友都碰到下载测试序列的困惑,为了减少麻烦,现提供HEVC所有测试序列的下载,上传到百度云网盘上,方便大家下载.主要的测试序列如下: Test ...
- NET基础课--配置文件1
在.NET Framework中,配置几乎是无处不在的.配置是控制应用程序行为的一些设置.下面我们就来看看到底有几个配置文件,而他们又分别代表了什么? 1. machine.config 这个文件只有 ...
- 动态根据checkbox 增加Dom
<%@ Page Title="" Language="C#" MasterPageFile="~/MasterPage.master" ...
- 小谈@override
@override是jdk1.5增加的注解,主要是用来声明子类的某方法覆盖了父类的某方法.非常简单的注解,但是有个小问题: 项目最开始使用的是jdk1.6,mvc模式:接口 ----> 实现类. ...
- C++中如何split字符串(转)
#include <iostream> #include <sstream> #include <string> using namespace std; int ...
- Centos7安装JDK
以下是gz包方式: 1,将jdk-8u51-linux-x64.tar.gz放到/usr/java目录下 2,用tar -zxvf jdk-8u51-linux-x64.tar.gz 解压到当前目录 ...
- jQuery 验证实例(shopnc二次开发)
shopnc 商家用户实现添加用户与前台用户分离, jQuery 验证实例 equalTo:等于 <div id="saleRefund" show_id="1&q ...
- php composer使用
Composer-PHP中用来管理依赖(dependency) 定义 composer是PHP中用来管理依赖(dependency)关系的工具.你可以在自己的项目中声明所依赖的外部工具库(librar ...