数据结构——哈夫曼编码

哈夫曼树的典型例子:

(1)修理牧场:

农夫要修理牧场的一段栅栏,他测量了栅栏,发现需要N块木头,每块木头长度为整数L​i​​个长度单位,于是他购买了一条很长的、能锯成N块的木头,即该木头的长度是L​i​​的总和。

但是农夫自己没有锯子,请人锯木头的酬金跟这段木头的长度成正比。为简单起见,不妨就设酬金等于所锯木头的长度。例如,要将长度为20的木头锯成长度为8、7和5的三段,第一次锯木头花费20,将木头锯成12和8;第二次锯木头花费12,将长度为12的木头锯成7和5,总花费为32。如果第一次将木头锯成15和5,则第二次锯木头花费15,总花费为35(大于32)。

请编写程序帮助农夫计算将木头锯成N块的最少花费。

首先输入一个正整数N(N≤10​4​​),表示要将木头锯成N块。接着给出N个正整数Li(Li≤50),表示每段木块的长度。输出一个整数,即将木头锯成N块的最少花费。

例如:

输入:

8

4 5 1 2 1 3 1 1

输出:

49

*(2)压缩软件:

给定一篇文章,只含有英文大小写字母和空格,以.txt格式存储,统计该文件中各种字符的频率,对各字符进行Huffman编码,将该文件翻译成Huffman编码文件,再将Huffman编码文件翻译成源文件。


代码与实现:

#include<bits/stdc++.h>
#define N 109
using namespace std;

struct huffman
{
    int data;
    int lchild, rchild, pre;
}H[N];


void menu()
{
    printf("1.修理牧场\n");
    printf("2.压缩软件\n");
    printf("3.退出\n");
}


void get_min(int &x, int &y, int n)
{
    x = y = -1;
    for(int i = 0; i < n; i++)
    {
        if(H[i].pre != -1) continue;
        if(x == -1 || H[x].data > H[i].data)
        {
            y = x;
            x = i;
        }
        else if(y == -1 || H[y].data > H[i].data) y = i;
    }
}

int creat_huffman(int n)
{
    int k = 2*n-1, ans = 0;
    for(int i = n; i < k; i++)
    {
        int x, y;
        get_min(x, y, i);
        ans += H[x].data + H[y].data;
        H[x].pre = H[y].pre = i;
        H[i].lchild = x; H[i].rchild = y;
        H[i].data = H[x].data + H[y].data;
        H[i].pre = -1;
    }
    return ans;
}

void solve1()
{
    printf("请输入n和n个数:\n");
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; i++)
    {
        scanf("%d", &H[i].data);
        H[i].lchild = H[i].rchild = H[i].pre = -1;
    }
    printf("%d\n\n", creat_huffman(n));
}

//**************************************************************************88888


void get_code(int k, char s[])
{
    int len = 0;
    while(true)
    {
        int p = H[k].pre;
        if(p == -1) break;
        if(H[p].lchild == k) s[len++] = '0';
        else s[len++] = '1';
        k = p;
    }
    s[len] = '\0';
    for(int i = 0, j = len - 1; i < j; i++, j--) swap(s[i], s[j]);
}


void solve2()
{
    int a[N];
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    char ch;
    memset(a, 0, sizeof(a));
    while(true)
    {
        ch = getchar();
        if(ch == '#') break;
        if(ch == ' ') a[0]++;
        else if(islower(ch)) a[ch-'a'+1]++;
        else if(isupper(ch)) a[ch-'A'+27]++;
    }
    int cnt = 0;
    for(int i = 0; i <= 52; i++)
    {
        if(!a[i]) continue;
        H[cnt].data = a[i]; H[cnt].lchild = H[cnt].rchild = H[cnt].pre = -1; cnt++;
    }
    char s[N];
    creat_huffman(cnt);
    cnt=0;
    for(int i = 0; i <= 52; i++)
    {
        if(!a[i]) continue;
        get_code(cnt, s); cnt++;
        printf("%c: 个数 %d 编码 %s\n", i == 0 ? ' ' : (i <= 26 ? i+'a'-1 : i+'A'-1), a[i], s);
    }
}


int main()
{
    while(true)
    {
        menu();
        int sel;
        scanf("%d", &sel);
        switch(sel)
        {
            case 1: solve1(); break;
            case 2: solve2(); break;
        }
        if(sel == 3) break;
    }
    return 0;
}






















  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值