文档库 最新最全的文档下载
当前位置:文档库 › 哈夫曼算法进行文件压缩和解压缩

哈夫曼算法进行文件压缩和解压缩

哈夫曼算法进行文件压缩和解压缩
哈夫曼算法进行文件压缩和解压缩

本文首先简要阐述哈夫曼算法的基本思想,然后介绍了使用哈夫曼算法进行文件压缩和解压缩的

处理步骤,最后给出了C语言实现的文件压缩和解压缩的源代码。

哈夫曼算法的主要思想是:

①首先遍历要处理的字符串,得到每个字符的出现的次数;

②将每个字符(以其出现次数为权值)分别构造为二叉树(注意此时的二叉树只有一个节点);

③取所有二叉树种种字符出现次数最小的二叉树合并为一颗新的二叉树,新二叉树根节点的权值等于两个子节点的权值之和,新节点中的字符忽略;

④重复过程③直到所有树被合并为同一棵二叉树

⑤遍历最后得到的二叉树,自顶向下按路径编号,指向左节点的边编号0,指向右节点的边编号1,从根到叶节点的所有边上的0和1链接起来,就是叶子节点中字符的哈夫曼编码。

下图展示了哈夫曼编码的基本思想。

基于哈夫曼算法的文件压缩和解压缩过程分别说明如下:

一、文件压缩:

①统计词频:读取文件的每个字节,使用整数数组int statistic[MAX_CHARS]统计每个字符出现的次数,

由于一个字节最多表示2^8-1个字符,所以MAX_CHARS=256就足够了。在统计字符数的时候,

对于每一个byte, 有statistic[(unsigned char)byte]++。

②构造哈夫曼树:根据statistic数组,基于哈夫曼树算法造哈夫曼树,由于构造的过程中每次都要取最小权值的字符,

所以需要用优先队列来维护每棵树的根节点。

③生成编码:深度优先遍历哈弗曼树,得到每个叶子节点中的字符的编码并存入字符串数组char *dictionary[MAX_CHARS];

④存储词频:新建存储压缩数据的文件,首先写入不同字符的个数,然后将每个字符及其对应的词频写入文件。

⑤存储压缩数据:再次读取待压缩文件的每个字节byte,由

dictionary[(unsigned int)byte]得到对应的编码(注意每个字符

编码的长度不一),使用位运算一次将编码中的每个位(BIT)设置到一个char 类型的位缓冲中,可能多个编码才能填满一个

位缓冲,每填满一次,将位缓冲区以单个字节的形式写入文件。当文件遍历完成的时候,文件的压缩也就完成了。

二、文件解压:

①读取词频:读取压缩文件,将每个字符的出现次数存入数组statistic

②构造哈夫曼编码树:根据statistic数组构造哈夫曼编码树

③继续读取压缩文件,对于每个字节,使用位运算得到每个位(BIT)。对于每个BIT,根据BIT从根开始遍历哈夫曼树,如果BIT是0就走左分支,如果BIT 是1就走有分支,走到叶子节点的时候,输出对应的字符。走到叶子节点后,重新从哈夫曼树根节点开始匹配每个位。当整个压缩文件读取完毕时,文件解压缩也完成了。

上文介绍了基于哈夫曼算法的文件压缩和解压缩,下面给出基于上述思想的C 语言源代码,一共有5个文件,其中pq.h和pq.c

是优先队列,compress.h和compress.c是压缩和解压缩的实现,main.c是测试文件。

pq.h和pq.c请参见《优先队列(priority_queue)的C语言实现》:

https://www.wendangku.net/doc/5612929195.html,/gropefor/blog/item/7d958eb68359cbe230add14e.html 另外三个文件内容如下:

* File: compress.h

* Purpose: To compress file using the Haffman algorithm

* Author: puresky

* Date: 2011/05/01

*/

#ifndef _FILE_COMPRESSION_H

#define _FILE_COMPRESSION_H

//Haffuman Tree Node

typedef struct HaffumanTreeNode HTN;

struct HaffumanTreeNode

{

char _ch; //character

int _count; //frequency

struct HaffumanTreeNode *_left; //left child

struct HaffumanTreeNode *_right;//rigth child

};

//FileCompress Struct

#define BITS_PER_CHAR 8 //the number of bits in a char

#define MAX_CHARS 256 //the max number of chars

#define FILE_BUF_SIZE 8192 //the size of Buffer for FILE I/O

typedef struct FileCompressStruct FCS;

struct FileCompressStruct

