c语言Huffman树构建的时间复杂度
时间: 2023-08-10 17:11:19 浏览: 64
Huffman树的构建算法是基于贪心策略的,时间复杂度为O(nlogn),其中n为待编码的字符个数。在构建Huffman树时,需要进行多次的合并操作,每次选取最小的两个节点进行合并,因此需要进行n-1次合并操作。每次合并操作都需要在已排序的节点集合中寻找最小的两个节点,这可以通过使用最小堆来实现,每次插入和删除操作的时间复杂度为logn。因此,构建Huffman树的总时间复杂度为O(nlogn)。
相关问题
c语言实现构建huffman树算法
下面是用C语言实现构建Huffman树算法的示例代码:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 1000
// 定义Huffman树节点结构体
typedef struct {
int weight; // 权值
int parent; // 父节点下标
int left; // 左子节点下标
int right; // 右子节点下标
} HuffNode, *HuffTree;
// 定义Huffman编码结构体
typedef struct {
char ch; // 字符
char code[MAX_SIZE]; // 编码
} HuffCode, *HuffCodeTable;
// 选择权值最小的两个节点
void select(HuffTree tree, int n, int *s1, int *s2) {
int i;
int min1, min2;
min1 = min2 = MAX_SIZE;
// 找出第一个权值最小的节点
for (i = 0; i < n; i++) {
if (tree[i].weight < min1 && tree[i].parent == -1) {
min1 = tree[i].weight;
*s1 = i;
}
}
// 找出第二个权值最小的节点
for (i = 0; i < n; i++) {
if (tree[i].weight < min2 && tree[i].parent == -1 && i != *s1) {
min2 = tree[i].weight;
*s2 = i;
}
}
}
// 构建Huffman树
void buildHuffTree(HuffTree tree, int n) {
if (n <= 1) return;
int i, s1, s2;
for (i = 0; i < 2 * n - 1; i++) {
tree[i].parent = -1;
tree[i].left = -1;
tree[i].right = -1;
}
// 构建n-1个节点的Huffman树
for (i = n; i < 2 * n - 1; i++) {
select(tree, i, &s1, &s2);
tree[s1].parent = i;
tree[s2].parent = i;
tree[i].left = s1;
tree[i].right = s2;
tree[i].weight = tree[s1].weight + tree[s2].weight;
}
}
// 获取Huffman编码
void getHuffCode(HuffTree tree, HuffCodeTable table, int n) {
int i, j;
char *code = (char *)malloc(n * sizeof(char));
code[n - 1] = '\0';
for (i = 0; i < n; i++) {
int start = n - 1;
int c = i;
int p = tree[c].parent;
while (p != -1) {
if (tree[p].left == c) {
code[--start] = '0';
} else {
code[--start] = '1';
}
c = p;
p = tree[c].parent;
}
strcpy(table[i].code, &code[start]);
}
free(code);
}
int main() {
int n;
printf("输入字符个数:");
scanf("%d", &n);
// 输入字符及其权值
HuffTree tree = (HuffTree)malloc(sizeof(HuffNode) * (2 * n - 1));
HuffCodeTable table = (HuffCodeTable)malloc(sizeof(HuffCode) * n);
int i;
for (i = 0; i < n; i++) {
printf("输入第%d个字符及其权值:", i + 1);
scanf("%s %d", &table[i].ch, &tree[i].weight);
}
// 构建Huffman树
buildHuffTree(tree, n);
// 获取Huffman编码
getHuffCode(tree, table, n);
// 输出Huffman编码
printf("Huffman编码如下:\n");
for (i = 0; i < n; i++) {
printf("%c: %s\n", table[i].ch, table[i].code);
}
free(tree);
free(table);
return 0;
}
```
这段代码实现了从用户输入字符及其权值,构建Huffman树,获取Huffman编码,输出Huffman编码的功能。在构建Huffman树时,采用的是贪心策略,每次选择权值最小的两个节点进行合并。在获取Huffman编码时,采用的是自底向上的遍历方式,从叶子节点到根节点依次获取每个字符的编码。
c语言 huffman编码解码
Huffman编码是一种无损压缩算法,常用于数据传输和存储中。下面是C语言实现Huffman编码和解码的基本思路:
Huffman编码:
1. 统计字符出现频率,构建字符频率表;
2. 将字符频率表中的字符和频率信息构建成一棵Huffman树;
3. 遍历Huffman树,给每个字符生成对应的Huffman编码;
4. 将编码写入文件。
Huffman解码:
1. 读取压缩文件中的编码信息和字符频率表;
2. 根据字符频率表构建Huffman树;
3. 遍历Huffman树,根据编码信息还原原始字符串。
以下是C语言实现Huffman编码和解码的参考代码:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_TREE_HT 100
// Huffman树节点结构体
struct MinHeapNode {
char data;
unsigned freq;
struct MinHeapNode *left, *right;
};
// Huffman编码表结构体
struct HuffmanCode {
char data;
char *code;
};
// 最小优先队列结构体
struct MinHeap {
unsigned size;
unsigned capacity;
struct MinHeapNode **array;
};
// 创建一个新的Huffman树节点
struct MinHeapNode* newNode(char data, unsigned freq)
{
struct MinHeapNode* node = (struct MinHeapNode*)malloc(sizeof(struct MinHeapNode));
node->left = node->right = NULL;
node->data = data;
node->freq = freq;
return node;
}
// 创建一个最小优先队列
struct MinHeap* createMinHeap(unsigned capacity)
{
struct MinHeap* minHeap = (struct MinHeap*)malloc(sizeof(struct MinHeap));
minHeap->size = 0;
minHeap->capacity = capacity;
minHeap->array = (struct MinHeapNode**)malloc(minHeap->capacity * sizeof(struct MinHeapNode*));
return minHeap;
}
// 交换两个节点
void swapMinHeapNode(struct MinHeapNode** a, struct MinHeapNode** b)
{
struct MinHeapNode* t = *a;
*a = *b;
*b = t;
}
// 最小堆化
void minHeapify(struct MinHeap* minHeap, int idx)
{
int smallest = idx;
int left = 2 * idx + 1;
int right = 2 * idx + 2;
if (left < minHeap->size && minHeap->array[left]->freq < minHeap->array[smallest]->freq)
smallest = left;
if (right < minHeap->size && minHeap->array[right]->freq < minHeap->array[smallest]->freq)
smallest = right;
if (smallest != idx) {
swapMinHeapNode(&minHeap->array[smallest], &minHeap->array[idx]);
minHeapify(minHeap, smallest);
}
}
// 检查堆大小是否为1
int isSizeOne(struct MinHeap* minHeap)
{
return (minHeap->size == 1);
}
// 取出堆顶元素
struct MinHeapNode* extractMin(struct MinHeap* minHeap)
{
struct MinHeapNode* temp = minHeap->array[0];
minHeap->array[0] = minHeap->array[minHeap->size - 1];
--minHeap->size;
minHeapify(minHeap, 0);
return temp;
}
// 插入新的节点
void insertMinHeap(struct MinHeap* minHeap, struct MinHeapNode* minHeapNode)
{
++minHeap->size;
int i = minHeap->size - 1;
while (i && minHeapNode->freq < minHeap->array[(i - 1) / 2]->freq) {
minHeap->array[i] = minHeap->array[(i - 1) / 2];
i = (i - 1) / 2;
}
minHeap->array[i] = minHeapNode;
}
// 构建最小优先队列
void buildMinHeap(struct MinHeap* minHeap)
{
int n = minHeap->size - 1;
int i;
for (i = (n - 1) / 2; i >= 0; --i)
minHeapify(minHeap, i);
}
// 判断是否是叶子节点
int isLeaf(struct MinHeapNode* root)
{
return !(root->left) && !(root->right);
}
// 创建一个最小优先队列并构建Huffman树
struct MinHeap* createAndBuildMinHeap(char data[], int freq[], int size)
{
int i;
struct MinHeap* minHeap = createMinHeap(size);
for (i = 0; i < size; ++i)
minHeap->array[i] = newNode(data[i], freq[i]);
minHeap->size = size;
buildMinHeap(minHeap);
return minHeap;
}
// 构建Huffman树
struct MinHeapNode* buildHuffmanTree(char data[], int freq[], int size)
{
struct MinHeapNode *left, *right, *top;
struct MinHeap* minHeap = createAndBuildMinHeap(data, freq, size);
while (!isSizeOne(minHeap)) {
left = extractMin(minHeap);
right = extractMin(minHeap);
top = newNode('$', left->freq + right->freq);
top->left = left;
top->right = right;
insertMinHeap(minHeap, top);
}
return extractMin(minHeap);
}
// 生成Huffman编码
void generateCodes(struct MinHeapNode* root, char *code, int top, struct HuffmanCode *huffmanCode)
{
if (root->left) {
code[top] = '0';
generateCodes(root->left, code, top + 1, huffmanCode);
}
if (root->right) {
code[top] = '1';
generateCodes(root->right, code, top + 1, huffmanCode);
}
if (isLeaf(root)) {
huffmanCode[root->data].data = root->data;
huffmanCode[root->data].code = (char*)malloc((top + 1) * sizeof(char));
memcpy(huffmanCode[root->data].code, code, (top + 1) * sizeof(char));
}
}
// 打印Huffman编码表
void printHuffmanCodes(struct HuffmanCode *huffmanCode, int size)
{
int i;
printf("Huffman编码表:\n");
for (i = 0; i < size; ++i)
printf("%c: %s\n", huffmanCode[i].data, huffmanCode[i].code);
}
// 压缩文件
void compressFile(char *fileName, struct HuffmanCode *huffmanCode, int size)
{
FILE *fpIn, *fpOut;
char ch, *code;
int i, j, len;
fpIn = fopen(fileName, "r");
if (fpIn == NULL) {
printf("打开文件失败!\n");
return;
}
fpOut = fopen("compressed.dat", "wb");
fwrite(&size, sizeof(int), 1, fpOut);
for (i = 0; i < size; ++i) {
fwrite(&huffmanCode[i].data, sizeof(char), 1, fpOut);
len = strlen(huffmanCode[i].code);
fwrite(&len, sizeof(int), 1, fpOut);
fwrite(huffmanCode[i].code, sizeof(char), len, fpOut);
}
code = (char*)malloc(MAX_TREE_HT * sizeof(char));
while ((ch = fgetc(fpIn)) != EOF) {
for (i = 0; i < size; ++i) {
if (huffmanCode[i].data == ch) {
len = strlen(huffmanCode[i].code);
for (j = 0; j < len; ++j)
code[j] = huffmanCode[i].code[j];
fwrite(code, sizeof(char), len, fpOut);
break;
}
}
}
fclose(fpIn);
fclose(fpOut);
printf("压缩成功!\n");
}
// 解压文件
void decompressFile(char *fileName)
{
FILE *fpIn, *fpOut;
struct HuffmanCode huffmanCode[256];
char ch, *code;
int i, j, len, size;
fpIn = fopen(fileName, "rb");
if (fpIn == NULL) {
printf("打开文件失败!\n");
return;
}
fpOut = fopen("decompressed.txt", "w");
fread(&size, sizeof(int), 1, fpIn);
for (i = 0; i < size; ++i) {
fread(&huffmanCode[i].data, sizeof(char), 1, fpIn);
fread(&len, sizeof(int), 1, fpIn);
huffmanCode[i].code = (char*)malloc((len + 1) * sizeof(char));
fread(huffmanCode[i].code, sizeof(char), len, fpIn);
huffmanCode[i].code[len] = '\0';
}
code = (char*)malloc(MAX_TREE_HT * sizeof(char));
struct MinHeapNode *root = buildHuffmanTree(NULL, NULL, 0);
struct MinHeapNode *curr = root;
while ((ch = fgetc(fpIn)) != EOF) {
for (i = 0; i < 8; ++i) {
if (ch & (1 << (7 - i))) // ASCII码从高位开始读
curr = curr->right;
else
curr = curr->left;
if (isLeaf(curr)) {
fputc(curr->data, fpOut);
curr = root;
}
}
}
fclose(fpIn);
fclose(fpOut);
printf("解压成功!\n");
}
int main()
{
char data[] = {'a', 'b', 'c', 'd', 'e', 'f'};
int freq[] = {5, 9, 12, 13, 16, 45};
int size = sizeof(data) / sizeof(data[0]);
struct HuffmanCode huffmanCode[256];
struct MinHeapNode* root = buildHuffmanTree(data, freq, size);
char code[MAX_TREE_HT];
int top = 0;
generateCodes(root, code, top, huffmanCode);
printHuffmanCodes(huffmanCode, size);
compressFile("input.txt", huffmanCode, size);
decompressFile("compressed.dat");
return 0;
}
```
上述代码中,我们使用了最小优先队列来构建Huffman树。在生成Huffman编码时,我们使用了递归的方法遍历树,并记录下每个叶子节点的编码。在压缩文件时,我们将字符的Huffman编码写入输出文件中。在解压文件时,我们读取压缩文件中的编码信息和字符频率表,根据它们构建Huffman树,并根据编码信息还原原始字符串。