D(哈夫曼树)

本文介绍了一种利用哈夫曼树计算字符编码的方法。通过分析输入字符串中字符的频率,构建哈夫曼树并计算编码长度。文章详细解释了算法步骤及实现细节。

#include <iostream>
#include<stdio.h>
#include <cstring>
using namespace std;
struct{
       int self;
       int parent;
       int left;
       int right;
       }tree[100];
int main()
{
    string s;
    int arr[35];
    int i,j,k,a,b,c,d,e,f,g;
    double A;
    while(cin>>s&&s!="END")
    {
        memset(arr,0,sizeof(arr));
        a=s.size();
        for(i=0;i<a;i++)
        {
            arr[s[i]-64]++;
        }
        for(i=1,j=1;i<35;i++)
        {
            if(arr[i]!=0)
            {
                tree[j].self=arr[i];
                tree[j].parent=tree[j].left=tree[j].right=0;
                j++;
            }
        }
        j--;
        for(i=j+1;i<j*2;i++)
            tree[i].parent=tree[i].left=tree[i].right=0;
        for(i=j+1;i<j*2;i++)
        {
            b=c=10000;
            for(k=1;k<i;k++)
            {
                if(tree[k].self<b&&tree[k].parent==0)
                {
                    c=b;
                    e=d;
                    b=tree[k].self;
                    d=k;
                }
                else if(tree[k].self<c&&tree[k].parent==0)
                {
                    c=tree[k].self;
                    e=k;
                }
            }
            tree[i].self=b+c;
            tree[i].right=d;
            tree[i].left=e;
            tree[d].parent=i;
            tree[e].parent=i;
        }
        f=0;
        for(i=1;i<j+1;i++)
        {
            k=i;
            g=0;
            while(tree[k].parent!=0)
            {
                k=tree[k].parent;
                g++;
            }
            f+=g*tree[i].self;
        }
        if(j==1)
            f=a;
        A=(double)(a*8)/f;
        a=a*8;
        printf("%d %d %.1f\n",a,f,A);
    }
    return 0;
}

题目代号 :D(1003)

简单题意:题目任意给出一串字符,以END为结束。字符内容包括有26个大写字母和一个‘_'。要求是算出8乘以字符数,再除以把字符串的字符按哈夫曼树组成的编码总数,结                     果保留一位小数。案例可以看出输入输出的规则。

解题思路:首先,求出字符数,那是必须要做的,无论是被除数需要还是为以后的循环做准备都有必要。其实深入思考就可以知道,解决此问题有2个大难题,第一,把重复的                       字符表示提取出来而且还要知道每个字符的重复次数。第二,贪心算法来求哈夫曼树,并表示出来,计算出编码总数。第一个问题不是很难,在大一C++考试好像                         就是专门考到过这样的题目,用一个数组套一个字符串然后减掉A再加加最后循环即可。第二个问题,那这个就是个大的问题了。首先根据哈夫曼树的特性,创建个                       结构体 吧,里面有4个属性,它本身的权,它的左右儿子,它的父母。而后创建个结构体的数组。一开始,我们需要初始化,也就是将整数数组给结构体的属性赋权                     值,其他属性清0。其次,扩展一下结构体的数组,因为我们一开始只给有权值的赋值了,但是根据哈夫曼树,有多少个叶子,圆圈总数是叶子树的二倍减一,所以                       要把扩展的 除权值以外的属性清零。下面的步骤才是重点:循环的目的是找到已有数组里的最小两个权值,然后把这2个作为此左右儿子,此为他们的父母,此权值                     也会成为他们的权值和。把此放入数组,再进行循环,直到数组满位置,找到树根。最后的求编码值,思路是:找到一开始时候的数组,也就是叶子树,从每个叶子                     开始,循环找到 它离根的距离,即就是它的编码位数,然后循环此数组就可以实现。输出用C语言更加简单。

做题感想:其实这题比较难了,为什么选这道题呢?其实我也有自己的想法,主要是想有个好一点的做题的开头吧,鼓励自己要坚持下去。上课那天的前天刚得了肠胃炎挂了水                     还没有好,所以那天上课昏昏沉沉的,也没有怎么听明白,回来自己看的课件弄的。同学舍友在选课的时候就劝我别选,但我觉得有用就选了。这学期刚开始我就觉                     得压力很大了,主要是专业课一下子转难了,没适应过来,其次我还和舍友一起报了驾校,再者我周六还有辅修,所以做题的时间非常少了,但我觉得时间总可以                         挤出来的。同学舍友看我那么忙又要劝我退,我还是想学学。这道题我用了2天的时间,查阅了哈夫曼树,改了好多次才A的,感觉很不错,毕竟自己很喜欢成功这                       种感觉,虽然代价有点大,但毕竟学到点东西了。大学该留下点什么的,ACM确实是个不错的选择,我希望自己能一直坚持下去,就算没有时间做题,咬着牙,男人                    不会半途而废!

### 哈夫曼的Java实现 哈夫曼是一种用于数据压缩的重要工具,在构建过程中,主要目标是最小化加权路径长度。对于给定的一组频率或者权重,可以创建对应哈夫曼来优化编码效率[^1]。 下面是一个完整的Java程序示例,展示了如何基于一组整数(表示字符出现次数或概率)建立哈夫曼并对其进行中序遍历: ```java import java.util.*; class Node implements Comparable<Node> { int weight; char data; // 如果是叶子节点则存储实际的数据, 否则是 &#39;\0&#39; Node leftChild, rightChild; public Node(char ch, int freq) { this.data = ch; this.weight = freq; } @Override public int compareTo(Node otherNode) { return Integer.compare(this.weight, otherNode.weight); } } public class HuffmanTree { private static PriorityQueue<Node> minHeap = new PriorityQueue<>(); /** * 构建哈夫曼. */ public static void buildHuffmanTree(List<Integer> weights){ for (int w : weights) { minHeap.add(new Node((char)(w), w)); } while(minHeap.size() != 1){ Node firstMin = minHeap.poll(); Node secondMin = minHeap.poll(); Node parent = new Node(&#39;\0&#39;,firstMin.weight + secondMin.weight); parent.leftChild = firstMin; parent.rightChild = secondMin; minHeap.offer(parent); } } /** * 中序遍历哈夫曼. */ public static void inorderTraversal(Node root){ if(root == null) return ; inorderTraversal(root.leftChild); System.out.print(String.format("(%c,%d)",root.data,root.weight)); inorderTraversal(root.rightChild); } } ``` 此代码片段定义了一个`Node`类用来表示哈夫曼中的每一个节点,并实现了比较器接口以便于优先队列能够自动按权重从小到大排列这些节点。接着提供了两个静态方法:一个是`buildHuffmanTree()`负责根据传入的权重列表构造哈夫曼;另一个是`inorderTraversal()`执行中序遍历操作并将结果打印出来[^3]。 为了使上述代码正常工作,还需要调用这两个函数以及处理输入输出部分。注意这里简化了原始问题描述里的具体细节,比如只考虑了整型数组而不是更复杂的场景下的应用案例[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值