{

HTN *_haffuman; //A pointer to the root of hafumman tree unsigned int _charsCount; //To store the number of chars

unsigned int _total; //Total bytes in a file.

char *_dictionary[MAX_CHARS]; //to store the encoding of each character

int _statistic[MAX_CHARS]; //To store the number of each character };

FCS *fcs_new();

void fcs_compress(FCS *fcs, const char *inFileName, const char

*outFileName);

void fcs_decompress(FCS *fcs, const char *inFileName, const char

*outFileName);

void fcs_free(FCS *fcs);

#endif

* File: compress.c

* Purpose: To compress file using the Haffman algorithm * Author: puresky

* Date: 2011/05/01

*/

#include

#include

#include

#include "compress.h"

#include "pq.h"

static const unsigned char mask[8] =

{

0x80, /* 10000000 */

0x40, /* 01000000 */

0x20, /* 00100000 */

0x10, /* 00010000 */

0x08, /* 00001000 */

0x04, /* 00000100 */

0x02, /* 00000010 */

0x01 /* 00000001 */

};

//static functions of HTN

static HTN *htn_new(char ch, int count)

{

HTN *htn = (HTN *)malloc(sizeof(HTN));

htn->_left = NULL;

htn->_right = NULL;

htn->_ch = ch;

htn->_count = count;

return htn;

}

static void htn_print_recursive(HTN *htn, int depth) {

int i;

if(htn)

{

for(i = 0; i < depth; ++i)

printf(" ");

printf("%d:%d\n", htn->_ch, htn->_count); htn_print_recursive(htn->_left, depth + 1);

htn_print_recursive(htn->_right, depth + 1);

}

}

static void htn_print(HTN *htn)

{

htn_print_recursive(htn, 0);

}

static void htn_free(HTN *htn)

{

if(htn)

{

htn_free(htn->_left);

htn_free(htn->_right);

free(htn);

}

}

//static functions of FCS

static void fcs_generate_statistic(FCS *fcs, const char *inFileName) {

int ret, i;

unsigned char buf[FILE_BUF_SIZE];

FILE *pf = fopen(inFileName, "rb");

if(!pf)

{

fprintf(stderr, "can't open file:%s\n", inFileName);

return;

}

while((ret = fread(buf, 1, FILE_BUF_SIZE, pf)) > 0)

{

fcs->_total += ret;

for(i = 0; i < ret; ++i)

{

if(fcs->_statistic[buf[i]] == 0)

fcs->_charsCount++;

fcs->_statistic[buf[i]]++;

}

}

fclose(pf);

}

static void fcs_create_haffuman_tree(FCS *fcs)

{

int i, count;

HTN *htn, *parent, *left, *right;

KeyValue *kv, *kv1, *kv2;

PriorityQueue *pq;

pq = priority_queue_new(PRIORITY_MIN);

for(i = 0; i < MAX_CHARS; ++i)

{

if(fcs->_statistic[i])

{

htn = htn_new((char)i, fcs->_statistic[i]); kv = key_value_new(fcs->_statistic[i], htn); priority_queue_enqueue(pq, kv);

}

}

//fprintf(stdout, "the number of haffuman leaf is %d\n", priority_queue_size(pq));

while(!priority_queue_empty(pq))

{

//fprintf(stdout, "priority queue size:%d\n", priority_queue_size(pq));

kv1 = priority_queue_dequeue(pq);

kv2 = priority_queue_dequeue(pq);

if(kv2 == NULL)

{

fcs->_haffuman = kv1->_value;

key_value_free(kv1, NULL);

}

else

{

left = (HTN *)kv1->_value;

right = (HTN *)kv2->_value;

count = left->_count + right->_count;

key_value_free(kv1, NULL);

key_value_free(kv2, NULL);

parent = htn_new(0, count);

parent->_left = left;

parent->_right = right;

kv = key_value_new(count, parent);

priority_queue_enqueue(pq, kv);

}

}

priority_queue_free(pq, NULL);

//htn_print(fcs->_haffuman);

}

static void fcs_generate_dictionary_recursively(HTN *htn, char

*dictionary[], char path[], int depth)

{

char *code = NULL;

if(htn)

{

if(htn->_left == NULL && htn->_right == NULL)

{

code = (char *)malloc(sizeof(char) * (depth + 1)); memset(code, 0, sizeof(char) * (depth + 1));

memcpy(code, path, depth);

dictionary[(unsigned char)htn->_ch] = code;

}

if(htn->_left)

{

path[depth] = '0';

fcs_generate_dictionary_recursively(htn->_left, dictionary, path, depth + 1);

}

if(htn->_right)

{

path[depth] = '1';

fcs_generate_dictionary_recursively(htn->_right, dictionary, path, depth + 1);

}

}

}

static void fcs_generate_dictionary(FCS *fcs)

{

char path[32];

fcs_generate_dictionary_recursively(fcs->_haffuman,

fcs->_dictionary, path, 0);

//fcs_print_dictionary(fcs);

}

static void fcs_print_dictionary(FCS *fcs)

{

int i;

for(i = 0; i < MAX_CHARS; ++i)

if(fcs->_dictionary[i] != NULL)

fprintf(stdout, "%d:%s\n", i, fcs->_dictionary[i]); }

static void fcs_write_statistic(FCS *fcs, FILE *pf)

{

int i;

fprintf(pf, "%d\n", fcs->_charsCount);

for(i = 0; i < MAX_CHARS; ++i)

if(fcs->_statistic[i] != 0)

fprintf(pf, "%d %d\n", i, fcs->_statistic[i]);

}

static void fcs_do_compress(FCS *fcs, const char *inFileName, const char* outFileName)

{

int i, j, ret;

char *dictEntry, len;

unsigned int bytes;

char bitBuf;

int bitPos;

unsigned char inBuf[FILE_BUF_SIZE];

FILE *pfIn, *pfOut;

pfIn = fopen(inFileName, "rb");

if(!pfIn)

{

fprintf(stderr, "can't open file:%s\n", inFileName);

return;

}

pfOut = fopen(outFileName, "wb");

if(!pfOut)

{

fclose(pfIn);

fprintf(stderr, "can't open file:%s\n", outFileName);

return;

}

fcs_write_statistic(fcs, pfOut);

bitBuf = 0x00;

bitPos = 0;

bytes = 0;

while((ret = fread(inBuf, 1, FILE_BUF_SIZE, pfIn)) > 0)

{

for(i = 0; i < ret; ++i)

{

len = strlen(fcs->_dictionary[inBuf[i]]);

dictEntry = fcs->_dictionary[inBuf[i]];

//printf("%s\n", dictEntry);

for(j = 0; j < len; ++j)

{

if(dictEntry[j] == '1')

{

bitBuf |= mask[bitPos++];

}

else

{

bitPos++;

}

if(bitPos == BITS_PER_CHAR)

{

fwrite(&bitBuf, 1, sizeof(bitBuf), pfOut);

bitBuf = 0x00;

bitPos = 0;

bytes++;

}

}

}

}

if(bitPos != 0)

{

fwrite(&bitBuf, 1, sizeof(bitBuf), pfOut);

bytes++;

}

fclose(pfIn);

fclose(pfOut);

printf("The compression ratio is:%f%%\n",

(fcs->_total - bytes) * 100.0 / fcs->_total);

}

static void fcs_read_statistic(FCS *fcs, FILE *pf)

{

int i, charsCount = 0;

int ch;

int num;

fscanf(pf, "%d\n", &charsCount);

fcs->_charsCount = charsCount;

for(i = 0; i < charsCount; ++i)

{

fscanf(pf, "%d %d\n", &ch, &num);

fcs->_statistic[(unsigned int)ch] = num;

fcs->_total += num;

}

}

static void fcs_do_decompress(FCS *fcs, FILE *pfIn, const char

*outFileName)

{

int i, j, ret;

unsigned char ch;

HTN *htn;

unsigned char buf[FILE_BUF_SIZE];

unsigned char bitCode;

int bitPos;

FILE *pfOut;

pfOut = fopen(outFileName, "wb");

if(!pfOut)

{

fprintf(stderr, "can't open file:%s\n", outFileName); return;

}

htn = fcs->_haffuman;

bitCode = 0x00;

bitPos = 0;

while((ret = fread(buf, 1, FILE_BUF_SIZE, pfIn)) > 0)

{

for(i = 0; i < ret; ++i)

{

ch = buf[i];

for(j = 0; j < BITS_PER_CHAR; ++j)

{

if(ch & mask[j])

{

htn = htn->_right;

}

else

{

htn = htn->_left;

}

if(htn->_left == NULL && htn->_right == NULL) //leaf

{

if(fcs->_total > 0)

{

fwrite(&htn->_ch, 1, sizeof(char), pfOut);

fcs->_total--;

}

htn = fcs->_haffuman;

}

}

}

}

fclose(pfOut);

}

//FCS functions

FCS *fcs_new()

{

FCS *fcs = (FCS *)malloc(sizeof(FCS));

fcs->_charsCount = 0;

fcs->_total = 0;

memset(fcs->_statistic, 0, sizeof(fcs->_statistic));

memset(fcs->_dictionary, 0, sizeof(fcs->_dictionary));

fcs->_haffuman = NULL;

return fcs;

}

void fcs_free(FCS *fcs)

{

int i;

if(fcs)

{

if(fcs->_haffuman)

htn_free(fcs->_haffuman);

for(i = 0; i < MAX_CHARS; ++i)

free(fcs->_dictionary[i]);

free(fcs);

}

}

void fcs_compress(FCS *fcs, const char *inFileName, const char

*outFileName)

{

fprintf(stdout, "To compress file: %s ...\n", inFileName);

fcs_generate_statistic(fcs, inFileName);

fcs_create_haffuman_tree(fcs);

fcs_generate_dictionary(fcs);

fcs_do_compress(fcs, inFileName, outFileName);

fprintf(stdout, "The compressed data of file: %s stored at %s!\n", inFileName, outFileName);

}

void fcs_decompress(FCS *fcs, const char *inFileName, const char

*outFileName)

{

FILE *pfIn;

fprintf(stdout, "To decompress file: %s ...\n", inFileName);

pfIn= fopen(inFileName, "rb");

if(!pfIn)

{

fprintf(stderr, "can't open file: %s\n", inFileName);

return ;

}

fcs_read_statistic(fcs, pfIn);

fcs_create_haffuman_tree(fcs);

fcs_generate_dictionary(fcs);

fcs_do_decompress(fcs, pfIn, outFileName);

fclose(pfIn);

fprintf(stdout, "The decompressed data of file: %s stored at %s\n", inFileName, outFileName);

}

/*

* File: main.c

* Purpose: testing File Compression

* Author:puresky

* Date: 2011/05/01

*/

#include

#include "compress.h"

const int DO_COMPRESS = 1;

const int DO_DECOMPRESS = 1;

const char *InFile = "data.txt"; //The file to compress.

const char *CompressedFile = "data.hfm"; //Compressed data of the file. const char *OutFile = "data2.txt"; //The decompressed file of the data.

int main(int argc, char **argv)

{

//1. compress file

if(DO_COMPRESS)

{

FCS *fcs1;

fcs1 = fcs_new();

fcs_compress(fcs1, InFile, CompressedFile);

fcs_free(fcs1);

}

//2. decompress file

if(DO_DECOMPRESS)

{

FCS *fcs2;

fcs2 = fcs_new();

fcs_decompress(fcs2, CompressedFile, OutFile);

fcs_free(fcs2);

}

system("pause");

return 0;

}

优先队列(priority_queue)和一般队列(queue)的函数接口一致,不同的是,优先队列每次出列的是整个队列中

最小(或者最大)的元素。

本文简要介绍一种基于数组二叉堆实现的优先队列,定义的数据结构和实现的函数接口说明如下:

一、键值对结构体:KeyValue

// =============KeyValue Struct================================== typedef struct key_value_struct KeyValue;

struct key_value_struct

{

int _key;

void *_value;

};

KeyValue *key_value_new(int key, void *value);

void key_value_free(KeyValue *kv, void (*freevalue)(void *));

键值对作为优先队列的中数据的保存形式,其中key用于保存优先级,_value

用于指向实际的数据。

key_value_new用于创建一个KeyValue结构体;key_value_free用于释放一个KeyValue结构体的内存,

参数freevalue用于释放数据指针_value指向的内存。

二、优先队列结构体:PriorityQueue

// =============PriorityQueue Struct==============================

#define PRIORITY_MAX 1

#define PRIORITY_MIN 2

typedef struct priority_queue_struct PriorityQueue;

struct priority_queue_struct

{

KeyValue **_nodes;

int _size;

int _capacity;

int _priority;

};

PriorityQueue *priority_queue_new(int priority);

void priority_queue_free(PriorityQueue *pq, void (*freevalue)(void *)); const KeyValue *priority_queue_top(PriorityQueue *pq);

KeyValue *priority_queue_dequeue(PriorityQueue *pq);

void priority_queue_enqueue(PriorityQueue *pq, KeyValue *kv);

int priority_queue_size(PriorityQueue *pq);

int priority_queue_empty(PriorityQueue *pq);

void priority_queue_print(PriorityQueue *pq);

1) 其中nodes字段是二叉堆数组,_capacity是nodes指向的KeyValue*指针的个数,_size是nodes中实际存储的元素个数。

