计算哈夫曼编码长度
来源:互联网 发布:windows eds安装文件 编辑:程序博客网 时间:2024/05/22 12:56
本篇文章向大家介绍一个不用构造哈夫曼树的方法来计算哈夫曼编码的长度,这对于较大字符集有极大的优势,因为构造一个树要花费相当大的空间和时间,本算法的时间复杂度为O(nlogn),空间复杂度为O(N);
参考文献<深入搜索引擎>第二章
程序处理:高亮显示
转载自http://jinyun2012.blog.sohu.com/159537265.html
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
using namespace std;
#define BUFF_SIZE 4096
#define HASH_SIZE 256
char buff[BUFF_SIZE]; //缓冲区
int hash[HASH_SIZE]; //统计每个字符出现的次数
int heap[(HASH_SIZE<<1)+2];
int pos[HASH_SIZE+1][3];//内部节点 , 0和1记录子结点位置,3节录当前的深度
int tlen[HASH_SIZE+1]; //记录每个叶子结点的深度
int fd; //文件描述符
int sym_num ; //文件中出现的符号数量
int SUM(0); //文件中字符总数
//初始化程序
void init(const char * pathname)
{
memset(buff , 0 , sizeof(buff));
memset(hash , 0 , sizeof(hash));
memset(heap , 0 , sizeof(heap));
memset(pos , 0 , sizeof(pos));
memset(tlen , 0 , sizeof(tlen));
//打开文件
fd = open(pathname , O_RDONLY);
if(fd < 0){
printf("init: %s dont exit!\n" , pathname);
exit(1);
}
}
//统计文件中每个符号出现的次数
void count_symbol()
{
lseek(fd , 0 , SEEK_SET);
while(read(fd , buff , BUFF_SIZE)){
SUM += strlen(buff);
for(int i=strlen(buff) - 1;i>=0;i--)
hash[(unsigned int)(buff[i] & 0xFF)]++;
}
//记录出现的符号数量;
for(int i = HASH_SIZE - 1; i >= 0; i--)
if(hash[i])sym_num++;
}
//建立一个最小堆
void build_min_heap()
{
for(int i=sym_num;i>0;i--){
int p = i >> 1 , j = i;
while(p >= 1){
if(heap[heap[p]] > heap[heap[j]])
std::swap(heap[j] , heap[p]);
j = p; p >>= 1;
}
}
}
//每次取出最小数之后重新调整堆,
//h 指推中元素的个数
void heap_adjust(int h)
{
int t = 1 , p , q , l;
while(t<h){
p = t<<1; q = p + 1; l = t;
if(p <= h && heap[heap[p]] < heap[heap[t]])l = p;
if(q <= h && heap[heap[q]] < heap[heap[l]])l = q;
if(l == t)break;
std::swap(heap[l] , heap[t]);
t = l;
}
}
//计算每个字符编码的长度
void huff_length()
{
int i , j , p , h , m1 , m2;
for(i=1 , p=0;i<=sym_num;i++){
while(!hash[p]) p++;
heap[sym_num + i] = hash[p];
heap[i] = sym_num + i;
p++;
}
h = sym_num;
//对1到n建立最小堆
build_min_heap();
while(h>1){
//取出最小数
m1 = heap[heap[1]];
pos[h][0] = heap[1];
heap[1] = heap[h];
h--;
heap_adjust(h);
//取出次小数
m2 = heap[heap[1]];
pos[h+1][1] = heap[1];
//最后数和次小数之和放在堆的最后一个位置
heap[h+1] = m1 + m2;
//重新指向最新合并的结点
heap[1] = h+1;
heap_adjust(h);
}
//统计编码长度 , 线性时间统计
int ts = sym_num << 1;
for(int i=2;i<=sym_num;i++){
if(pos[i][0] <= sym_num) pos[pos[i][0]][2] = pos[i][2] + 1;
else tlen[pos[i][0] - sym_num] = pos[i][2] + 1;
if(pos[i][1] <= sym_num) pos[pos[i][1]][2] = pos[i][2] + 1;
else tlen[pos[i][1] - sym_num] = pos[i][2] + 1;
}
}
int main()
{
init("data.dat");
count_symbol();
huff_length();
unsigned int sum = 0;
for(int i=1;i<=sym_num;i++)
sum += tlen[i] * heap[sym_num + i];
cout<<SUM <<"\t\t"<<sum<<"\t\t"<<sum*1.0/SUM<<endl;
return 0;
}
参考文献<深入搜索引擎>第二章
程序处理:高亮显示
转载自http://jinyun2012.blog.sohu.com/159537265.html
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
using namespace std;
#define BUFF_SIZE 4096
#define HASH_SIZE 256
char buff[BUFF_SIZE]; //缓冲区
int hash[HASH_SIZE]; //统计每个字符出现的次数
int heap[(HASH_SIZE<<1)+2];
int pos[HASH_SIZE+1][3];//内部节点 , 0和1记录子结点位置,3节录当前的深度
int tlen[HASH_SIZE+1]; //记录每个叶子结点的深度
int fd; //文件描述符
int sym_num ; //文件中出现的符号数量
int SUM(0); //文件中字符总数
//初始化程序
void init(const char * pathname)
{
memset(buff , 0 , sizeof(buff));
memset(hash , 0 , sizeof(hash));
memset(heap , 0 , sizeof(heap));
memset(pos , 0 , sizeof(pos));
memset(tlen , 0 , sizeof(tlen));
//打开文件
fd = open(pathname , O_RDONLY);
if(fd < 0){
printf("init: %s dont exit!\n" , pathname);
exit(1);
}
}
//统计文件中每个符号出现的次数
void count_symbol()
{
lseek(fd , 0 , SEEK_SET);
while(read(fd , buff , BUFF_SIZE)){
SUM += strlen(buff);
for(int i=strlen(buff) - 1;i>=0;i--)
hash[(unsigned int)(buff[i] & 0xFF)]++;
}
//记录出现的符号数量;
for(int i = HASH_SIZE - 1; i >= 0; i--)
if(hash[i])sym_num++;
}
//建立一个最小堆
void build_min_heap()
{
for(int i=sym_num;i>0;i--){
int p = i >> 1 , j = i;
while(p >= 1){
if(heap[heap[p]] > heap[heap[j]])
std::swap(heap[j] , heap[p]);
j = p; p >>= 1;
}
}
}
//每次取出最小数之后重新调整堆,
//h 指推中元素的个数
void heap_adjust(int h)
{
int t = 1 , p , q , l;
while(t<h){
p = t<<1; q = p + 1; l = t;
if(p <= h && heap[heap[p]] < heap[heap[t]])l = p;
if(q <= h && heap[heap[q]] < heap[heap[l]])l = q;
if(l == t)break;
std::swap(heap[l] , heap[t]);
t = l;
}
}
//计算每个字符编码的长度
void huff_length()
{
int i , j , p , h , m1 , m2;
for(i=1 , p=0;i<=sym_num;i++){
while(!hash[p]) p++;
heap[sym_num + i] = hash[p];
heap[i] = sym_num + i;
p++;
}
h = sym_num;
//对1到n建立最小堆
build_min_heap();
while(h>1){
//取出最小数
m1 = heap[heap[1]];
pos[h][0] = heap[1];
heap[1] = heap[h];
h--;
heap_adjust(h);
//取出次小数
m2 = heap[heap[1]];
pos[h+1][1] = heap[1];
//最后数和次小数之和放在堆的最后一个位置
heap[h+1] = m1 + m2;
//重新指向最新合并的结点
heap[1] = h+1;
heap_adjust(h);
}
//统计编码长度 , 线性时间统计
int ts = sym_num << 1;
for(int i=2;i<=sym_num;i++){
if(pos[i][0] <= sym_num) pos[pos[i][0]][2] = pos[i][2] + 1;
else tlen[pos[i][0] - sym_num] = pos[i][2] + 1;
if(pos[i][1] <= sym_num) pos[pos[i][1]][2] = pos[i][2] + 1;
else tlen[pos[i][1] - sym_num] = pos[i][2] + 1;
}
}
int main()
{
init("data.dat");
count_symbol();
huff_length();
unsigned int sum = 0;
for(int i=1;i<=sym_num;i++)
sum += tlen[i] * heap[sym_num + i];
cout<<SUM <<"\t\t"<<sum<<"\t\t"<<sum*1.0/SUM<<endl;
return 0;
}
0 0
- 计算哈夫曼编码长度
- base64编码长度计算
- 赫夫曼编码长度计算问题?
- 解决关于哈夫曼编码计算带权路径长度问题
- 哈夫曼编码计算带权路径长度问题
- 再谈日文编码字符显示长度的计算
- Huffman Codes(哈弗曼编码)之计算最优编码长度和对每位学生的提交检查
- 游程长度编码
- 游程长度编码
- 游程长度编码
- poj1521 求赫夫曼编码长度
- 行程长度编码
- 32:行程长度编码
- 32:行程长度编码
- 行程长度编码科普
- 长度限制计算长度与服务器计算长度不符
- 计算字符串的长度
- 计算字符串长度
- 第五届校内选拔javaA组-子序列第一题
- 响应式设计布局之@media用法详解(转)
- 浅谈MyBatis 之 增删改查(CRUD) (二)
- 【Maven】Nexus(Maven仓库私服)下载与安装
- 【HTTP】Fiddler(三)- Fiddler命令行和HTTP断点调试
- 计算哈夫曼编码长度
- Go 在游戏行业中的工程实践
- 欢迎使用CSDN-markdown编辑器
- 线性表
- r18_ap6330的步骤.txt
- 简单总结笔试和面试中的海量数据问题
- C# 使用Semaphore(信号量)控制多线程
- Find a way
- c++标准库中各种容器的介绍