zoukankan      html  css  js  c++  java
  • 【C】哈夫曼编码

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <malloc.h>
    
    #define HFMLENTH 999
    #define MAXCODE 10
    
    // 待输入字符串
    char str[HFMLENTH];
    
    // 编码
    int code[HFMLENTH];
    
    // 哈夫曼树的叶子数 其他节点数 根节点 最大深度
    int oriLenth = 0, addLenth = 0, root, maxLayer;
    
    void GetStr()
    {
        getchar();
        for (int i = 0; i < strlen(str); i++)
            str[i] = '';
        printf("输入字符串长度
    ");
        int lenth;
        scanf("%d", &lenth);
        printf("输入字符串
    ");
        getchar();
        for (int i = 0; i < lenth; i++)
            scanf("%c", &str[i]);
    }
    
    typedef struct
    {
        char everyBit[MAXCODE];
        int lenth;
    } Code;
    
    // 节点
    typedef struct
    {
        int leftChild, rightChild, parent;
        char cr;
        int count;
        Code code;
    } Node;
    
    // 哈夫曼树
    Node * HFMTree;
    
    // 字符串转哈夫曼编码
    void StrToHFM()
    {
        HFMTree = (Node *)malloc(2 * HFMLENTH * sizeof(Node));
        // 构造节点
        for (int i = 0; i < 2 * HFMLENTH; i++)
        {
            HFMTree[i].cr = '';
            HFMTree[i].count = 0;
            HFMTree[i].parent = -1;
            HFMTree[i].leftChild = -1;
            HFMTree[i].rightChild = -1;
        }
        for (int i = 0; str[i] != ''; i++)
            for (int j = 0; j < strlen(str); j++)
                if (HFMTree[j].cr == '')
                {
                    HFMTree[j].cr = str[i];
                    HFMTree[j].count = 1;
                    if (oriLenth < j)
                        oriLenth = j;
                    break;
                }
                else if (HFMTree[j].cr == str[i])
                {
                    HFMTree[j].count++;
                    break;
                }
    
        // 构造树
        int finish = 0;
        while (!finish)
        {
            int index1 = 0, index2 = 0;
            for (int i = 0; i <= oriLenth + addLenth; i++)
            {
                if (HFMTree[i].parent == -1 && (HFMTree[index1].parent != -1 || HFMTree[index1].count > HFMTree[i].count))
                    index1 = i;
            }
            for (int i = 0; i <= oriLenth + addLenth; i++)
            {
                if (i == index1)
                    continue;
                if (index1 == index2 || HFMTree[i].parent == -1 && (HFMTree[index2].parent != -1 || HFMTree[index2].count > HFMTree[i].count))
                    index2 = i;
            }
            if (index1 != index2)
            {
                if (HFMTree[index2].parent == -1)
                {
                    root = oriLenth + (++addLenth);
                    HFMTree[root].count = HFMTree[index1].count + HFMTree[index2].count;
                    HFMTree[root].leftChild = index1;
                    HFMTree[root].rightChild = index2;
                    HFMTree[root].cr = '';
                    HFMTree[root].parent = -1;
                    HFMTree[index1].parent = root;
                    HFMTree[index2].parent = root;
                }
                else
                {
                    root = index1;
                    finish = 1;
                }
            }
            else
            {
                root = index1;
                finish = 1;
            }
        }
    }
    
    // 设置哈夫曼编码并打印哈夫曼树
    // isPrinting为0时仅仅设置哈夫曼编码 不打印
    void PrintHFM(int index, int layer, int isPrinting)
    {
        if (index == -1)
            return;
    
        if (layer > maxLayer)
            maxLayer = layer;
    
        for (int i = 0; i < layer; i++)
            HFMTree[index].code.everyBit[i] = code[i];
        HFMTree[index].code.lenth = layer;
    
        if (index == root && HFMTree[index].cr != '')
        {
            if (isPrinting == 1)
                printf("%c的编码为:0.
    ", HFMTree[index].cr);
            return;
        }
    
        if (HFMTree[index].cr != '')
        {
            if (isPrinting == 1)
            {
                printf("%c的编码为:", HFMTree[index].cr);
                for (int i = 0; i < HFMTree[index].code.lenth; i++)
                    printf("%d", HFMTree[index].code.everyBit[i]);
                printf("
    ");
            }
        }
    
        code[layer] = 0;
        PrintHFM(HFMTree[index].leftChild, layer + 1, isPrinting);
        code[layer] = 1;
        PrintHFM(HFMTree[index].rightChild, layer + 1, isPrinting);
    
    }
    
    // 读入文件
    void ReadFile()
    {
        FILE *fp;
        if ((fp = fopen("test.txt", "rb")) == NULL)
        {
            printf("未找到文件
    ");
            return;
        }
        fseek(fp, 0, SEEK_END);
        int fileLen = ftell(fp);
        fseek(fp, 0, SEEK_SET);
        fread(str, fileLen, sizeof(char), fp);
        fclose(fp);
    }
    
    void WriteHFMFile()
    {
        FILE *fp;
        if ((fp = fopen("hfm.txt", "w")) == NULL)
        {
            printf("无法创建文件
    ");
            return;
        }
        for (int i = 0; i < strlen(str); i++)
            for (int j = 0; j <= oriLenth; j++)
                if (str[i] == HFMTree[j].cr)
                {
                    for (int k = 0; k < HFMTree[j].code.lenth; k++)
                        fprintf(fp,"%d",HFMTree[j].code.everyBit[k]);
                    for (int k = HFMTree[j].code.lenth; k < maxLayer; k++)
                        fprintf(fp, "%d", 0); // 填充
                    break;
                }
        fclose(fp);
    }
    
    int main()
    {
        printf("选择功能:
    1.输入字符串,输出字符串的哈夫曼编码;
    2.输入文本文件(英文),输出哈夫曼编码文件
    ");
        char choice;
        scanf("%c", &choice);
        switch(choice)
        {
        case '1':
            GetStr();
            StrToHFM();
            PrintHFM(root, 0, 1);
            break;
        case '2':
            ReadFile();
            StrToHFM();
            PrintHFM(root, 0, 0);
            WriteHFMFile();
            break;
        }
        return 0;
    }
    View Code

    这让我想到高中的时候记笔记,有些字笔画多,就用简单的符号代替了。

    实际上哈夫曼文件应该是按位输出的,打开之后可能是一堆乱码。为了方便观察,我就按照字符输出了。

    结构体节点Node来组成哈夫曼树,结构体编码Code来表示哈夫曼编码。

    用字符数组str读入输入;哈夫曼树的叶子数、其他节点数、根节点、最大深度分别为oriLenth, addLenth, root, maxLayer。

    提供用户输入选择功能1.输入字符串,输出字符串的哈夫曼编码;2.输入文本文件(英文),输出哈夫曼编码文件。为此还重温了文件操作代码。

    首先使用GetStr()或者ReadFile()获得字符串。

    然后用StrToHFM()生成哈夫曼树。

    接着用PrintHFM(root, 0, x)来生成编码。当x为1时顺带打印编码。

    WriteHFMFile()用来输入哈夫曼压缩文件。

  • 相关阅读:
    jquery选择器
    js实现添加className
    日期函数(date)
    IE6和IE7中<a>标签宽高设置无效的问题
    Uva 548 二叉树的递归遍历lrj 白书p155
    Uva 122 树的层次遍历 Trees on the level lrj白书 p149
    Uva 679 Dropping Ballls 二叉树的编号
    Uva 12657 Boxes in a Line 双向链表
    Uva 11988 Broken Keyboard STL+链表
    埃及分数问题+迭代加深搜索
  • 原文地址:https://www.cnblogs.com/kamishiroshinchi/p/12984203.html
Copyright © 2011-2022 走看看