_priority可以是PRIORITY_MAX或PRIORITY_MIN,分别表示最大元素优先和最小元素优先。

2) priority_queue_new和priority_queue_free分别用于创建和释放优先队列。

3) priority_queue_top用于取得队列头部元素,

4)priority_queue_dequeue用于取得队列头部元素并将元素出列。

其实现的基本思路,以最大优先队列说明如下:

①将队列首部nodes[0]保存作为返回值

②将队列尾部nodes[_size-1]置于nodes[0]位置,并令_size=_size-1

③令当前父节点parent(nodes[i])等于新的队列首部(i=0)元素,parent

指向元素的儿子节点为left = nodes[2 * i + 1]和rigth = nodes[2 * i + 2],比较left和right得到优先级高的儿子节点,设为nodes[j](j = 2 *i + 1或2 *i + 2),

④如果当前父节点parent的优先级高于nodes[j],交换nodes[i]和

nodes[j],并更新当前父节点,即令i=j,并循环③;

如果当前父节点的优先级低于nodes[j],处理结束。

5)priority_queue_enqueue用于将KeyValue入列

其实现的基本思路,以最大优先队列说明如下:

①设置nodes[_size] 为新的KeyValue,并令_size++

②令当前儿子节点child(nodes[i])为新的队列尾部节点(i=_size-1),child的父节点parent为nodes[j],其中j= (i - 1) / 2

③如果当前儿子节点child的优先级高于parent, 交换nodes[i]和

nodes[j],并更新当前儿子节点即令i = j,并循环③;

如果当前儿子节点的优先级低于parent,处理结束。

6) priority_queue_size用于取得队列中元素个数,priority_queue_empty 用于判断队列是否为空。

7)priority_queue_print用于输出队列中的内容。

文件pq.h给出了数据结构和函数的声明,文件pq.c给出了具体实现,main.c 文件用于测试。虽然是使用

过程化编程的C语言,可以看到具体的编码中应用了基于对象的思想,我们对数据结构和相关函数做了一定程度的

聚集和封装。

/*

*File: pq.h

*purpose: declaration of priority queue in C

*Author:puresky

*Date:2011/04/27

*/

#ifndef _PRIORITY_QUEUE_H

#define _PRIORITY_QUEUE_H

// =============KeyValue Struct================================== typedef struct key_value_struct KeyValue;

struct key_value_struct

{

int _key;

void *_value;

};

KeyValue *key_value_new(int key, void *value);

void key_value_free(KeyValue *kv, void (*freevalue)(void *));

// =============PriorityQueue Struct==============================

#define PRIORITY_MAX 1

#define PRIORITY_MIN 2

typedef struct priority_queue_struct PriorityQueue;

struct priority_queue_struct

{

KeyValue **_nodes;

int _size;

int _capacity;

int _priority;

};

PriorityQueue *priority_queue_new(int priority);

void priority_queue_free(PriorityQueue *pq, void (*freevalue)(void *)); const KeyValue *priority_queue_top(PriorityQueue *pq);

KeyValue *priority_queue_dequeue(PriorityQueue *pq);

void priority_queue_enqueue(PriorityQueue *pq, KeyValue *kv);

int priority_queue_size(PriorityQueue *pq);

int priority_queue_empty(PriorityQueue *pq);

void priority_queue_print(PriorityQueue *pq);

#endif

/*

*File:pq.c

*purpose: definition of priority queue in C

*Author:puresky

*Date:2011/04/27

*/

#include

#include

#include

#include "pq.h"

//Private Functions

static void priority_queue_realloc(PriorityQueue *pq);

static void priority_queue_adjust_head(PriorityQueue *pq);

static void priority_queue_adjust_tail(PriorityQueue *pq);

static int priority_queue_compare(PriorityQueue *pq,

int pos1,

int pos2);

static void priority_queue_swap(KeyValue **nodes,

int pos1,

int pos2);

//Functions of KeyValue Struct

KeyValue *key_value_new(int key,

void *value)

{

KeyValue *pkv = (KeyValue *)malloc(sizeof(KeyValue));

pkv->_key = key;

pkv->_value = value;

return pkv;

}

void key_value_free(KeyValue *kv,

void (*freevalue)(void *))

{

if(kv)

{

if(freevalue)

{

freevalue(kv->_value);

}

free(kv);

}

}

//Functions of PriorityQueue Struct

PriorityQueue *priority_queue_new(int priority)

{

PriorityQueue *pq = (PriorityQueue

*)malloc(sizeof(PriorityQueue));

pq->_capacity = 11; //default initial value

pq->_size = 0;

pq->_priority = priority;

pq->_nodes = (KeyValue **)malloc(sizeof(KeyValue *) *

pq->_capacity);

return pq;

}

void priority_queue_free(PriorityQueue *pq,

void (*freevalue)(void *)) {

int i;

if(pq)

{

for(i = 0; i < pq->_size; ++i)

key_value_free(pq->_nodes[i], freevalue);

free(pq->_nodes);

free(pq);

}

}

