哈夫曼编码

从键盘接收一串电文字符,输出对应的Huffman编码。同时,能翻译由Huffman编码生成的代码串,输出对应的电文字符串。
(2)设计要求
完成如下菜单的功能
Huffman树的建立
Huffman树的输出
生成Huffman编码
译码并输出

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>

// 定义一个字母及其频度结构体
struct FREQ
{
    unsigned char alpha;
    int freq;
};
typedef struct FREQ FREQ;

// 定义一个哈夫曼表结构体
struct HUFFMAN_TABLE
{
    unsigned char alpha;
    int freq;
    int lChild;
    int rChild;
    unsigned char accessFlag;
    char *hufCode;
};
typedef struct HUFFMAN_TABLE HUFFMAN_TABLE;

#define NOT_FOUND 0
#define FOUND 1

FREQ *getAlphaFreq(char *str, int *alphaKind, int *alpha);
int findMinFreqAlpha(HUFFMAN_TABLE *hufTab, int account);
HUFFMAN_TABLE *initHufTab(FREQ *freq, int alphaCount);
HUFFMAN_TABLE *createHufTab(FREQ *freq, int alphaCount);
void destroyHufTab(HUFFMAN_TABLE *huf, int alphaCount);
void showHufTree(HUFFMAN_TABLE *huf, int alphaCount);
void makeHuffmanCode(HUFFMAN_TABLE *huf, int root, int codeIndex, char *code);
int getHufStringLen(HUFFMAN_TABLE *huf, int alphaCount);
char *codingString(HUFFMAN_TABLE *huf, int alphaCount, int *alphaHufIndex, char *string);
char *decodingString(HUFFMAN_TABLE *huf, int alphaCount, char *string);

char *decodingString(HUFFMAN_TABLE *huf, int alphaCount, char *string)
{
    int i = 0;
    int root = 2 * (alphaCount - 1);
    char *result;
    int t = 0;
    int strLen = getHufStringLen(huf, alphaCount);

    result = (char *)malloc(sizeof(char) * huf[root].freq + 1);

    while (i <= strLen)
    {
        if (-1 != huf[root].lChild)
        {
            root = string[i++] == '1' ? huf[root].lChild : huf[root].rChild;
        }
        else
        {
            result[t++] = huf[root].alpha;
            root = 2 * (alphaCount - 1);
        }
    }
    result[t] = 0;

    return result;
}
char *codingString(HUFFMAN_TABLE *huf, int alphaCount, int *alphaHufIndex, char *string)
{
    char *codestr;
    int i;

    codestr = (char *)calloc(sizeof(char), getHufStringLen(huf, alphaCount) + 1);
    for (i = 0; string[i]; i++)
    {
        strcat(codestr, huf[alphaHufIndex[string[i]]].hufCode);
    }

    return codestr;
}

int getHufStringLen(HUFFMAN_TABLE *huf, int alphaCount)
{
    int sum = 0;
    int i;

    for (i = 0; i < alphaCount; i++)
    {
        sum += huf[i].freq * strlen(huf[i].hufCode);
    }
    return sum;
}

void makeHuffmanCode(HUFFMAN_TABLE *huf, int root, int codeIndex, char *code)
{
    if (-1 == huf[root].lChild)
    {
        code[codeIndex] = 0;
        strcpy(huf[root].hufCode, code);
    }
    else
    {
        code[codeIndex] = '1';
        makeHuffmanCode(huf, huf[root].lChild, codeIndex + 1, code);
        code[codeIndex] = '0';
        makeHuffmanCode(huf, huf[root].rChild, codeIndex + 1, code);
    }
}

void showHufTree(HUFFMAN_TABLE *huf, int alphaCount)
{
    int i;

    printf("下标     字符    频度     左孩子 右孩子  Flag    哈夫曼编码\n");
    for (i = 0; i < 2 * alphaCount - 1; i++)
    {
        printf("%4d\t%4c\t%4d\t%6d\t%6d\t%4d\t%s\n",
               i,
               huf[i].alpha,
               huf[i].freq,
               huf[i].lChild,
               huf[i].rChild,
               huf[i].accessFlag,
               huf[i].hufCode);
    }
}

void destroyHufTab(HUFFMAN_TABLE *huf, int alphaCount)
{
    int i;

    for (i = 0; i < alphaCount; i++)
    {
        free(huf[i].hufCode);
    }
    free(huf);
}

HUFFMAN_TABLE *createHufTab(FREQ *freq, int alphaCount)
{
    HUFFMAN_TABLE *huf;
    int i;
    int lChild, rChild;

    huf = initHufTab(freq, alphaCount);
    for (i = 0; i < alphaCount; i++)
    {
        lChild = findMinFreqAlpha(huf, alphaCount + i);
        rChild = findMinFreqAlpha(huf, alphaCount + i);

        huf[alphaCount + i].alpha = (unsigned char)NULL;
        huf[alphaCount + i].freq = huf[lChild].freq + huf[rChild].freq;
        huf[alphaCount + i].lChild = lChild;
        huf[alphaCount + i].rChild = rChild;
        huf[alphaCount + i].accessFlag = NOT_FOUND;
        huf[alphaCount + i].hufCode = NULL;
    }

    return huf;
}

