哈弗曼编码与反编码的实现 java源代码下载地址:
public class Huffman {
public static void main(String[] args) {
new HaffmanFrame();
}
}
//主界面类
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
//主界面
public class HaffmanFrame extends JFrame implements ActionListener {
private static final long serialVersionUID = 1808617924849665897L;
private JButton choice, ok, reset,recoding,re;//choice 文件选择,ok 确定 ,reset 重置,recoding 反编译
private JLabel choiceJL,codingJL,recodingJL;//选择 编码 反编码 标签
private JTextArea inputJTA,recodingJTA;
private JScrollPane js1,js2,js3;
private HaffmanJTable table ;
private TotalChars tc = null;
private HffmanCoding hfc = null;
HaffmanFrame(){
super("哈弗曼编码与反编码");
newFrame();//界面的初始化
formeValidate();
}
@Override
public void actionPerformed(ActionEvent e) {
// TODO 事件的处理
if(e.getSource() == choice) {
open();
}
else if(e.getSource() == ok) {
ok();
}
else if(e.getSource() == reset) {
reset();
}
else if(e.getSource() == recoding) {
if(tc != null )
{
JOptionPane.showMessageDialog(this, hfc.reCoding(recodingJTA.getText()), "反哈弗曼编码文本",
JOptionPane.DEFAULT_OPTION);
}
}
else if(e.getSource() == re) {
recodingJTA.setText(null);
}
}
//重置
private void reset() {
inputJTA.setText("");
recodingJTA.setText("");
table.beginTable();
table.repaint();
}
// 确定
private void ok() {
table.beginTable();
table.repaint();
tc = new TotalChars();
int chars[][] = tc.getCharAddWeight(inputJTA.getText());
hfc = new HffmanCoding(chars);
hfc.coding();//哈弗曼树
String s[] = hfc.CreateHCode();//哈弗曼编码
for (int i = 0; i < chars.length; i++) {
if (chars[i][0]<= 32)
table.setT(i, 0, "A" + String.valueOf(chars[i][0]));//以ascll码的形式在表格输出
else
table.setT(i, 0, String.valueOf((char) chars[i][0]));//以字符的形式在表格输出
table.setT(i, 1, String.valueOf(chars[i][1]));
table.setT(i, 2, s[i]);
}
recodingJTA.setText(hfc.show(inputJTA.getText()));
table.repaint();
}
// 打开
private void open() {
inputJTA.setText("");
FileOpen fo = new FileOpen(this);
fo.open();
inputJTA.setText(fo.getText());
fo = null;
}
//界面的初始化
private void newFrame() {
table = new HaffmanJTable();
choice = new JButton("选择文件");
ok = new JButton("确 定");
reset = new JButton("重 置");
recoding = new JButton("反编码");
re = new JButton("重置反编码");
choiceJL = new JLabel("请选择文件或输入文本:");
codingJL = new JLabel("字符的哈弗曼编码:");
recodingJL = new JLabel("文本的哈弗曼编码表示:");
inputJTA = new JTextArea(5,5);
recodingJTA = new JTextArea(5,5);
recodingJTA.setLineWrap(true);
js1 = new JScrollPane(inputJTA);
js2 = new JScrollPane(table.myTable());
js3 = new JScrollPane(recodingJTA);
//设置位置
choiceJL.setBounds(10, 10, 150, 30);
js1.setBounds(160, 10, 320, 150);
ok.setBounds(200, 170, 80, 30);
reset.setBounds(350, 170, 80, 30);
choice.setBounds(30,50,100,30);
codingJL.setBounds(10, 210, 150, 30);
js2.setBounds(160, 210, 320, 150);
recodingJL.setBounds(10, 370, 150, 30);
js3.setBounds(160, 370, 320, 150);
recoding.setBounds(30, 410, 100, 30);
re.setBounds(30, 450, 100, 30);
this.setLayout(null);
this.add(choiceJL);
this.add(js1);
this.add(ok);
ok.addActionListener(this);
this.add(reset);
reset.addActionListener(this);
this.add(choice);
choice.addActionListener(this);
this.add(re);
re.addActionListener(this);
this.add(codingJL);
this.add(js2);
this.add(recodingJL);
this.add(js3);
this.add(recoding);
recoding.addActionListener(this);
Font f = new Font("宋体",Font.BOLD,15);//设置字体
inputJTA.setFont(f);
recodingJTA.setFont(f);
}
private void formeValidate() {
Toolkit tk = getToolkit();//获得屏幕的宽和高
Dimension dim = tk.getScreenSize();
this.setResizable(false);
this.setBounds(dim.width/2-250, dim.height/2-280,500,570);
setVisible(true);
validate();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
//表格类
import java.awt.Component;
import java.awt.Font;
import javax.swing.JTable;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
public class HaffmanJTable {
private JTable table;
private Object t[][] = new Object[100][3];//用来存放字符 次数 和哈弗曼编码
private Object name[] = {"字符","次数","哈弗曼编码"};//用来存放表头
public Component myTable() {
// TODO Auto-generated method stub
table = new JTable(t,name);
Font f = new Font("宋体",Font.BOLD,15);//设置字体
table.setFont(f);
setColumnSize(0,40);//设置第1列的大小
setColumnSize(1,60);//设置第2列的大小
setColumnSize(2,202);//设置第3列的大小
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);//AUTO_RESIZE_OFF
// 不自动调整列的宽度;使用滚动条。
//table.setAutoResizeMode()当调整表的大小时,设置表的自动调整模式。
return table;
}
public void setT(int i ,int j, String volue) {//设置表格的值
this.t[i][j] = volue;
}
public void setColumnSize(int i, int width ) {
TableColumnModel cm = table.getColumnModel(); //表格的列模型
TableColumn column = cm.getColumn(i);//得到第i个列对象
column.setPreferredWidth(width);//将此列的首选宽度设置为 preferredWidth。
//如果 preferredWidth 超出最小或最大宽度,则将其调整为合适的界限值。
}
public void repaint() {//重绘表格
table.repaint();
}
public void beginTable()//重值表格
{
for (int i = 0; i < 100; i++) {
for (int j = 0; j < 3; j++)
setT(i, j, "");
}
}
}
//文件的打开
import java.awt.FileDialog;
import java.awt.event.*;
import java.io.*;
import java.io.File;
import java.io.FileReader;
public class FileOpen {
private FileDialog filedialog_open;
private String fileopen = null, filename = null;// 用于存放打开文件地址 和文件名
private File file1; // 文件字节流对象
private FileReader file_reader;//文件字符流对象
private BufferedReader in;//文件行读取 写入对象
private StringBuffer text = new StringBuffer();
HaffmanFrame haffman= null;
FileOpen(HaffmanFrame hf) {
haffman = hf;
filedialog_open = new FileDialog(haffman, "打开文件对话框", FileDialog.LOAD);
// 打开文件对话框适配器
filedialog_open.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
filedialog_open.setVisible(false);
}
});
}
public void open() {
String s = "";
filedialog_open.setVisible(true);
fileopen = filedialog_open.getDirectory();// 返回文件对话框中显示的文件所属的目录
filename = filedialog_open.getFile();// 返回当前文件对话框中显示的文件名的字符串表示
// 如果不存在就返回NULL
if (filename != null)// 判断打开的文件是否存在
{
try {
file1 = new File(fileopen,filename );
file_reader = new FileReader(file1);
in = new BufferedReader(file_reader);//每次读取一行
while ((s = in.readLine()) != null)
text.append(s + '/n');
in.close();
file_reader.close();
} catch (IOException e2) {
System.out.println("不能打开文件!");
}
}
}
//返回得到的文本字符串
public String getText() {
return new String(text);
}
}
//统计字符类
public class TotalChars {
private int charCount[] = new int[255];
private char c[];//统计字符的个数
private int charAddWeight[][];//存放字符的ascll码值和字符的频率
private int total = 0;//存放需要编码字符的个数
TotalChars(){
for(int i = 0; i<255;i++)
charCount[i] = 0;
}
//统计每个字符的出现的个数
public void charToal(String s) {
c = new char[s.length()];
c = s.toCharArray();// 将字符串转化为字符数组
for (int i = 0; i < c.length; i++) {
int j = c[i];
charCount[j]++;
}
for(int i = 0; i < 255 ; i++) {
if (charCount[i] != 0) {
total++;//统计字符的个数
}
}
}
// 返回字符的ascll码值和字符的频率
public int[][] getCharAddWeight(String s){
charToal(s);//统计每个字符的出现的个数
charAddWeight = new int[total][2];
for(int i = 0,j=0; i < 255 ; i++) {
if (charCount[i] != 0) {
charAddWeight[j][0] = i;
charAddWeight[j++][1] = charCount[i];
}
}
return charAddWeight;
}
}
//哈弗曼编码的实现类
public class HffmanCoding {
private int charsAndWeight[][];// [][0]是 字符,[][1]存放的是字符的权值(次数)
private int hfmcoding[][];// 存放哈弗曼树
private int i = 0;// 循环变量
private String hcs[];
public HffmanCoding(int[][] chars) {
// TODO 构造方法
charsAndWeight = new int[chars.length][2];
charsAndWeight = chars;
hfmcoding = new int[2 * chars.length - 1][4];// 为哈弗曼树分配空间
}
// 哈弗曼树的实现
public void coding() {
int n = charsAndWeight.length;
if (n == 0)
return;
int m = 2 * n - 1;
// 初始化哈弗曼树
for (i = 0; i < n; i++) {
hfmcoding[i][0] = charsAndWeight[i][1];// 初始化哈弗曼树的权值
hfmcoding[i][1] = 0;// 初始化哈弗曼树的根节点
hfmcoding[i][2] = 0;// 初始化哈弗曼树的左孩子
hfmcoding[i][3] = 0;// 初始化哈弗曼树的右孩子
}
for (i = n; i < m; i++) {
hfmcoding[i][0] = 0;// 初始化哈弗曼树的权值
hfmcoding[i][1] = 0;// 初始化哈弗曼树的根节点
hfmcoding[i][2] = 0;// 初始化哈弗曼树的左孩子
hfmcoding[i][3] = 0;// 初始化哈弗曼树的右孩子
}
// 构建哈弗曼树
for (i = n; i < m; i++) {
int s1[] = select(i);// 在哈弗曼树中查找双亲为零的 weight最小的节点
hfmcoding[s1[0]][1] = i;// 为哈弗曼树最小值付双亲
hfmcoding[s1[1]][1] = i;
hfmcoding[i][2] = s1[0];// 新节点的左孩子
hfmcoding[i][3] = s1[1];// 新节点的右孩子
hfmcoding[i][0] = hfmcoding[s1[0]][0] + hfmcoding[s1[1]][0];// 新节点的权值是左右孩子的权值之和
}
}
// 查找双亲为零的 weight最小的节点
private int[] select(int w) {
// TODO Auto-generated method stub
int s[] = { -1, -1 }, j = 0;// s1 最小权值且双亲为零的节点的序号 , i 是循环变量
int min1 = 32767, min2 = 32767;
for (j = 0; j < w; j++) {
if (hfmcoding[j][1] == 0) {// 只在尚未构造二叉树的结点中查找(双亲为零的节点)
if (hfmcoding[j][0] < min1) {
min2 = min1;
s[1] = s[0];
min1 = hfmcoding[j][0];
s[0] = j;
} else if (hfmcoding[j][0] < min2) {
min2 = hfmcoding[j][0];
s[1] = j;
}
}
}
return s;
}
public String[] CreateHCode() {// 根据哈夫曼树求哈夫曼编码
int n = charsAndWeight.length;
int i, f, c;
String hcodeString = "";
hcs = new String[n];
for (i = 0; i < n; i++) {// 根据哈夫曼树求哈夫曼编码
c = i;
hcodeString = "";
f = hfmcoding[i][1]; // f 哈弗曼树的根节点
while (f != 0) {// 循序直到树根结点
if (hfmcoding[f][2] == c) {// 处理左孩子结点
hcodeString += "0";
} else {
hcodeString += "1";
}
c = f;
f = hfmcoding[f][1];
}
hcs[i] = new String(new StringBuffer(hcodeString).reverse());
}
return hcs;
}
public String show(String s) {// 对字符串显示编码
String textString = "";
char c[];
int k = -1;
c = new char[s.length()];
c = s.toCharArray();// 将字符串转化为字符数组
for (int i = 0; i < c.length; i++) {
k = c[i];
for (int j = 0; j < charsAndWeight.length; j++)
if (k == charsAndWeight[j][0])
textString += hcs[j];
}
return textString;
}
// 哈弗曼编码反编译
public String reCoding(String s) {
String text = "";// 存放反编译后的字符
int k = 0, m = hfmcoding.length - 1;// 从根节点开始查询
char c[];
c = new char[s.length()];
c = s.toCharArray();
k = m;
for (int i = 0; i < c.length; i++) {
if (c[i] == '0') {
k = hfmcoding[k][2];// k的值为根节点左孩子的序号
if (hfmcoding[k][2] == 0 && hfmcoding[k][3] == 0)// 判断是不是叶子节点,条件(左右孩子都为零)
{
text += (char) charsAndWeight[k][0];
k = m;
}
}
if (c[i] == '1') {
k = hfmcoding[k][3];// k的值为根节点右孩子的序号
if (hfmcoding[k][2] == 0 && hfmcoding[k][3] == 0)// 判断是不是叶子节点,条件(左右孩子都为零)
{
text += (char) charsAndWeight[k][0];
k = m;
}
}
}
return text;
}
}
标签:reset,编码,源代码,ok,private,table,弗曼
From: https://blog.51cto.com/aimilin/7739328