const KeyValue *priority_queue_top(PriorityQueue *pq)

{

if(pq->_size > 0)

return pq->_nodes[0];

return NULL;

}

KeyValue *priority_queue_dequeue(PriorityQueue *pq) {

KeyValue *pkv = NULL;

if(pq->_size > 0)

{

pkv = pq->_nodes[0];

priority_queue_adjust_head(pq);

}

return pkv;

}

void priority_queue_enqueue(PriorityQueue *pq,

KeyValue *kv) {

printf("add key:%d\n", kv->_key);

pq->_nodes[pq->_size] = kv;

priority_queue_adjust_tail(pq);

if(pq->_size >= pq->_capacity)

priority_queue_realloc(pq);

}

int priority_queue_size(PriorityQueue *pq)

{

return pq->_size;

}

int priority_queue_empty(PriorityQueue *pq)

{

return pq->_size <= 0;

}

void priority_queue_print(PriorityQueue *pq)

{

int i;

KeyValue *kv;

printf("data in the pq->_nodes\n");

for(i = 0; i < pq->_size; ++i)

printf("%d ", pq->_nodes[i]->_key);

printf("\n");

printf("dequeue all data\n");

while(!priority_queue_empty(pq))

关于计算极限的几种方法

目录 摘要 (1) 引言 (2) 一.利用导数定义求极限 (2) 二.利用中值定理求极限 (2) 三.利用定积分定义求极限 (3) 四.利用施笃兹公式 (4)

五.利用泰勒公式 (5) 六.级数法 (5) 七.结论 (6) 参考文献 (6)

内容摘要

引言: 极限是分析数学中最基本的概念之一,用以描述变量在一定的变化过程中的终极状态。早在中国古代,极限的朴素思想和应用就已在文献中有记载。例如,3世纪中国数学家刘徽的割圆术,就是用圆内接正多边形周长的极限是圆周长这一思想来近似地计算圆周率 的。随着微积分学的诞生,极限作为数学中的一个概念也就明确提出。但最初提出的这一概念是含糊不清的,因此在数学界引起不少争论甚至怀疑。直到19世纪,由A.-L.柯西、K. (T.W.)外尔斯特拉斯等人的工作,才将其置于严密的理论基础之上,从而得到举世一致的公认。 数学分析中的基本概念的表述,都可以用极限来描述。如函数()x f y =在 0x x =处导数的定义,定积分的定义,偏导数的定义,二重积分,三重积分的定义,无穷级数收敛的定义,都是用极限来定义的。极限是研究数学分析的基本公具。极限是贯穿数学分析的一条主线。 一.利用导数定义求极限 据文[]1定理1导数的定义:函数)(x f 在0x 附近有定义,对于任意的x ?, 则)()(00x f x x f y -?+=? 如果x x f x x f x x ?-?+=→?→? ) ()(lim lim 000 0存在,则此极限值就 称函数)(x f 在点0x 的导数记为 )('0x f .即x x f x x f x f x ?-?+=→?) ()(lim )('0000在这 种方法的运用过程中。首先要选好)(x f ,然后把所求极限。表示成)(x f 在定点0x 的导数。 例1:求a x x a a x x a a a a x --→lim 解:原式0)(lim lim 1lim 0---?=---=-→→→a x x a a x a a x a x x a a a x x a a a a x a a a a a x x a x x ,令a x x a y -=, 当a x →时,0→y ,故原式a a a a a a a y y a ln |)'(0=?== 一般地,能直接运用导数定义求的极限就直接用导数定义来求,值得注意的是许

中衡算法分析与【设计明细】-实验二-哈夫曼编码

昆明理工大学信息工程与自动化学院学生实验报告 (201 —201 学年第一学期) 课程名称:算法设计与分析开课实验室:年月日 一、上机目的及内容 1.上机内容 设需要编码的字符集为{d1, d2, …, dn},它们出现的频率为{w1, w2, …, wn},应用哈夫曼树构造最短的不等长编码方案。 2.上机目的 (1)了解前缀编码的概念,理解数据压缩的基本方法; (2)掌握最优子结构性质的证明方法; (3)掌握贪心法的设计思想并能熟练运用。 二、实验原理及基本技术路线图(方框原理图或程序流程图) (1)证明哈夫曼树满足最优子结构性质; (2)设计贪心算法求解哈夫曼编码方案; (3)设计测试数据,写出程序文档。 数据结构与算法: typedef char *HuffmanCode; //动态分配数组,存储哈夫曼编码 typedef struct { unsigned int weight; //用来存放各个结点的权值 unsigned int parent,LChild,RChild; //指向双亲、孩子结点的指针 } HTNode, *HuffmanTree; //动态分配数组,存储哈夫曼树 程序流程图:

三、所用仪器、材料(设备名称、型号、规格等或使用软件) 1台PC及VISUAL C++6.0软件

四、实验方法、步骤(或:程序代码或操作过程) 程序代码: #include #include #include typedef struct { unsigned int weight; unsigned int parent,LChild,RChild; } HTNode, *HuffmanTree; //动态分配数组,存储哈夫曼树 typedef char *HuffmanCode; //动态分配数组,存储哈夫曼编码 void Select(HuffmanTree *ht,int n,int *s1,int *s2) { int i,min; for(i=1; i<=n; i++) { if((*ht)[i].parent==0) { min=i; break; } } for(i=1; i<=n; i++) { if((*ht)[i].parent==0) { if((*ht)[i].weight<(*ht)[min].weight) min=i; } } *s1=min; for(i=1; i<=n; i++) { if((*ht)[i].parent==0 && i!=(*s1)) { min=i; break; } } for(i=1; i<=n; i++) { if((*ht)[i].parent==0 && i!=(*s1)) { if((*ht)[i].weight<(*ht)[min].weight)

常用图像压缩方法

常用图像压缩方法 概述了常用的图像压缩方法,包括行程长度压缩,霍夫曼编码压缩,LZW压缩方法,算术压缩方法,JPEG压缩等。 一、行程长度压缩 原理是将一扫描行中的颜色值相同的相邻像素用一个计数值和那些像素的颜色值来代替。例如:aaabccccccddeee,则可用3a1b6c2d3e来代替。对于拥有大面积,相同颜色区域的图像,用RLE压缩方法非常有效。由RLE原理派生出许多具体行程压缩方法: 1. PCX行程压缩方法 该算法实际上是位映射格式到压缩格式的转换算法,该算法对于连续出现1次的字节Ch,若Ch>0xc0则压缩时在该字节前加上0xc1,否则直接输出Ch,对于连续出现N次的字节Ch,则压缩成0xc0+N,Ch这两个字节,因而N最大只能为ff-c0=3fh(十进制为63),当N大于63时,则需分多次压缩。 2. BI_RLE8压缩方法 在WINDOWS3.0、3.1的位图文件中采用了这种压缩方法。该压缩方法编码也是以两个字节为基本单位。其中第一个字节规定了用第二个字节指定的颜色重复次数。如编码0504表示从当前位置开始连续显示5个颜色值为04的像素。当第二个字节为零时第二个字节有特殊含义:0表示行末;1 表示图末;2转义后面2个字节,这两个字节分别表示下一像素相对于当前位置的水平位移和垂直位移。这种压缩方法所能压缩的图像像素位数最大为8位(256色)图像。 3. BI_RLE压缩方法 该方法也用于WINDOWS3.0/3.1位图文件中,它与BI_RLE8编码类似,唯一不同是:BI_RLE4的一个字节包含了两个像素的颜色,因此,它只能压缩的颜色数不超过16的图像。因而这种压缩应用范围有限。 4. 紧缩位压缩方法(Packbits) 该方法是用于Apple公司的Macintosh机上的位图数据压缩方法,TIFF规范中使用了这种方法,这种压缩方法与BI_RLE8压缩方法相似,如 1c1c1c1c2132325648压缩为:831c2181325648,显而易见,这种压缩方法最好情况是每连续128个字节相同,这128个字节可压缩为一个数值7f。这种方法还是非常有效的。