HUFFMAN_TABLE *initHufTab(FREQ *freq, int alphaCount)
{
    HUFFMAN_TABLE *huf;
    int i;

    huf = (HUFFMAN_TABLE *)malloc(sizeof(HUFFMAN_TABLE) * (2 * alphaCount - 1));
    for (i = 0; i < alphaCount; i++)
    {
        huf[i].alpha = freq[i].alpha;
        huf[i].freq = freq[i].freq;
        huf[i].lChild = huf[i].rChild = -1;
        huf[i].accessFlag = NOT_FOUND;
        huf[i].hufCode = (char *)calloc(sizeof(char), alphaCount);
    }
    return huf;
}

int findMinFreqAlpha(HUFFMAN_TABLE *hufTab, int account)
{
    int minIndex = -1;
    int i;

    for (i = 0; i < account; i++)
    {
        if (hufTab[i].accessFlag == NOT_FOUND &&
            (minIndex == -1 || hufTab[i].freq < hufTab[minIndex].freq))
            minIndex = i;
    }
    hufTab[minIndex].accessFlag = FOUND;

    return minIndex;
}

FREQ *getAlphaFreq(char *str, int *count, int *alpha)
{
    FREQ *p = NULL; // 获得的字符串频度信息保存在该结构体
    int cnt = 0;    // 字符串种类
    int i, j;

    if (NULL == str)
    {
        printf("error: str is null\n");
        return NULL;
    }
    for (i = 0; str[i]; i++)
    {
        alpha[str[i]]++; // 不同位置的相同字符是数组的同一个元素 ++
    }
    for (i = 0; i < 256; i++)
    {
        if (alpha[i])
        {
            cnt++;
        }
    }
    p = (FREQ *)malloc(sizeof(FREQ) * cnt);
    for (i = j = 0; i < 256 && j < cnt; i++)
    {
        if (alpha[i])
        {
            p[j].alpha = i; // i是对应字符的ASCII码,此处会以char类型解释
            p[j].freq = alpha[i];
            alpha[i] = j++;
        }
    }
    *count = cnt;

    return p;
}

int main()
{
    char str[1024];
    FREQ *freqPoint = NULL;
    int alphaCount;
    int i;
    HUFFMAN_TABLE *huf = NULL;
    char *code = NULL;
    int alphaHufIndex[256] = {0};
    char *coString = NULL;
    char *deString = NULL;
    int choice;

    while (1)
    {
        printf("菜单:\n");
        printf("1. Huffman树的建立\n");
        printf("2. Huffman树的输出\n");
        printf("3. 生成Huffman编码\n");
        printf("4. 译码并输出\n");
        printf("5. 退出系统\n");
        printf("请选择操作(1-5): ");
        scanf("%d", &choice);

        switch (choice)
        {
        case 1:
            printf("请输入一个字符串:\n");
            scanf("%s", str);
            freqPoint = getAlphaFreq(str, &alphaCount, alphaHufIndex);
            huf = createHufTab(freqPoint, alphaCount);
            code = (char *)malloc(sizeof(char *) * alphaCount);
            makeHuffmanCode(huf, 2 * (alphaCount - 1), 0, code);
            printf("Huffman树已建立\n");
            break;
        case 2:
            if (huf != NULL)
            {
                showHufTree(huf, alphaCount);
            }
            else
            {
                printf("Huffman树尚未建立,请先选择操作1建立树\n");
            }
            break;
        case 3:
            if (huf != NULL)
            {
                printf("Huffman编码生成成功\n");
                coString = codingString(huf, alphaCount, alphaHufIndex, str);
                printf("生成的Huffman编码为:\n%s\n", coString);
            }
            else
            {
                printf("Huffman树尚未建立,请先选择操作1建立树\n");
            }
            break;
        case 4:
            if (huf != NULL && coString != NULL)
            {
                printf("Huffman译码并输出成功\n");
                deString = decodingString(huf, alphaCount, coString);
                printf("译码后的字符串为:\n%s\n", deString);
            }
            else
            {
                printf("Huffman树或编码尚未生成,请先选择操作1和3生成树和编码\n");
            }
            break;
        case 5:
            if (freqPoint != NULL)
            {
                free(freqPoint);
            }
            if (huf != NULL)
            {
                destroyHufTab(huf, alphaCount);
            }
            if (code != NULL)
            {
                free(code);
            }
            if (coString != NULL)
            {
                free(coString);
            }
            if (deString != NULL)
            {
                free(deString);
            }
            printf("退出系统\n");
            return 0;
        default:
            printf("无效的选择,请重新输入\n");
            break;
        }
    }

    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_45230280

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值