数据结构13-哈夫曼树

数据结构13-哈夫曼树

代码

#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100

// 定义一个结点结构体
typedef struct NODE {
    char c;            // 字符
    int weight;        // 权重
    int binary;        // 二进制编码
    int flag;          // 标志位
    struct NODE *lchild, *rchild, *parent;  // 左孩子、右孩子、父结点指针
} NODE, *PNODE;

// 定义一个栈结构体
typedef struct {
    int valuse[MAXSIZE]; // 栈的值
    int top;             // 栈顶指针
} STACK;

// 初始化栈
void initStack(STACK &stack) {
    stack.top = 0;
}

// 入栈操作
void push(STACK &stack, int value) {
    stack.valuse[stack.top++] = value;
}

// 出栈操作
int pop(STACK &stack) {
    if (stack.top == 0)
        return -1;
    stack.top--;
    return stack.valuse[stack.top];
}

// 初始化结点
void initNode(PNODE node) {
    node->lchild = NULL;
    node->parent = NULL;
    node->rchild = NULL;
    node->flag = 0;
    node->weight = 0;
    node->c = -1;
    node->binary = 0;
}

// 创建结点
PNODE createNode(int weight) {
    PNODE node = (PNODE)malloc(sizeof(NODE));
    if (node) {
        initNode(node);
        node->weight = weight;
    }
    return node;
}

// 字符编码
STACK charEncode(char c, PNODE childrenNodes, int lenOfNodes) {
    STACK stack;
    initStack(stack);
    for (int i = 0; i < lenOfNodes; i++) {
        if (c == childrenNodes[i].c) {
            PNODE tmp = &childrenNodes[i];
            while (tmp->parent != NULL) {
                push(stack, tmp->binary);
                tmp = tmp->parent;
            }
            break;
        }
    }
    return stack;
}

// 字符串编码
char *strEncode(char *str, PNODE childrenNodes, int lenOfNodes) {
    char *result = (char *)malloc(sizeof(char) * MAXSIZE * lenOfNodes);
    int len = 0;
    while (*str != '\0') {
        STACK stack = charEncode(*str, childrenNodes, lenOfNodes);
        while (stack.top > 0) {
            result[len++] = pop(stack) + '0';
        }
        str++;
    }
    result[len] = '\0';
    return result;
}

// 获取最小权重的结点
PNODE getMinWeightNode(PNODE nodes, int lenOfNodes) {
    PNODE node;
    int min = 0, i;
    while (min < lenOfNodes) {
        if (nodes[min].flag == 0) {
            break;
        }
        min++;
    }
    if (min == lenOfNodes) {
        return NULL;
    }
    for (i = min + 1; i < lenOfNodes; i++) {
        if (nodes[i].flag == 0 && nodes[i].weight < nodes[min].weight) {
            min = i;
            continue;
        }
    }
    nodes[min].flag = 1;
    return &nodes[min];
}

// 创建霍夫曼树
PNODE createHuffmanTree(PNODE nodes, int lenOfNodes, PNODE childNode) {
    PNODE minWeightNode, parentNode;
    minWeightNode = getMinWeightNode(nodes, lenOfNodes);
    if (!minWeightNode)
        return childNode;
    if (!childNode) {
        parentNode = minWeightNode;
    } else {
        parentNode = createNode(childNode->weight + minWeightNode->weight);
        if (childNode->weight < minWeightNode->weight) {
            parentNode->lchild = childNode;
            parentNode->rchild = minWeightNode;
        } else {
            parentNode->rchild = childNode;
            parentNode->lchild = minWeightNode;
        }
        parentNode->lchild->binary = 0;
        parentNode->rchild->binary = 1;
        childNode->parent = minWeightNode->parent = parentNode;
    }
    createHuffmanTree(nodes, lenOfNodes, parentNode);
}

// 将字符转换为小写
char charTolowercase(char c) {
    if (c >= 'A' && c <= 'Z') {
        c += 'a' - 'A';
    }
    return c;
}

// 从文件中读取字符并统计权重,构建霍夫曼树
PNODE readFromSource(const char *filePath, char *buff, PNODE childrenNodes, int &lenOfNodes) {
    int lenOfStr = 0, i;
    char c;
    FILE *file = fopen(filePath, "rb");
    if (file == NULL) {
        puts("Can't find source file!");
        exit(0);
    }
    c = fgetc(file);
    while (!feof(file)) {
        c = charTolowercase(c);
        initNode(&childrenNodes[lenOfNodes]);
        buff[lenOfStr++] = c;
        for (i = 0; i < lenOfNodes; i++) {
            if (childrenNodes[i].c == c) {
                childrenNodes[i].weight++;
                break;
            }
        }
        if (i == lenOfNodes) {
            childrenNodes[lenOfNodes].c = c;
            childrenNodes[lenOfNodes++].weight++;
        }
        c = fgetc(file);
    }
    buff[lenOfStr] = '\0';
    fclose(file);
    return createHuffmanTree(childrenNodes, lenOfNodes, NULL);
}

// 将编码结果写入文件
void writeResult(const char *filePath, char *result) {
    FILE *fp = fopen(filePath, "wb");
    if (fputs(result, fp) >= 0) {
        printf("生成结果成功\r\n");
    }
    fclose(fp);
}

// 字符串解码
char *strDecode(const char *str, PNODE TreeRoot) {
    const char *tmp = str;
    char *result = (char *)malloc(sizeof(char) * MAXSIZE);
    int len = 0;
    while (*tmp != '\0') {
        PNODE tmpNode = TreeRoot;
        while (tmpNode->lchild && tmpNode->rchild) {
            tmpNode = *tmp == '0' ? tmpNode->lchild : tmpNode->rchild;
            tmp++;
        }
        result[len++] = tmpNode->c;
    }
    result[len] = '\0';
    return result;
}

int main() {
    char buff[MAXSIZE];
    NODE childrenNodes[MAXSIZE];
    int len = 0;
    PNODE root = readFromSource("source.txt", buff, childrenNodes, len);
    writeResult("result.txt", strEncode(buff, childrenNodes, len));
    printf("%s", strDecode("11111111111110111111111110011101111111111011001110011111111101111111101111111011111101111101100111101010", root));
    return 0;
}

代码总结

这段代码实现了一个霍夫曼编码的示例。霍夫曼编码是一种无损数据压缩算法。代码的主要功能包括:

  1. 结点定义和初始化

    • 定义了结点结构体 NODE,包含字符、权重、二进制编码、标志位以及左右孩子和父结点指针。
    • 定义并实现了栈结构体 STACK 及其初始化、入栈和出栈操作。
  2. 结点操作

    • initNode 函数用于初始化结点。
    • createNode 函数用于创建一个新的结点,并初始化其权重。
  3. 霍夫曼树构建

    • getMinWeightNode 函数用于从结点数组中获取权重最小的结点。
    • createHuffmanTree 函数用于递归地创建霍夫曼树。
  4. 字符编码和解码

    • charEncode 函数用于将单个字符编码为霍夫曼编码。
    • strEncode 函数用于将字符串编码为霍夫曼编码。
    • strDecode 函数用于将霍夫曼编码解码为原始字符串。
  5. 文件操作

    • readFromSource 函数从文件中读取字符并统计其权重,构建霍夫曼树。
    • writeResult 函数将编码后的字符串写入文件。
  6. 主函数

    • main 函数从文件 source.txt 读取数据,生成霍夫曼树,并将编码结果写入 result.txt 文件,最后将一个示例编码字符串解码并打印。

这段代码详细展示了如何利用霍夫曼编码进行数据压缩与解压缩的全过程。

运行结果

无源文件

  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值