贪心算法构造哈夫曼树

软件02 1311611006 张松彬利用贪心算法构造哈夫曼树及输出对应的哈夫曼编码 问题简述: 两路合并最佳模式的贪心算法主要思想如下: (1)设w={w0,w1,......wn-1}是一组权值,以每个权值作为根结点值,构造n棵只有根的二叉树 (2)选择两根结点权值最小的树,作为左右子树构造一棵新二叉树,新树根的权值是两棵子树根权值之和 (3)重复(2),直到合并成一颗二叉树为 一、实验目的 (1)了解贪心算法和哈夫曼树的定义(2)掌握贪心法的设计思想并能熟练运用(3)设计贪心算法求解哈夫曼树(4)设计测试数据,写出程序文档 二、实验内容 (1)设计二叉树结点数据结构,编程实现对用户输入的一组权值构造哈夫曼树(2)设计函数,先序遍历输出哈夫曼树各结点3)设计函数,按树形输出哈夫曼树 代码: #include #include #include #include typedef struct Node{ //定义树结构 int data; struct Node *leftchild; struct Node *rightchild; }Tree; typedef struct Data{ //定义字符及其对应的频率的结构 int data;//字符对应的频率是随机产生的 char c; }; void Initiate(Tree **root);//初始化节点函数 int getMin(struct Data a[],int n);//得到a中数值(频率)最小的数 void toLength(char s[],int k);//设置有k个空格的串s void set(struct Data a[],struct Data b[]);//初始化a,且将a备份至b char getC(int x,struct Data a[]);//得到a中频率为x对应的字符 void prin(struct Data a[]);//输出初始化后的字符及对应的频率 int n; void main() { //srand((unsigned)time(NULL));

求极限的13种方法

