课程:《程序设计与数据结构》
班级:1823
姓名:华罗晗
学号:20182308
实验教师:王志强
实验日期:(课后实践)
必修/选修:必修
1.实验内容
设有字符集:S={a,b,c,d,e,f,g,h,i,j,k,l,m,n.o.p.q,r,s,t,u,v,w,x,y,z}。
给定一个包含26个英文字母的文件,统计每个字符出现的概率,根据计算的概率构造一颗哈夫曼树。
并完成对英文文件的编码和解码。
要求:
- 准备一个包含26个英文字母的英文文件(可以不包含标点符号等),统计各个字符的概率
- 构造哈夫曼树
- 对英文文件进行编码,输出一个编码后的文件
- 对编码文件进行解码,输出一个解码后的文件
- 撰写博客记录实验的设计和实现过程,并将源代码传到码云
- 把实验结果截图上传到云班课
2. 实验思路、过程及结果
1、百度上找到一个符合要求的文段。
2、构造哈夫曼树,首先哈弗曼树是一种树,所以必须要制造结点,这是Node代码里面的一部分方法。
public HuffmanNode(T name, double length)
{
this.name = name;
this.length = length;
code = "";
}
public T getName()
{
return name;
}
public void setName(T name)
{
this.name = name;
}
public double getLength()
{
return length;
}
public void setLength(double length)
{
this.length = length;
}
public HuffmanNode getLeft()
{
return left;
}
public void setLeft(HuffmanNode left)
{
this.left = left;
}
public HuffmanNode getRight()
{
return right;
}
public void setRight(HuffmanNode right)
{
this.right = right;
}
public String getCode()
{
return code;
}
public void setCode(String str)
{
code = str;
}
@Override
public String toString()
{
return "name:"+this.name+";length:"+this.length+";编码为: "+this.code;
}
@Override
public int compareTo(HuffmanNode other)
{
if(other.getLength() > this.getLength())
return 1;
if(other.getLength() < this.getLength())
return -1;
return 0;
}
这是哈弗曼树的结点类中的一些方法,哈弗曼树构造的本体中还有一些别的构造树的方法,大体与之前打的树差不多。
这里列举出建树部分的代码:
public HuffmanNode createTree(List> nodes)
{
while (nodes.size() > 1)
{
Collections.sort(nodes);
HuffmanNode left = nodes.get(nodes.size() - 2);
left.setCode(0 + "");
HuffmanNode right = nodes.get(nodes.size() - 1);
right.setCode(1 + "");
HuffmanNode parent = new HuffmanNode(null, left.getLength() + right.getLength());
parent.setLeft(left);
parent.setRight(right);
nodes.remove(left);
nodes.remove(right);
nodes.add(parent);
}
return nodes.get(0);
}
public List breadth(HuffmanNode root)
{
List list = new ArrayList();
Queue queue = new ArrayDeque();
if (root != null)
{
queue.offer(root);
root.getLeft().setCode(root.getCode() + "0");
root.getRight().setCode(root.getCode() + "1");
}
while (!queue.isEmpty())
{
list.add(queue.peek());
HuffmanNode node = queue.poll();
if (node.getLeft() != null)
node.getLeft().setCode(node.getCode() + "0");
if (node.getRight() != null)
node.getRight().setCode(node.getCode() + "1");
if (node.getLeft() != null)
{
queue.offer(node.getLeft());
}
if (node.getRight() != null)
{
queue.offer(node.getRight());
}
}
return list;
}
3、对英文文件进行编码,首先需要创建一个文件、并且进行读入,这里沿用I/O相关的内容。这一部分的代码就跳过啦,把这个文件中的英文转换成String格式的变量、进行01加密。再新建两个文件将目标变量res(编码后)和String2(解码后)写入。同时再对String进行操作,计算一下出现概率之类的变量。
int temp = 0;
for(int e = 0;e putlist = new ArrayList();
for(int i = 0;i < res.length();i++)
putlist.add(res.charAt(i)+"");
String string1 = "";
String string2 = "";
for(int h = putlist.size(); h > 0; h--){
string1 = string1 + putlist.get(0);
putlist.remove(0);
for(int i=0;i
4、读取部分放在了之后的错误抛出部分,在此就不把代码放出来了。
运行结果如下图所示:
3. 实验过程中遇到的问题和解决过程
- 问题1:错误抛出问题。
- 问题1解决方案:参看同学代码的时候,想到了抛出错误的问题。因此加入了以下的方法代码(同时对于两个新建文件的读入操作也在这里):
private static int getFileLineCount(File file) {
int cnt = 0;
InputStream is = null;
try
{
is = new BufferedInputStream(new FileInputStream(file));
byte[] c = new byte[1024];
int readChars = 0;
while ((readChars = is.read(c)) != -1)
{
for (int i = 0; i < readChars; ++i)
{
if (c[i] == '\n')
++cnt;
}
}
} catch (Exception ex)
{
cnt = -1;
ex.printStackTrace();
}
finally
{
try
{
is.close();
}
catch (Exception ex)
{ex.printStackTrace();}
}
return cnt;
}
参考资料
《Java程序设计与数据结构教程(第二版)》
《Java程序设计与数据结构教程(第二版)》学习指导