哈夫曼编码问题

Description

给定一个数字N,代表有N种不同的字符,已知每种字符的出现次数,现在要求你设计一种编码,使得任意一个编码都不是另外一个编码的前缀,并且使得这些字符经过编码压缩之后的总长度最小; 

Input

一个数字N 代表有多少种不同的字符(0<=N<=1000)N个数字  每个数字代表一种字符的出现次数

Output

一个数字,代表总的编码长度

Sample Input

5
1
2
3
4
5

3
3
8
8

Sample Output

33
30

正常版

#include<bits/stdc++.h>
using namespace std;
bool bj[2001];
struct jg{
    int l,r,q;
};
struct nsj
{
    int n1,n2;
};
int data[2001],cd[2001];
jg shu[2001];
void dfs(int x,int y);
nsj zhapy(int x);
int main()
{
    int n,i,cnt;
    nsj n12;
    while(cin>>n)
    {
        memset(cd,0,sizeof(cd));
        memset(shu,0,sizeof(shu));
        for(i=1;i<=n;i++)
        {
            cin>>data[i];
        }
        for(i=1;i<=n;i++)
        {
            bj[i]=true;
            bj[i+n]=false;
        }
        cnt=n;
        while(cnt<2*n-1)
        {
            n12=zhapy(cnt);
            bj[n12.n1]=bj[n12.n2]=false;
            cnt++;
            bj[cnt]=true;
            shu[cnt].l=n12.n1;
            shu[cnt].r=n12.n2;
            shu[cnt].q=data[n12.n1]+data[n12.n2];
            data[cnt]=data[n12.n1]+data[n12.n2];
        }
        dfs(2*n-1,0);
        int ans=0;
        for(i=1;i<=n;i++)
        {
            ans+=cd[i]*data[i];
        }
        cout<<ans<<endl;
    }
    return 0;
}
nsj zhapy(int x)
{
    nsj cnt;
    int x1,x2,i;
    x1=999999999;
    x2=999999999;
    cnt.n1=1;
    cnt.n2=1;
    for(i=1;i<=x;i++)
    {
        if(bj[i])
        {
            if(data[i]<x1)
        {
            x2=x1;
            cnt.n2=cnt.n1;
            x1=data[i];
            cnt.n1=i;
        }
        else if(data[i]<x2)
        {
            cnt.n2=i;
            x2=data[i];
        }
        }

    }
    return cnt;
}
void dfs(int x,int y)
{
    int l,r;
    l=shu[x].l;
    if(l!=0)
    {
        dfs(l,y+1);
        r=shu[x].r;
        dfs(r,y+1);
    }
    else
    {
        cd[x]=y;
    }
}

变态版:

#include<bits/stdc++.h>
using namespace std;bool bj[2001];struct jg{int l,r,q;};struct nsj{int n1,n2;};int data[2001],cd[2001];jg shu[2001];void dfs(int x,int y);nsj zhapy(int x);int main(){int n,i,cnt;nsj n12;while(cin>>n){memset(cd,0,sizeof(cd));memset(shu,0,sizeof(shu));for(i=1;i<=n;i++){cin>>data[i];}for(i=1;i<=n;i++){bj[i]=true;bj[i+n]=false;}cnt=n;while(cnt<2*n-1){n12=zhapy(cnt);bj[n12.n1]=bj[n12.n2]=false;cnt++;bj[cnt]=true;shu[cnt].l=n12.n1;shu[cnt].r=n12.n2;shu[cnt].q=data[n12.n1]+data[n12.n2];data[cnt]=data[n12.n1]+data[n12.n2];}dfs(2*n-1,0);int ans=0;for(i=1;i<=n;i++){ans+=cd[i]*data[i];}cout<<ans<<endl;}return 0;}nsj zhapy(int x){nsj cnt;int x1,x2,i;x1=999999999;x2=999999999;cnt.n1=1;cnt.n2=1;for(i=1;i<=x;i++){if(bj[i]){if(data[i]<x1){x2=x1;cnt.n2=cnt.n1;x1=data[i];cnt.n1=i;}else if(data[i]<x2){cnt.n2=i;x2=data[i];}}}return cnt;}void dfs(int x,int y){int l,r;l=shu[x].l;if(l!=0){dfs(l,y+1);r=shu[x].r;dfs(r,y+1);}else{cd[x]=y;}}
### Java 实现哈夫曼编码 #### 哈夫曼树构建过程 在Java中实现哈夫曼编码,首先要创建一个节点类`Node`用于表示哈夫曼树的各个结点。该类应包含权重、字符以及指向左子节点和右子节点的指针。 ```java class Node implements Comparable<Node> { char ch; int weight; Node left, right; public Node(char ch, int weight) { this.ch = ch; this.weight = weight; } @Override public int compareTo(Node other) { return Integer.compare(this.weight, other.weight); } } ``` 接下来定义方法`createHT`来构建哈夫曼树。此函数接收一组字符及其对应的频率作为输入参数,并返回一棵完整的二叉树结构[^1]。 ```java public static Node createHT(Map<Character, Integer> freqMap) { PriorityQueue<Node> pq = new PriorityQueue<>(); // 将所有字符加入优先队列 for (var entry : freqMap.entrySet()) { pq.add(new Node(entry.getKey(), entry.getValue())); } while(pq.size() != 1){ Node n1 = pq.poll(); Node n2 = pq.poll(); Node parent = new Node('\0', n1.weight + n2.weight); parent.left = n1; parent.right = n2; pq.offer(parent); } return pq.peek(); } ``` #### 编码生成逻辑 一旦获得了哈夫曼树,则可以通过递归方式遍历整棵树并记录路径上的'0'(向左走)'1'(向右走),从而得到每个叶子节点所代表字符的具体编码串。这里可以借助辅助函数完成: ```java private void buildCodes(Node node, String codeStr, Map<Character, String> codes) { if(node == null) return ; if(Character.isDefined(node.ch)) codes.put(node.ch, codeStr); buildCodes(node.left , codeStr+"0",codes); buildCodes(node.right, codeStr+"1",codes); } // 调用buildCodes初始化编码映射表 public Map<Character, String> generateHuffmanCode(Node root) { Map<Character, String> huffManCodes = new HashMap<>(); buildCodes(root,"",huffManCodes ); return huffManCodes ; } ``` #### 字符串压缩解压功能 有了上述准备之后就可以轻松地编写两个主要的功能——字符串到其哈夫曼编码形式之间的转换(`encode`);反之亦然(`decode`)。 ```java public String encode(String inputText, Map<Character, String> codes) { StringBuilder encodedString = new StringBuilder(); for (char c : inputText.toCharArray()) encodedString.append(codes.get(c)); return encodedString.toString(); } public String decode(String encodedData, Node rootNode) { StringBuilder decodedOutput = new StringBuilder(); Node current = rootNode; for (char bit : encodedData.toCharArray()){ if(bit=='0') current=current.left; else if(bit=='1') current=current.right; if(current!=null && Character.isLetterOrDigit(current.ch)){ decodedOutput.append(current.ch); current=rootNode; } } return decodedOutput.toString(); } ``` 通过以上步骤,在Java环境中实现了基本的哈夫曼编码机制,能够有效地减少原始数据量的同时保持信息不失真[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值