求极限的13种方法(简叙) 龘龖龍 极限概念与求极限的运算贯穿了高等数学课程的始终,极限思想亦是高等数学的核心与基础,因此,全面掌握求极限的方法与技巧是高等数学的基本要求。本篇较为全面地介绍了求数列极限与函数极限的各种方法,供同学参考。 一、利用恒等变形求极限 利用恒等变形求极限是最基础的一种方法,但恒等变形灵活多变,令人难以琢磨。常用的的恒等变形有:分式的分解、分子或分母有理化、三角函数的恒等变形、某些求和公式与求积公式的利用等。 例1、求极限 )1...()1)(1(22 lim n a a a n +++∞ → ,其中1

提高运算效率。常用的变量代换有倒代换、整体代换、三角代换等。 例2、求极限1 1lim 1 --→n m x x x ,其中m,n 为正整数。 分析 这是含根式的(0 )型未定式,应先将其利用变量代换进行化简,再进一步计算极限。 解 令11,1→→=t x x t mn 时,则当 原式=m n t t t t t t t t t t t t m m n n m m n n t m n t =++++++=+++-+++-=----------→→1...1...)1...)(1()1...)(1(lim 11lim 2121212111 三、利用对数转换求极限 利用对数转换求极限主要是通过公式,ln v u v e u ?=进行恒等变形,特别的情形,在(∞1)型未定式时可直接运用v u v e u ?-=)1( 例3、求极限o x →lim x x 2csc ) (cos 解 原式=o x →lim 2 1sin sin 21 lim csc )1(cos 2202 - --==→e e e x x x x x 四、利用夹逼准则求极限 利用夹逼准则求极限主要应用于表达式易于放缩的情形。 例4、求极限∞ →n lim n n n ! 分析 当我们无法或不易把无穷多个因子的积变为有限时,可考虑使用夹逼准则。 解 因为n n n n n n n n n o n 1121!≤?-??=≤ , 且不等式两端当趋于无穷时都以0为极限,所以∞ →n lim n n n ! =0 五、利用单调有界准则求极限 利用单调有界准则求极限主要应用于给定初始项与递推公式

实验三.哈夫曼编码的贪心算法设计

实验四 哈夫曼编码的贪心算法设计(4学时) [实验目的] 1. 根据算法设计需要,掌握哈夫曼编码的二叉树结构表示方法; 2. 编程实现哈夫曼编译码器; 3. 掌握贪心算法的一般设计方法。 实验目的和要求 (1)了解前缀编码的概念,理解数据压缩的基本方法; (2)掌握最优子结构性质的证明方法; (3)掌握贪心法的设计思想并能熟练运用 (4)证明哈夫曼树满足最优子结构性质; (5)设计贪心算法求解哈夫曼编码方案; (6)设计测试数据,写出程序文档。 实验内容 设需要编码的字符集为{d 1, d 2, …, dn },它们出现的频率为 {w 1, w 2, …, wn },应用哈夫曼树构造最短的不等长编码方案。 核心源代码 #include #include #include typedef struct { unsigned int weight; //用来存放各个结点的权值 unsigned int parent,LChild,RChild; //指向双亲、孩子结点的指针 } HTNode, *HuffmanTree; //动态分配数组,存储哈夫曼树 typedef char *HuffmanCode; //动态分配数组,存储哈夫曼编码 ∑=j i k k a

//选择两个parent为0,且weight最小的结点s1和s2 void Select(HuffmanTree *ht,int n,int *s1,int *s2) { int i,min; for(i=1; i<=n; i++) { if((*ht)[i].parent==0) { min=i; break; } } for(i=1; i<=n; i++) { if((*ht)[i].parent==0) { if((*ht)[i].weight<(*ht)[min].weight) min=i; } } *s1=min; for(i=1; i<=n; i++)

极限压缩文件方法

极限压缩文件方法 介绍如何使1G的文件压缩到1M的文件。 1.常见文件压缩 首先我们用WinRAR的最高压缩率对常见的文本文件、程序文件和多媒体文件进行压缩,其压缩结果如下(见图1): 压缩后分别还是挺大的 从上图可以看出,多媒体文件压缩比最低,与原文件相差无几,而文本文件和程序文件压缩比要高一些,最高达到3:1,从实际经验来看,我们平时常见的文件压缩比都在10倍以下。 那么,再来看看这个RAR压缩包(见图2),注意其中的原文件大小和压缩后的包裹大小分别为16777215和18407,这是多大的比例?笔者用计算器算了一下,约等于911:1,接近1000倍的压缩比!这是怎么回事?真的假的?跟我一起继续做下面的试验就明白了。 这个简直是不可思议 2.把大象装进瓶子里 这里笔者从自己的电脑里随便找了个文件“数字图像噪声和去除.htm”,这是笔者在浏览网页时使用另存为功能从网上下载的文章,大小为125KB。 第一步:压缩为ZIP文件。右键单击“数字图像噪声和去除.htm”文件,选择

“WinRAR→添加到档案文件”,在压缩选项对话框中选择“档案文件类型”为“ZIP”,“压缩方式”为“最好”(见图3),单击“确定”开始压缩。可以看到压缩后的“数字图像噪声和去除.zip”文件只有19KB,压缩率还不错,不过仍离我们的目标相去甚远。 第二步:用WinRAR打开“数字图像噪声和去除.zip”,记下“大小”列中显示的原文件大小数值“127594”,打开计算器程序,单击“查看”菜单选择“科学型”,输入数字“127594”,再点击“十六进制”选项将其转换为16进制值,结果是“1F26A”(见图4)。 用科学型计算器认真算一下 第三步:用UltraEdit编辑器打开“数字图像噪声和去除.zip”文件,我们要在文件中找到“1F26A”的数据,不过由于文件中的十六进制数是高低位倒置表示的,所

数据结构哈夫曼树的实现

#include #include #include #include using namespace std; typedef struct { unsigned int weight; unsigned int parent,lchild,rchild,ch; }HTNode,*HuffmanTree; //动态分配数组存储哈夫曼树 typedef char *HuffmanCode; //动态分配数组存储哈夫曼编码表 int m,s1,s2; HuffmanTree HT; void Select(int n){ //选择两个权值最小的结点 int i,j; for(i=1;i<=n;i++){ if(!HT[i].parent){ s1 = i;break; } } for(j=i+1;j<=n;j++){ if(!HT[j].parent){ s2 = j;break; } } for(i=1;i<=n;i++){ if((HT[s1].weight>HT[i].weight)&&(!HT[i].parent)&&(s2!=i)){ s1=i; } } for(j=1;j<=n;j++){ if((HT[s2].weight>HT[j].weight)&&(!HT[j].parent)&&(s1!=j)) s2=j; } } void HuffmanCoding(HuffmanCode HC[], int *w, int n) { // w存放n个字符的权值(均>0),构造哈夫曼树HT,// 并求出n个字符的哈夫曼编码HC int i, j; char *cd; int p; int cdlen; int start; if (n<=1) return;

高等数学求极限的常用方法

高等数学求极限的14种方法 一、极限的定义 1.极限的保号性很重要:设 A x f x x =→)(lim 0 , (i )若A 0>,则有0>δ,使得当δ<-<||00x x 时,0)(>x f ; (ii )若有,0>δ使得当δ<-<||00x x 时,0A ,0)(≥≥则x f 。 2.极限分为函数极限、数列极限,其中函数极限又分为∞→x 时函数的极限和0x x →的极限。要特别注意判定极限是否存在在: (i )数列{} 的充要条件收敛于a n x 是它的所有子数列均收敛于a 。常用的是其推论,即“一个数列收敛于a 的充要条件是其奇子列和偶子列都收敛于a ” (ii )A x x f x A x f x =+∞ →=-∞ →?=∞ →lim lim lim )()( (iii) A x x x x A x f x x =→=→?=→+ - lim lim lim 0 )( (iv)单调有界准则 (v )两边夹挤准则(夹逼定理/夹逼原理) (vi )柯西收敛准则(不需要掌握)。极限 ) (lim 0 x f x x →存在的充分必要条件是: εδεδ<-∈>?>?|)()(|)(,0,021021x f x f x U x x o 时,恒有、使得当 二.解决极限的方法如下: 1.等价无穷小代换。只能在乘除.. 时候使用。例题略。 2.洛必达(L ’hospital )法则(大题目有时候会有暗示要你使用这个方法) 它的使用有严格的使用前提。首先必须是X 趋近,而不是N 趋近,所以面对数列极限时候先要转化成求x 趋近情况下的极限,数列极限的n 当然是趋近于正无穷的,不可能是负无穷。其次,必须是函数的导数要存在,假如告诉f (x )、g (x ),没告诉是否可导,不可直接用洛必达法则。另外,必须是“0比0”或“无穷大比无穷大”,并且注意导数分母不能为0。洛必达法则分为3种情况: (i )“ 00”“∞ ∞ ”时候直接用 (ii)“∞?0”“∞-∞”,应为无穷大和无穷小成倒数的关系,所以无穷大都写成了无穷小的倒数形式了。通 项之后,就能变成(i)中的形式了。即)(1)()()()(1)()()(x f x g x g x f x g x f x g x f ==或;) ()(1 )(1 )(1 )()(x g x f x f x g x g x f -=- (iii)“00”“∞1”“0 ∞”对于幂指函数,方法主要是取指数还取对数的方法,即e x f x g x g x f ) (ln )()()(=, 这样就能把幂上的函数移下来了,变成“∞?0”型未定式。 3.泰勒公式(含有x e 的时候,含有正余弦的加减的时候)

哈夫曼编码算法实现完整版

实验三树的应用 一.实验题目: 树的应用——哈夫曼编码 二.实验内容: 利用哈夫曼编码进行通信可以大大提高信道的利用率,缩短信息传输的时间,降低传输成本。根据哈夫曼编码的原理,编写一个程序,在用户输入结点权值的基础上求哈夫曼编码。 要求:从键盘输入若干字符及每个字符出现的频率,将字符出现的频率作为结点的权值,建立哈夫曼树,然后对各个字符进行哈夫曼编码,最后打印输出字符及对应的哈夫曼编码。 三、程序源代码: #include #include #include #include typedef struct{ char data; int weight; int parent,lchild,rchild; }HTNode,*HuffmanTree; typedef char * * HuffmanCode; void Select(HuffmanTree &HT,int n,int m) {HuffmanTree p=HT; int tmp; for(int j=n+1;j<=m;j++) {int tag1,tag2,s1,s2; tag1=tag2=32767; for(int x=1;x<=j-1;x++) { if(p[x].parent==0&&p[x].weights2) //将选出的两个节点中的序号较小的始终赋给s1 { tmp=s1; s1=s2; s2=tmp;} p[s1].parent=j;

技巧:将Word表格压缩进行到底(多图)

技巧:将Word表格压缩进行到底(多图) 近日从网上下载一个包含Word表格的文件,此表格内容多、尺寸大,要将它排列到A4纸上,着实费了一番功夫,下面就看看我是如何压缩表格的尺寸的。当然减小表格中文字字号是最有效的办法,但要适可而止,主要还是在其他方面下功夫。 设置表格属性 在表格右键单击,从右键菜单中选择“表格属性”,打开“表格属性”对话框(如图1)。在“表格”选项止中,去掉尺寸中“指定宽度”的勾选,同样也将“行”、“列”及“单元格”选项卡中的此处勾选都去掉。单击[确定]按钮,表格自动缩小至各行、列的最小值,如果表格没有反应,尺寸没有缩小,您需要继续下面的设置。 在“表格属性”对话框的“表格”选项卡中,单击[选项]按钮,又打开了“表格选项”对话框(如图2)。勾选“自动调整尺寸以适应内容”复选框,确定后退出,重复去掉指定宽度的设置,则表格的自动缩小尺寸设置才起作用。 此时您还可以继续减小表格尺寸,在图2中,将表格的“默认单元格”间距都修改为“0厘米”,确认退出,此时表格又变小了。 利用表格控制柄 如果您使用的是Word 2000/2002,在表格的右下角会出现一个正方形控制柄,拖动此控制柄,向左上方压缩,直至最小,则快速减小表格的尺寸。 减小行间距、字间距 经过上面的调整,表格的尺寸已经大为减小了,但并不是到了极限,您还可以缩小表格尺寸,通过减小表格中字符的行间距、字间距,可继续缩小表格的尺寸。调整行间距、字间距,分别利用“段落”对话框、“字体”对话框实现! “榨干”Word表格的最后空间 作者:网络雨青更新时间:2005-07-29 收藏此页 【IT168 办公应用】Word中制作表格时,往往会因为一两个字或一行(列)的增加使得表格无法按要 求完成,特别是有字号和其他格式限制时,更让许多新手朋友为了找出这点空间而急得抓耳挠腮。 1.让直接“拖拽”更精确 也许本列只需要再增加1、2mm就不至于使表格多出一行,其他列也许能再挤一挤,而这个数目已是 最大限度了,可是用鼠标拖动表格线时,总是无法达到理想的位置……

哈夫曼树的建立与操作

实验六哈夫曼树的建立与操作 一、实验要求和实验内容 1、输入哈夫曼树叶子结点(信息和权值) 2、由叶子结点生成哈夫曼树内部结点 3、生成叶子结点的哈夫曼编码 4、显示哈夫曼树结点顺序表 二、详细代码(内包含了详细的注释): #include using namespace std; typedef char Elemtype; struct element { int weight; Elemtype date; element* lchild,*rchild; }; class HuffmanTree { public: HuffmanTree()//构造函数 { cout<<"请输入二叉树的个数"<>count; element *s=new element[count];//s为指向数组的指针,保存指向数组的地址 for(int i=0;i>s[i].weight;

cout<<"输入第"<>s[i].date; s[i].lchild=NULL; s[i].rchild=NULL; }//以上为初始化每一个结点 element * *m=new element*[count];//m为指向数组成员的地址的指针,保存【指向数组成员地址的指针】的地址 for(int i=0;iweightweight; return1=i; } } for(int i=0;iweightweight>a) { b=m[i]->weight; return2=i; } } q=new element;//构建一棵新树 q->weight=m[return1]->weight+m[return2]->weight; q->lchild=m[return1]; q->rchild=m[return2]; m[return1]=q; m[return2]=NULL; //用新树替换原来的两子树,并置空一个数 } boot=q;//把最后取得的哈夫曼树的头结点即q赋值给boot

求极限13种方法

求极限的 13种方法(简叙) 龘龖龍 极 限概念与求极限的运算贯穿了高等数学课程的始终, 极限思想亦是高等数学的核心与 基础, 因此,全面掌握求极限的方法与技巧是高等数学的基本要求。 本篇较为全面地介绍了 求数列极限与函数极限的各种方法,供同学参考。 一、利用恒等变形求极限 利用恒等变形求极限是最基础的一种方法,但恒等变形灵活多 变,令人难以琢磨。常用的的恒等变形有:分式的分解、分子或分母 有理化、三角函数的恒等变形、某些求和公式与求积公式的利用等。 n 例 1、求极限 lim (1 a)(1 a 2 )...(1 a 2 ) ,其中 a 1 n 分析 由于积的极限等于极限的积这一法则只对有限个因子成立, n 因为 (1 a)(1 a 2 )...(1 a 2 ) 1 (1 a)(1 a)(1 a 2 )...(1 a 2 1a 1 2 2 2 n (1 a 2)(1 a 2 )...(1 a 2 ) 1a 1 2 n 1 11a (1 a 2 ) 2 2n 0,从而 lim (1 a)(1 a 2 )...(1 a 2 )= n 1 a 二、利用变量代换求极限 利用变量代换求极限的主要目的是化简原表达式,从而减少运算量, 提高运算效率。常用的变量代换有倒代换、整体代换、三角代换等。 此, 应先对其进行恒等变形。 n 时 2n 1 2 n 1 a 2

例 2、求极限 lim x 1 ,其中 m,n 为正整数。 x 1n x 1 分析 这是含根式的( 0 )型未定式,应先将其利用变量代换进行化 简,再进一步计算极限 1 解 令 t x mn ,则当 x 1时,t 1 三、利用对数转换求极限 原式 = lim e (cos x 1)csc 2 x e xo 四、利用夹逼准则求极限 利用夹逼准则求极限主要应用于表达式易于放缩的情形。 例 4、求极限 l n im n n ! n n n 分析 当我们无法或不易把无穷多个因子的积变为有限时,可考虑使 用夹逼准则。 解 因为 o n n ! 1 2 n 1 n 1 , n n n n n n 且不等式两端当趋于无穷时都以 0为极限,所 以 l n im n n ! =0 n n n 五、利用单调有界准则求极限 利用单调有界准则求极限主要应用于给定初始项与递推公式 原式=l t im 1 t t lim (t 1)(t t 1 (t 1)(t n1 m1 t n 2 ... 1) t m 2 ... t n1 t n 2 ... 1 t m 1 t m 2 (1) 利用对数转换求极限主要是通过公式 u v e lnuv ,进行恒等变形,特别 的情形,在( 1 )型未定式时可直接运用 (u 1) v e 例 3、求极限 l x im o (cosx) csc 2 x 1 2 sin x lim 2 2 x 0 sin 2

哈夫曼树建立、哈夫曼编码算法的实现

#include /*2009.10.25白鹿原*/ #include /*哈夫曼树建立、哈夫曼编码算法的实现*/ #include typedef char* HuffmanCode;/*动态分配数组,存储哈夫曼编码*/ typedef struct { unsigned int weight ; /* 用来存放各个结点的权值*/ unsigned int parent, LChild,RChild ; /*指向双亲、孩子结点的指针*/ }HTNode, * HuffmanTree; /*动态分配数组,存储哈夫曼树*/ void select(HuffmanTree *ht,int n, int *s1, int *s2) { int i; int min; for(i=1; i<=n; i++) { if((*ht)[i].parent == 0) { min = i; i = n+1; } } for(i=1; i<=n; i++) { if((*ht)[i].parent == 0) { if((*ht)[i].weight < (*ht)[min].weight) min = i; } } *s1 = min; for(i=1; i<=n; i++) { if((*ht)[i].parent == 0 && i!=(*s1)) { min = i; i = n+1; } } for(i=1; i<=n; i++) { if((*ht)[i].parent == 0 && i!=(*s1)) {

if((*ht)[i].weight < (*ht)[min].weight) min = i; } } *s2 = min; } void CrtHuffmanTree(HuffmanTree *ht , int *w, int n) { /* w存放已知的n个权值,构造哈夫曼树ht */ int m,i; int s1,s2; m=2*n-1; *ht=(HuffmanTree)malloc((m+1)*sizeof(HTNode)); /*0号单元未使用*/ for(i=1;i<=n;i++) {/*1-n号放叶子结点,初始化*/ (*ht)[i].weight = w[i]; (*ht)[i].LChild = 0; (*ht)[i].parent = 0; (*ht)[i].RChild = 0; } for(i=n+1;i<=m;i++) { (*ht)[i].weight = 0; (*ht)[i].LChild = 0; (*ht)[i].parent = 0; (*ht)[i].RChild = 0; } /*非叶子结点初始化*/ /* ------------初始化完毕!对应算法步骤1---------*/ for(i=n+1;i<=m;i++) /*创建非叶子结点,建哈夫曼树*/ { /*在(*ht)[1]~(*ht)[i-1]的范围内选择两个parent为0且weight最小的结点,其序号分别赋值给s1、s2返回*/ select(ht,i-1,&s1,&s2); (*ht)[s1].parent=i; (*ht)[s2].parent=i; (*ht)[i].LChild=s1; (*ht)[i].RChild=s2; (*ht)[i].weight=(*ht)[s1].weight+(*ht)[s2].weight; } }/*哈夫曼树建立完毕*/ void outputHuffman(HuffmanTree HT, int m) { if(m!=0) {

压缩映射原理在求极限中的应用

压缩映射原理在求极限中的应用 张烁 摘要:压缩映射原理是泛函分析中最基本的存在性定理.本文通过对考研中数列极限的典型例题的解析,归纳总结出适合压缩映射原理求极限数列的一般形式,展示压缩映射原理在解决数学极限中的优越性. 关键词:压缩映射原理极限 压缩映射原理是著名的波兰数学家Stefan Banach在1922年提出的,它是整个分析科学中最常用的存在性理论,应用非常广泛,如隐函数存在性定理、微分方程解的存在唯一性.这里我们主要研究压缩映射原理在数列极限中的应用.许多参考资料都讲过这个方面的应用.在前人的基础上,结合自己的学习体会,归纳总结了压缩映射原理在求数列极限中的应用,进一步展示其优越性. 1 压缩映射 定义1 若X是度量空间, T 是x 到x 中的映射, 如果存在一个数α,0< α<1, 使得对所有的x , y∈x , d( Tx , Ty ) ≤αd( x , y) , 则称T 是X 上的一个压缩映射,α称为压缩常数。 定义2设X 为一非空集, T ∶X →X 是一个映射, 如果有x 3 ∈X 使得T x 3= x 3 , 则称x 3为映射T 的一个不动点。 定理1 (压缩映射定理)设X是完备的度量空间T是X上的压缩映射,那 么T只有且只有一个不动点(就是说,方程Tx=x,有且只有一个解). 证明任取x0∈X , 令x1= Tx 0, x2 = Tx 1, ??, x n+1= Tx n, ?.我们先证明{ x n } 是基本列. ρ( x2, x1 ) = ρ( T x 1, Tx 0 ) ≤αρ( x1, x0 ) = αρ( Tx 0 , x0 ) , ρ( x3, x2 ) = ρ( T x 2, Tx 1 ) ≤αρ( x2 , x1 ) = α2ρ( Tx 0 , x0 ) . 一般, 由归纳法可得ρ( x n+1, x n ) ≤αnρ( Tx 0, x0 ) ( n = 1 , 2 , ?) , 于是, 对于任意的正整数P , 有 ρ( x n+ p , x n )≤ρ(x n+ p , x n+ p- 1 ) +ρ( x n+ p- 1 , x n+ p - 2 ) + ?,ρ( x n+1 , x n ) ≤ (αn+ p- 1 +αn+ p- 2 +?+αn )ρ( Tx 0 , x0 ) = αn ( 1 - αp ) ρ( Tx 0, x0)/(1 - α) ≤ αn /(1 -α)ρ( Tx 0, x0 )。 因为0 ≤α≤1 , 当n →∞,ρ( x n+ p, x n ) →0 , 即{ x n } 是基本列。由于X 是 完备空间, 存在x n∈X , 使得x n→x n。再由T 的连续性, 在( 1) 中, 令n →∞, 就得到x n= Tx n . 再证唯一性。如y n也是T的一个不动点, 即y n=Ty n,则有 ρ( x n,y n) = ρ( Tx n, Ty n) ≤αρ( x n,y n). 由于0≤α< 1 , 做ρ( x n, y n) = 0 , 即x n=y n . 推论设X是完备距离空间, TX→X 。如果存在常数α( 0 ≤α< 1)及正整n0 ,使对任何x , y∈X 都有ρ( T n0 x , T n0y) ≤αρ( x , y) , 则T 存在唯一的不动点(其中T no可 以归纳定义如下: T2 x=T(Tx),T3 ( x) = T ( ( T2x) , ?) . 定理1′对数列{ x n},若存在常数h :0

哈夫曼树 实验报告

计算机科学与技术学院数据结构实验报告 班级2014级计算机1班学号20144138021 姓名张建华成绩 实验项目简单哈夫曼编/译码的设计与实现实验日期2016.1.5 一、实验目的 本实验的目的是进一步理解哈夫曼树的逻辑结构和存储结构,进一步提高使用理论知识指导解决实际问题的能力。 二、实验问题描述 利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码,此实验即设计这样的一个简单编/码系统。系统应该具有如下的几个功能: 1、接收原始数据。 从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmtree.dat中。 2、编码。 利用已建好的哈夫曼树(如不在内存,则从文件hfmtree.dat中读入),对文件中的正文进行编码,然后将结果存入文件codefile.dat中。 3、译码。 利用已建好的哈夫曼树将文件codefile.dat中的代码进行译码,结果存入文件textfile.dat中。 4、打印编码规则。 即字符与编码的一一对应关系。 5、打印哈夫曼树, 将已在内存中的哈夫曼树以直观的方式显示在终端上。 三、实验步骤 1、实验问题分析 1、构造哈夫曼树时使用静态链表作为哈夫曼树的存储。 在构造哈夫曼树时,设计一个结构体数组HuffNode保存哈夫曼树中各结点的信息,根据二叉树的性质可知,具有n个叶子结点的哈夫曼树共有2n-1个结点,所以数组HuffNode的大小设置为2n-1,描述结点的数据类型为: Typedef strcut { Int weight;/*结点权值*/ Int parent; Int lchild; Int rchild; }HNodeType; 2、求哈夫曼编码时使用一维结构数组HuffCode作为哈夫曼编码信息的存储。 求哈夫曼编码,实质上就是在已建立的哈夫曼树中,从叶子结点开始,沿结点的双亲链域回退到根结点,没回退一步,就走过了哈夫曼树的一个分支,从而得到一位哈夫曼码值,由于一个字符的哈夫曼编码是从根结点到相应叶子结点所经过的路径上各分支所组成的0、1序列,因此先得到的分支代码为所求编码的低位码,后得到的分支代码位所求编码的高位码,所以设计如下数据类型:

0023算法笔记——【贪心算法】哈夫曼编码问题

0023算法笔记——【贪心算法】哈夫曼编码问题 1、问题描述 哈夫曼编码是广泛地用于数据文件压缩的十分有效的编码方法。其压缩率通常在20%~90%之间。哈夫曼编码算法用字符在文件中出现的频率表来建立一个用0,1串表示各字符的最优表示方式。一个包含100,000个字符的文件,各字符出现频率不同,如下表所示。 有多种方式表示文件中的信息,若用0,1码表示字符的方法,即每个字符用唯一的一个0,1串表示。若采用定长编码表示,则需要3位表示一个字符,整个文件编码需要300,000位;若采用变长编码表示,给频率高的字符较短的编码;频率低的字符较长的编码,达到整体编码减少的目的,则整个文件编码需要(45×1+13×3+12×3+16×3+9×4+5×4)×1000=224,000位,由此可见,变长码比定长码方案好,总码长减小约25%。 前缀码:对每一个字符规定一个0,1串作为其代码,并要求任一字符的代码都不是其他字符代码的前缀。这种编码称为前缀码。编码的前缀性质可以使译码方法非常简单;例如001011101可以唯一的分解为0,0,101,1101,因而其译码为aabe。

译码过程需要方便的取出编码的前缀,因此需要表示前缀码的合适的数据结构。为此,可以用二叉树作为前缀码的数据结构:树叶表示给定字符;从树根到树叶的路径当作该字符的前缀码;代码中每一位的0或1分别作为指示某节点到左儿子或右儿子的“路标”。 从上图可以看出,表示最优前缀码的二叉树总是一棵完全二叉树,即树中任意节点都有2个儿子。图a表示定长编码方案不是最优的,其编码的二叉树不是一棵完全二叉树。在一般情况下,若C是编码字符集,表示其最优前缀码的二叉树中恰有|C|个叶子。每个叶子对应于字符集中的一个字符,该二叉树有|C|-1个内部节点。 给定编码字符集C及频率分布f,即C中任一字符c以频率f(c)在数据文件中出现。C的一个前缀码编码方案对应于一棵二叉树T。字符c在树T中的深度记为d T(c)。d T(c)也是字符c的前缀码长。则平均码长定义为:

相关文档