信息论实验:包括哈夫曼编码和解码,汉明编码和解码,交错去交错,加入错码码元,图形化界面
信息论的实验要求:
我用cpp和java都写了一份程序,java的是带有有图形化界面的。cpp的程序是要在当前目录下创建words.txt,java的是直接图形化界面输入,加入了其他一些功能更加完整。可以对128个ASCII字符进行编码。
(一)统计数据
在对输入的数据进行信源编码即哈夫曼编码前首先要统计数据中各个字符出现的频率。对文本中出现的128个ASCII字符进行编码。从输入框中统计数据,统计各个字符出现的频率和总的字符个数。二者相除,即可得到各个字符出现的频率。
(二)信道编码和译码
1)哈夫曼编码:
哈夫曼码首先要构建哈夫曼树,
首先哈夫曼树有一个特性,对于具有n个叶子结点的哈夫曼树,总共有2n-1个结点,因为哈夫曼树无度为1的结点。所以首先要对所有节点进行初始化,包括叶子结点和父节点。然后先在叶子结点中找到对应的频率值最小的结点求和,将求和得到的结果放入父节点中。并将这个父节点加入下一轮求频率最小的搜索范围中。不断进行搜索最小概率的结点的过程,直至所有节点都被覆盖,即达到概率为1。此时哈夫曼树就构建好了。构建完哈夫曼树后,根据哈夫曼树找叶子结点。首先要找到根节点,再沿着根节点找到所有对应的叶子结点,这里将左分支变为“0”,右分支编为“1”.这样就可以得到所有字母对应的哈夫曼编码。
2.哈夫曼解码:删除信源编码时补充的零,得到哈夫曼编码后的序列。按照正向最大匹配算法进行解码。采用正向最大匹配算法:从左往右扫描要解码的文本:第一次扫描n个字符,如果字典中有匹配的key则用该key对应的value替换这n个字符,如果无匹配的key则n=n-1,再次扫描。先匹配最长的哈夫曼码,如果不能匹配再减小码元长度,直到成功匹配为止。匹配后在哈希表中查找哈夫曼码对应的字母,得到解码后的数据。
4.哈明编码:
采用(7,4)汉明编码,这里要对哈夫曼编码后的数据进行预处理,因为哈夫曼编码后的数据长度可能不是4的倍数,因此对于不足的部分要补零。以四个码元作为一个码字,将每个码字与生成矩阵相乘得到(7,4)汉明码,再根据汉明码编码要发送的数据。
5.汉明解码:
对(7,4)汉明码进行纠错和解码恢复哈夫曼编码后的信息序列。纠错是通过计算伴随式,判断伴随式是否与一致校验矩阵中的某一列相同,如果相同说明该列元素出现错误,该列对应的差错图案的位为1。再将原序列与差错图案模二相加得到纠错后的码元。在哈希表中查找纠错后的码字所对应的四位哈夫曼编码。得到解码后的信息序列。
6.交错:
将要改变要发送的码字的顺序。先确定要交错的码元数目即为上图中交错器的行数,这里取发送码元的数目除以七的结果这样可以把误码分摊到每个码字上。将总码元数与交错器的交错码元数相除,得到交错器的列数。新的数据是从第一列开始一行行的读取数据,既可以得到交错后的码元。
去交错是交错的反过程。
7.加入错误码元:
这个就是简单的取反,只是要注意起始码元和错误码元的范围。
代码:我写了两份cpp和java版的。主要是java版的有图形化界面。cpp版的可能还有一些bug没有改正,欢迎指出。我都列出来吧
没有写成单独的是写成的一个个类,可以看单独的类。
1.cpp版:
#include<iostream>
#include<math.h>
#include<fstream>
#include<vector>
#include<unordered_map>
#include<cstdlib>
#include<ctime>
using namespace std;
#define N 4
#define K 7
struct HRNode//建立哈夫曼树的结构体
{
double frequency;
char key;
HRNode *lchild;
HRNode *rchild;
HRNode *parent;
HRNode(double x, char y): frequency(x), key(y), lchild(NULL), rchild(NULL), parent(NULL) {}
};
class File_io {
public:
void calculate(vector<double>& fre)//这里是读取的部分
{
fstream infile;
infile.open("words.txt");//读取文件
if(!infile.is_open())
{
cout<<"读取文件错误"<<endl;
return;
}
int len = 0;
string strfile, tmp;
while(getline(infile, tmp))//getline是读取文件中的一行
{
for(int i = 0;i < tmp.size();i++)
{
fre[tmp[i]]++;
len++;
}
}
for(int i = 0;i < fre.size();i++)//统计频率
{
fre[i] = fre[i]/len;
}
}
vector<int> send_file(unordered_map<char, string> HF_map_char2str)
{
fstream infile;
infile.open("words.txt");//读取文件
if(!infile.is_open())
{
cout<<"读取文件错误"<<endl;
}
vector<int> mess_send;
int len = 0;
string strfile, tmp;
char uni_char;//将大小写同一转化后的字母
while(getline(infile, tmp))//getline是读取文件中的一行
{
for(int i = 0;i < tmp.size();i++)
{
uni_char = tmp[i];
string str_tmp = HF_map_char2str[uni_char];
for(int j = 0;j<str_tmp.size();j++)
{
mess_send.push_back(str_tmp[j]-'0');
}
len++;
}
}
return mess_send;
}
};
class Haffman_Tree
{
private:
int valid_len;
int longest_str;
public:
unordered_map<char, string> HF_map_char2str;
unordered_map<string, char> HF_map_str2char;
vector<string>Process(vector<double>fre)
{
valid_len = 0;
vector<HRNode*> Tree(fre.size());
CreateHaffmanTree(fre,Tree,valid_len);
vector<string> HFcode(valid_len,"");
CreateHCode(Tree, HFcode);
return HFcode;
}
//Tree中有各个分立的结点,如何把它们连接成哈夫曼树
void CreateHaffmanTree(vector<double>& fre,vector<HRNode*>& Tree, int& n0)
{
HRNode* HuffmanTree;
//初始化部分
n0 = 0;//叶子结点的数目
for(int i = 0;i < fre.size();i++)
{
if(fre[i]>0)//只要编码频率不为0的字符
{
HRNode* tmp = new HRNode(fre[i],i);
Tree[n0]=tmp;
n0++;
}
}
int n = 2*n0 - 1;
Tree.resize(n);
for(int i = n0;i < n;i++)
{
HRNode* tmp = new HRNode(0,0);
Tree[i]=tmp;
}
double min1, min2;
HRNode* lnode;
HRNode* rnode;
for(int i = n0;i < n;i++)
{
min1 = min2 = INT_MAX;
lnode = NULL;
rnode = NULL;
for (int k = 0;k <= i - 1;k++)
{
if (Tree[k]->parent == NULL)
{
if (Tree[k]->frequency < min1)
{
min2 = min1;
rnode = lnode;
min1 = Tree[k]->frequency;
lnode = Tree[k];
}
else if (Tree[k]->frequency < min2)
{
min2 = Tree[k]->frequency;
rnode = Tree[k];
}
}
}
Tree[i]->frequency = lnode->frequency + rnode->frequency;
Tree[i]->lchild = lnode;
Tree[i]->rchild = rnode;
lnode->parent = Tree[i];
rnode->parent = Tree[i];
}
}
//编译为哈夫曼码,这里需要注意不能有编码全为0的情况出现,因为后面要补零
void CreateHCode(vector<HRNode*> ht, vector<string>& hcd)
{
longest_str = 0;
HRNode* f;
HRNode* c;
char tmp;
for (int i = 0;i < valid_len; i++)//根据哈夫曼树求哈夫曼编码
{
f = ht[i]->parent;
c = ht[i];
tmp = c->key;
int n = 2*valid_len - 1;//哈夫曼树总的结点个数
while(f != NULL)//循环到达根节点
{
if (f->lchild == c)//当前节点是双亲节点的左孩子
{
hcd[i]+='1';
}
else//当前节点是双亲节点的右孩子
{
hcd[i]+='0';
}
c = f;
f = f->parent;
}
for(int j = 0;j < valid_len;j++)
{
reverse(hcd[j].begin(),hcd[j].end());
}
cout<<"字母:"<<tmp<<"编码为:"<<hcd[i]<<endl;
HF_map_str2char[hcd[i]] = tmp;
HF_map_char2str[tmp] = hcd[i];
int tmp_len = hcd[i].length();
longest_str = max(longest_str, tmp_len);
}
}
string decode(vector<int>& Hm_code, int supply_zero)
{
Hm_code.erase(Hm_code.end()-supply_zero,Hm_code.end());
int len = Hm_code.size();
string s = "";
string res = "";
vector<int> temp(longest_str);
if(len==0)
{
return "";
}
int i = 0;
int sub_len = min(len, longest_str);
while(i < len)
{
s = "";
temp.clear();
if(sub_len<=0)
break;
copy(Hm_code.begin()+i,Hm_code.begin()+i+sub_len,temp.begin());//这个copy一定要多加一位
for(int j = 0;j < sub_len;j++)
{
s += temp[j]+'0';
}
if (HF_map_str2char.find(s)==HF_map_str2char.end())
{
sub_len--;
}
else
{
res += HF_map_str2char[s];
i += sub_len;
sub_len = min(longest_str, len-i);
}
}
return res;
}
};
/*
由接收到的7位序列和校验矩阵相乘得到校验子S
然后由纠正子e和S的关系求出e
最后通过接收的码字和e求和得到就正好的序列
74汉明码只能识别和纠正一位错误
*/
class Hamming
{
private:
int G[N][K]={{1,0,0,0,1,0,1},//生成矩阵
{0,1,0,0,1,1,1},
{0,0,1,0,1,1,0},
{0,0,0,1,0,1,1}};
int H[K-N][K]={{1,1,1,0,1,0,0},//一致校验矩阵
{0,1,1,1,0,1,0},
{1,1,0,1,0,0,1}};
int s[K-N];//伴随式
int e[K];//差错图案
int code_send[K];
int code_received[K];//接收码字
int mess_get[N];//解码得到的消息
vector<int> result;
vector<int> get_result;
unordered_map<string,string>mess2Hm;
unordered_map<string, string>Hm2mess;
public:
int supply_zero;
vector<int> Process_send(vector<int>&mess_send)
{
vector<int> temp(N);
int len = mess_send.size();
supply_zero = (N-len%N)%N;
for(int i = 0;i < supply_zero;i++)
{
mess_send.push_back(0);
}
len = mess_send.size();
for(int i = 0;i < len/N;i++)
{
temp.resize(N,0);
copy(mess_send.begin()+i*N,mess_send.begin()+(i+1)*N,temp.begin());//这个copy一定要多加一位
coding(temp);
}
return result;
}
vector<int> Process_decode(vector<int>& mess_receive)
{
vector<int> temp(K);
int len = mess_receive.size()/K;
for(int i = 0;i < len;i++)
{
temp.resize(K,0);
copy(mess_receive.begin()+i*K,mess_receive.begin()+(i+1)*K,temp.begin());//这个copy一定要多加一位
decoding(temp);
}
return get_result;
}
void coding(vector<int> mess_send)
{
string Hm;
string ori_code;
int temp = 0;
for(int i = 0;i < N;i++)
{
ori_code.push_back(mess_send[i]+'0');
}
for(int i = 0;i < K;i++)//表示列
{
temp = 0;
for(int j = 0;j < N;j++)//mess_send的第j列和生成矩阵第j行相乘后再相加
{
temp += mess_send[j]*G[j][i];
}
result.push_back(temp%2);
Hm.push_back(temp%2+'0');
}
//这里还要把编码的数据记录下来
//cout<<"ori_code="<<ori_code<<endl;
//cout<<"Hm="<<Hm<<endl;
mess2Hm[ori_code]=Hm;
Hm2mess[Hm]=ori_code;
}
void decoding(vector<int> code_get)
{
int temp = 0;
string sum = "";
string str_temp;
string res_temp;
for(int i = 0;i < K-N;i++)//7位接收码元mess_get与校验矩阵H的转置相乘得到伴随式s
{
temp = 0;
for(int j = 0;j < K;j++)
{
temp += code_get[j]*H[i][j];
}
s[i] = temp%2;//因为s[i]只取0到1之间
sum += s[i] + '0';
}
e[0]=(sum=="101");//101
e[1]=(sum=="111");//111
e[2]=(sum=="110");//110
e[3]=(sum=="011");//011
e[4]=(sum=="100");//100
e[5]=(sum=="010");//010
e[6]=(sum=="001");//001
for (int i = 0;i < K;i++)
{
if(e[i]!=0)
{
code_get[i] = (code_get[i]+e[i])%2;//这样得到的才是正确的码字
printf("\n一个码元的第%d位发生错误",i);
}
str_temp.push_back(code_get[i]+'0');
}
//这里要加入解码的方法,是将汉明码转换为源码
res_temp = Hm2mess[str_temp];
for(int i = 0;i < res_temp.length();i++)
{
get_result.push_back(res_temp[i]-'0');
}
}
};
class Intervein
{
int times;
public:
Intervein(int time)
{
times = time;
}
vector<int> addIntervein(vector<int>code_send)//其中code_send一定是4的倍数
{
vector<int> res;
int line = code_send.size()/times;//得到列数,其中N为行数
for(int i = 0;i < line;i++)
{
for(int j = 0;j < times;j++)
{
res.push_back(code_send[i+line*j]);
}
}
return res;
}
vector<int> removeIntervein(vector<int>code_receive)
{
vector<int> res;
int line = code_receive.size()/times;//得到列数,其中N为行数
for(int i = 0;i < times;i++)
{
for(int j = 0;j < line;j++)
{
res.push_back(code_receive[times*j+i]);
}
}
return res;
}
};
class Mistake {
public:
void add_mistake(vector<int>& transfer_code, int num, int start)
{
int len = transfer_code.size();
srand((int)time(0));
for (int i = 0;i < num;i++)
{
transfer_code[start+i] = transfer_code[start+i]==1?0:1;
}
}
};
int main()
{
File_io IO;
int valid_len = 0;
//读取文件,并且计算字母出现的频率部分
vector<double> fre(128,0);
IO.calculate(fre);
//信源编码,哈夫曼树处理部分
Haffman_Tree HT;
vector<string> HFcode;
HFcode = HT.Process(fre);
//按照编好的码元发送
vector<int> mess_send;
mess_send = IO.send_file(HT.HF_map_char2str);
cout<<"哈夫曼编码后的码元:"<<endl;
for(int i = 0;i < mess_send.size();i++)
{
cout<<mess_send[i];
if ((i+1)%N==0)
cout<<" ";
}
cout<<endl;
//信道编码,(7,4)汉明码部分
Hamming HM;
vector<int> code_send;
code_send = HM.Process_send(mess_send);
cout<<"74汉明编码后的码元:"<<endl;
for(int i = 0;i < code_send.size();i++)
{
cout<<code_send[i];
if ((i+1)%K==0)
cout<<" ";
}
//交错部分
Intervein IN(code_send.size()/7);
vector<int> inter_code;
inter_code = IN.addIntervein(code_send);
cout<<endl<<"交错后的码元:"<<endl;
for(int i = 0;i < inter_code.size();i++)
{
cout<<inter_code[i];
if ((i+1)%K==0)
cout<<" ";
}
//加入错误码元
Mistake MIS;
int mistake_num;//加入的错误码元的数目
int start;
bool flag = true;
char answer = 'n';
while(flag)
{
cout<<"\n请输入加入错码的个数:";
cin>>mistake_num;
cout<<"请输入加入错误码元的起始位置:";
cin>>start;
if(start<0||start>inter_code.size()||start+mistake_num>inter_code.size())
{
cout<<"当前共有"<<inter_code.size()<<"个码元";
cout<<"\n输入的错码或是错误码元的起始位置超出范围,请重新输入:"<<endl;
flag = true;
}
else if(mistake_num>inter_code.size()/7)
{
cout<<"当前加入误码错误超过纠正能力,是否重新输入?";
cin>>answer;
if(answer=='y'||answer=='Y')
{
flag = true;
}
else
{
flag = false;
}
}
else
flag = false;
}
MIS.add_mistake(inter_code,mistake_num,start);
//去交错部分
vector<int> normal_code;
normal_code = IN.removeIntervein(inter_code);
cout<<endl<<"去交错后的码元:"<<endl;
for(int i = 0;i < normal_code.size();i++)
{
cout<<normal_code[i];
if ((i+1)%K==0)
cout<<" ";
}
//汉明解码部分
vector<int> decode_Hm;
decode_Hm = HM.Process_decode(normal_code);
cout<<endl<<"汉明解码后的码元:"<<endl;
for(int i = 0;i < decode_Hm.size();i++)
{
cout<<decode_Hm[i];
if ((i+1)%N==0)
cout<<" ";
}
cout<<endl;
//哈夫曼解码部分
string ori_code;
ori_code = HT.decode(decode_Hm, HM.supply_zero);
cout<<"哈夫曼解码后的部分:"<<endl;
cout<<ori_code<<endl;
return 0;
}
cpp的结果演示:
java版的:
import java.io.BufferedReader;
import java.io.FileReader;
import java.security.KeyStore.Entry;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.Iterator;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.text.BadLocationException;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.JLabel;
import java.awt.Font;
import javax.swing.JTextArea;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JSeparator;
import javax.swing.JComboBox;
import java.awt.Color;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JScrollPane;
import javax.swing.JMenuBar;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import javax.swing.JDialog;
import javax.swing.JTable;
class HRNode//建立哈夫曼树的结构体
{
public HRNode(double x, char y)
{
frequency = x;
key = y;
lchild = null;
rchild = null;
parent = null;
}
public HRNode()
{
frequency = 0;
key = 0;
lchild = null;
rchild = null;
parent = null;
}
double frequency;
char key;
HRNode lchild;
HRNode rchild;
HRNode parent;
};
class String_fre {
int valid_len;
int len;
public void calculate(String s,double[] fre)
{
len = 0;
valid_len = 0;
for(int i = 0;i < s.length();i++)
{
int index = s.charAt(i);
if(index>=0&&index<128)
{
fre[index]++;
len++;
}
}
for(int i = 0;i < fre.length;i++)
{
if (fre[i]!=0)
{
fre[i] = fre[i]/len;
valid_len++;
}
}
}
public ArrayList<Integer> send_file(String s,HashMap<Character,String> HF_map_char2str)
{
ArrayList<Integer> mess_send = new ArrayList<Integer>();
Character uni_char = ' ';
for(int i = 0;i < s.length();i++)
{
uni_char = s.charAt(i);
len++;
if(HF_map_char2str.containsKey(uni_char))
{
String str_tmp = HF_map_char2str.get(uni_char);
for (int j = 0;j < str_tmp.length();j++)
{
mess_send.add(str_tmp.charAt(j)-'0');
}
}
}
return mess_send;
}
}
class Haffman_Tree
{
int valid_len;
int longest_str;
public HashMap<Character, String> HF_map_char2str = new HashMap<>();
public HashMap<String, Character> HF_map_str2char = new HashMap<>();
public String[] Process(double[] fre, int vl)
{
valid_len = vl;
String[] HFcode = new String[valid_len];
if(valid_len==1)//只有一位码的情况
{
for(int i = 0;i < fre.length;i++)
{
if(fre[i]!=0)
{
HFcode[0] = "1";
HF_map_str2char.put("1", (char)(i));
HF_map_char2str.put((char)(i), "1");
longest_str = 1;
return HFcode;
}
}
}
ArrayList<HRNode> Tree = new ArrayList<HRNode>();
CreateHaffmanTree(fre,Tree);
CreateHCode(Tree, HFcode);
return HFcode;
}
//Tree中有各个分立的结点,如何把它们连接成哈夫曼树
void CreateHaffmanTree(double[] fre,ArrayList<HRNode> Tree)
{
//初始化部分
for(int i = 0;i < fre.length;i++)
{
if(fre[i]!=0)
{
HRNode tmp = new HRNode(fre[i],(char)(i));
Tree.add(tmp);
}
}
int total_len = 2*valid_len - 1;
for(int i = valid_len;i < total_len;i++)
{
HRNode tmp = new HRNode(0,(char)(0));
Tree.add(tmp);
}
double min1, min2;
HRNode lnode;
HRNode rnode;
for(int i = valid_len;i < total_len;i++)
{
min1 = min2 = Integer.MAX_VALUE;
lnode = null;
rnode = null;
for (int k = 0;k <= i - 1;k++)
{
if (Tree.get(k).parent == null)
{
if (Tree.get(k).frequency < min1)
{
min2 = min1;
rnode = lnode;
min1 = Tree.get(k).frequency;
lnode = Tree.get(k);
}
else if (Tree.get(k).frequency<min2)
{
min2 = Tree.get(k).frequency;
rnode = Tree.get(k);
}
}
}
Tree.get(i).frequency = lnode.frequency + rnode.frequency;
Tree.get(i).lchild = lnode;
Tree.get(i).rchild = rnode;
lnode.parent = Tree.get(i);
rnode.parent = Tree.get(i);
}
}
//编译为哈夫曼码,这里需要注意不能有编码全为0的情况出现,因为后面要补零
void CreateHCode(ArrayList<HRNode> ht, String[] hcd)
{
longest_str = 0;
HRNode f;
HRNode c;
Character tmp;
for (int i = 0;i < valid_len; i++)//根据哈夫曼树求哈夫曼编码
{
hcd[i] = "";
f = ht.get(i).parent;
c = ht.get(i);
tmp = c.key;
while(f != null)//循环到达根节点
{
if (f.lchild == c)//当前节点是双亲节点的左孩子
{
hcd[i]+='1';
}
else//当前节点是双亲节点的右孩子
{
hcd[i]+='0';
}
c = f;
f = f.parent;
}
hcd[i] = new StringBuilder(hcd[i]).reverse().toString();//反转字符串
System.out.println("字母:"+tmp+"编码为:"+hcd[i]);
HF_map_str2char.put(hcd[i], tmp);
HF_map_char2str.put(tmp, hcd[i]);
int tmp_len = hcd[i].length();
longest_str = Math.max(longest_str, tmp_len);
}
}
String decode(ArrayList<Integer> Hm_code, int supply_zero)
{
int len = Hm_code.size();
Hm_code.subList(len-supply_zero, len).clear();
len = Hm_code.size();
String s = "";
String res = "";
List<Integer> temp = new ArrayList<Integer>(longest_str);
if(len==0)
{
return "";
}
int i = 0;
int sub_len = Math.min(len, longest_str);
while(i < len)
{
s = "";
temp.clear();
if(sub_len<=0)
break;
for(int j = i;j < i+sub_len;j++)
{
s += (char)(Hm_code.get(j)+'0');
}
if (!HF_map_str2char.containsKey(s))
{
sub_len--;
}
else
{
res += HF_map_str2char.get(s);
i += sub_len;
sub_len = Math.min(longest_str, len-i);
}
}
return res;
}
}
//由接收到的7位序列和校验矩阵相乘得到校验子S
//然后由纠正子e和S的关系求出e
//最后通过接收的码字和e求和得到就正好的序列
//74汉明码只能识别和纠正一位错误
class Hamming
{
static int N = 4;
static int K = 7;
private int [][]G={{1,0,0,0,1,0,1},//生成矩阵
{0,1,0,0,1,1,1},
{0,0,1,0,1,1,0},
{0,0,0,1,0,1,1}};
public int [][]H={{1,1,1,0,1,0,0},//一致校验矩阵
{0,1,1,1,0,1,0},
{1,1,0,1,0,0,1}};
int []s = new int[K-N];//伴随式
int []e = new int[K];//差错图案
ArrayList<Integer> result = new ArrayList<Integer>();
ArrayList<Integer> get_result = new ArrayList<Integer>();
public HashMap<String,String>mess2Hm = new HashMap<String, String>();
public HashMap<String, String>Hm2mess = new HashMap<String, String>();
public int supply_zero;
public ArrayList<Integer> Process_send(ArrayList<Integer>mess_send)
{
int len = mess_send.size();
supply_zero = (N-len%N)%N;
for(int i = 0;i < supply_zero;i++)
{
mess_send.add(0);
}
len = mess_send.size();
for(int i = 0;i < len/N;i++)
{
coding(mess_send.subList(i*N, (i+1)*N));
}
return result;
}
void coding(List<Integer> mess_send)
{
StringBuilder ori = new StringBuilder();
StringBuilder Hm = new StringBuilder();
int temp = 0;
for(int i = 0;i < N;i++)
{
ori.append((char)(mess_send.get(i)+'0'));
}
for(int i = 0;i < K;i++)//表示列
{
temp = 0;
for(int j = 0;j < N;j++)//mess_send的第j列和生成矩阵第j行相乘后再相加
{
temp += mess_send.get(j)*G[j][i];
}
result.add(temp%2);
Hm.append((char)(temp%2+'0'));
}
//这里还要把编码的数据记录下来
mess2Hm.put(ori.toString(), Hm.toString());
Hm2mess.put(Hm.toString(), ori.toString());
}
ArrayList<Integer> Process_decode(ArrayList<Integer> mess_receive)
{
int len = mess_receive.size()/K;
for(int i = 0;i < len;i++)
{
int tmp = decoding(mess_receive.subList(i*K, (i+1)*K));
if(tmp == -1)//这里对应译码错误即出错码元数过多无法纠正的情况
{
return null;
}
}
return get_result;
}
int decoding(List<Integer> code_get)
{
int temp = 0;
StringBuilder sum = new StringBuilder();
StringBuilder str_temp = new StringBuilder();
String res_temp;
for(int i = 0;i < K-N;i++)//7位接收码元mess_get与校验矩阵H的转置相乘得到伴随式s
{
temp = 0;
for(int j = 0;j < K;j++)
{
temp += code_get.get(j)*H[i][j];
}
s[i] = temp%2;//因为s[i]只取0到1之间
sum.append((char)(s[i]+'0'));
}
e[0]=(sum.toString().equals("101"))?1:0;//101
e[1]=(sum.toString().equals("111"))?1:0;//111
e[2]=(sum.toString().equals("110"))?1:0;//110
e[3]=(sum.toString().equals("011"))?1:0;//011
e[4]=(sum.toString().equals("100"))?1:0;//100
e[5]=(sum.toString().equals("010"))?1:0;//010
e[6]=(sum.toString().equals("001"))?1:0;//001
for (int i = 0;i < K;i++)
{
if(e[i]==1)
{
code_get.set(i, (code_get.get(i)+e[i])%2);
System.out.format("\n一个码元的第%d位发生错误",i);
}
str_temp.append((char)(code_get.get(i)+'0'));
}
//这里要加入解码的方法,是将汉明码转换为源码
res_temp = Hm2mess.get(str_temp.toString());
if(res_temp==null)
{
System.out.println("\n多于一位发生错误,无法纠正");
return -1;
}
for(int i = 0;i < res_temp.length();i++)
{
get_result.add(res_temp.charAt(i)-'0');
}
return 0;
}
}
class Intervein
{
int times;
public Intervein(int time)
{
times = time;
}
ArrayList<Integer> addIntervein(ArrayList<Integer>code_send)//其中code_send一定是4的倍数
{
ArrayList<Integer> res = new ArrayList<Integer>();
int line = code_send.size()/times;//得到列数,其中N为行数
for(int i = 0;i < line;i++)
{
for(int j = 0;j < times;j++)
{
res.add(code_send.get(i+line*j));
}
}
return res;
}
ArrayList<Integer> removeIntervein(ArrayList<Integer>code_receive)
{
ArrayList<Integer> res = new ArrayList<Integer>();
int line = code_receive.size()/times;//得到列数,其中N为行数
for(int i = 0;i < times;i++)
{
for(int j = 0;j < line;j++)
{
res.add(code_receive.get(times*j+i));
}
}
return res;
}
};
class Mistake {
public void add_mistake(ArrayList<Integer>transfer_code, int num, int start_point)
{
for(int i = 0;i < num;i++)
{
int tmp = start_point + i;
transfer_code.set(start_point+i,transfer_code.get(start_point+i)==1?0:1);
}
}
}
class pre_process {
public double[] fre;//计算得到的频率的结果
String[] HFcode;//哈夫曼编码,字母对应哈夫曼码
ArrayList<Integer>mess_send;//连接哈夫曼码组成的码元
ArrayList<Integer> code_send;//汉明编码得到的码元
ArrayList<Integer> inter_code;//交错并加入错码后得到的码元
ArrayList<Integer> normal_code;//去交错后的码元
ArrayList<Integer> decode_Hm;//汉明解码后得到的码元
public HashMap<Character, String> HF_map_char2str = new HashMap<>();
public HashMap<String, String>Hm2mess = new HashMap<String, String>();
String ori_code;//得到的最终结果
Intervein IN;
Hamming HM;
Haffman_Tree HT;
final int N = 4;
final int K = 7;
public String Haff_code(String s)
{
//读取字符串计算频率
String_fre sf = new String_fre();
fre = new double[128];
sf.calculate(s, fre);
//哈夫曼编码
HT = new Haffman_Tree();
HFcode = HT.Process(fre,sf.valid_len);
mess_send = sf.send_file(s,HT.HF_map_char2str);
HF_map_char2str = HT.HF_map_char2str;
return arrayList2string(mess_send,N);
}
public String[] calculate()//用于计算平均码长和编码效率
{
String[] res = new String[]{"平均码长K=","信源熵H(x)=","编码效率="};
Set<HashMap.Entry<Character,String>>sets = HF_map_char2str.entrySet();
Iterator<HashMap.Entry<Character,String>> it = sets.iterator();
double k = 0;
double H_x = 0;
double efficiency = 0;
while(it.hasNext())
{
HashMap.Entry<Character,String> e = it.next();
char c = e.getKey();
String s = e.getValue();
int index = c;
double tmp_fre = fre[index];
int tmp_len = s.length();
if(it.hasNext())
{
res[0]+=String.format("%.2f",tmp_fre)+'x'+String.valueOf(tmp_len)+'+';
}
else
{
res[0]+=String.format("%.2f",tmp_fre)+'x'+String.valueOf(tmp_len);
}
res[1]+='-'+String.format("%.2f",tmp_fre)+"xlog2("+String.format("%.2f",tmp_fre)+")";
k += tmp_fre*tmp_len;
H_x += -tmp_fre*Math.log(tmp_fre)/Math.log(2);//换底公式
}
res[0]+='='+String.format("%.2f",k);
res[1]+='='+String.format("%.2f",H_x);
if(k!=0)
{
efficiency = H_x/k;
}
res[2]+=String.format("%.2f",efficiency);
return res;
}
public String Haming_code()
{
HM = new Hamming();
code_send = HM.Process_send(mess_send);
Hm2mess = HM.Hm2mess;
return arrayList2string(code_send,K);
}
public String Interver_code()
{
IN = new Intervein(code_send.size()/7);
inter_code = IN.addIntervein(code_send);
return arrayList2string(inter_code,K);
}
public String Interver_decode(int start_point, int num)
{
Mistake MIS = new Mistake();
MIS.add_mistake(inter_code,num,start_point);
normal_code = IN.removeIntervein(inter_code);
return arrayList2string(normal_code,K);
}
public String Haming_decode()
{
decode_Hm = HM.Process_decode(normal_code);
if(decode_Hm==null)
{
return "";
}
return arrayList2string(decode_Hm,N);
}
public String Haff_decode()
{
ori_code = HT.decode(decode_Hm, HM.supply_zero);
return ori_code;
}
public String arrayList2string(ArrayList<Integer> a,int index)
{
String res="";
for(int i = 0;i < a.size();i++)
{
res += (char)('0'+a.get(i));
if((i+1)%index==0)
res += " ";
}
return res;
}
public int mistake_detect(int warn_index)
{
String []info = {"错误码元数超过编码码元数目","起始码元超出范围","错误码元索引超出范围","请输入起始码元数","请输入要编码的信息","加入错码过多无法正确译码"};
try {
warning1 dialog = new warning1(info[warn_index]);
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
return -1;
}
}
public class Test2 extends JFrame {
private JPanel contentPane;
private JTextArea textArea, textArea_1, textArea_1_1, textArea_1_1_1;
private JTextArea textArea_1_1_2, textArea_1_1_3, textArea_1_1_4;
JComboBox comboBox;
private JTextField textField;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Test2 frame = new Test2();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Test2() {
pre_process pp = new pre_process();
setTitle("信息论实验");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 624, 700);
contentPane = new JPanel();
contentPane.setToolTipText("0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10");
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JLabel lblNewLabel = new JLabel("输入要编码的内容:");
lblNewLabel.setFont(new Font("Lucida Grande", Font.PLAIN, 15));
lblNewLabel.setBounds(46, 38, 140, 19);
contentPane.add(lblNewLabel);
JScrollPane scrollPane = new JScrollPane();
scrollPane.setBounds(46, 69, 450, 101);
contentPane.add(scrollPane);
textArea = new JTextArea();
textArea.setLineWrap(true);
scrollPane.setViewportView(textArea);
JButton btnNewButton = new JButton("确认");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
textArea_1.setText("");
textArea_1_1.setText("");
textArea_1_1_1.setText("");
textArea_1_1_2.setText("");
textArea_1_1_3.setText("");
textArea_1_1_4.setText("");
int warn_index = 0;
String start_point = textField.getText();
String input = textArea.getText();
if(input.length()==0)
{
warn_index = 4;
pp.mistake_detect(warn_index);
return;
}
else if(start_point.length()==0)
{
warn_index = 3;
pp.mistake_detect(warn_index);
return;
}
int num = comboBox.getSelectedIndex();
int sp = Integer.parseInt(start_point);
String haff_code = pp.Haff_code(input);
textArea_1.setText(haff_code);
String haming_code = pp.Haming_code();//注意这里的长度是加入了空格之后的长度
int length_code = haming_code.length()/8*7;
textArea_1_1.setText(haming_code);
if(num>length_code)
{
warn_index = 0;
pp.mistake_detect(warn_index);
return;
}
else if(sp>length_code-1||sp<0)
{
warn_index = 1;
pp.mistake_detect(warn_index);
return;
}
else if(sp+num>length_code)//错误码元数超出范围
{
warn_index = 2;
pp.mistake_detect(warn_index);
return;
}
else if(num>length_code/7)
{
warn_index = 5;
pp.mistake_detect(warn_index);
return;
}
String interver_code = pp.Interver_code();
textArea_1_1_1.setText(interver_code);
String interver_decode = pp.Interver_decode(sp,num);
textArea_1_1_2.setText(interver_decode);
String haming_decode = pp.Haming_decode();
if(haming_decode=="")
{
warning1 dialog = new warning1("错码超过一位纠错失败");
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.setVisible(true);
return;
}
textArea_1_1_3.setText(haming_decode);
String haff_decode = pp.Haff_decode();
textArea_1_1_4.setText(haff_decode);
}
});
btnNewButton.setBounds(508, 69, 93, 29);
contentPane.add(btnNewButton);
JButton btnNewButton_1 = new JButton("清空");
btnNewButton_1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
textArea.setText("");
textArea_1.setText("");
textArea_1_1.setText("");
textArea_1_1_1.setText("");
textArea_1_1_2.setText("");
textArea_1_1_3.setText("");
textArea_1_1_4.setText("");
}
});
btnNewButton_1.setBounds(508, 110, 93, 29);
contentPane.add(btnNewButton_1);
JLabel lblNewLabel_1 = new JLabel("哈夫曼编码组成的码元:");
lblNewLabel_1.setFont(new Font("Lucida Grande", Font.PLAIN, 15));
lblNewLabel_1.setBounds(46, 232, 216, 19);
contentPane.add(lblNewLabel_1);
JLabel lblNewLabel_2 = new JLabel("引入错误码元数目:");
lblNewLabel_2.setFont(new Font("Lucida Grande", Font.PLAIN, 15));
lblNewLabel_2.setBounds(46, 184, 140, 19);
contentPane.add(lblNewLabel_2);
comboBox = new JComboBox();
comboBox.setModel(new DefaultComboBoxModel(new String[] {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"}));
comboBox.setMaximumRowCount(10);
comboBox.setBounds(179, 182, 93, 27);
contentPane.add(comboBox);
JLabel lblNewLabel_3 = new JLabel("七四汉明编码组成的码元:");
lblNewLabel_3.setFont(new Font("Lucida Grande", Font.PLAIN, 15));
lblNewLabel_3.setBounds(46, 291, 251, 19);
contentPane.add(lblNewLabel_3);
JSeparator separator = new JSeparator();
separator.setBackground(Color.BLACK);
separator.setForeground(Color.BLACK);
separator.setBounds(46, 215, 555, 12);
contentPane.add(separator);
JScrollPane scrollPane_1 = new JScrollPane();
scrollPane_1.setBounds(46, 252, 555, 37);
contentPane.add(scrollPane_1);
textArea_1 = new JTextArea();
scrollPane_1.setViewportView(textArea_1);
textArea_1.setEditable(false);
JScrollPane scrollPane_2 = new JScrollPane();
scrollPane_2.setBounds(46, 318, 555, 37);
contentPane.add(scrollPane_2);
textArea_1_1 = new JTextArea();
scrollPane_2.setViewportView(textArea_1_1);
textArea_1_1.setEditable(false);
JLabel lblNewLabel_4 = new JLabel("交错后的码元:");
lblNewLabel_4.setFont(new Font("Lucida Grande", Font.PLAIN, 15));
lblNewLabel_4.setBounds(46, 367, 140, 19);
contentPane.add(lblNewLabel_4);
JLabel lblNewLabel_5 = new JLabel("去交错后的码元:");
lblNewLabel_5.setFont(new Font("Lucida Grande", Font.PLAIN, 15));
lblNewLabel_5.setBounds(46, 428, 140, 19);
contentPane.add(lblNewLabel_5);
JLabel lblNewLabel_6 = new JLabel("汉明解码后的码元:");
lblNewLabel_6.setFont(new Font("Lucida Grande", Font.PLAIN, 15));
lblNewLabel_6.setBounds(46, 488, 140, 19);
contentPane.add(lblNewLabel_6);
JLabel lblNewLabel_7 = new JLabel("最终译码结果:");
lblNewLabel_7.setFont(new Font("Lucida Grande", Font.PLAIN, 15));
lblNewLabel_7.setBounds(46, 548, 140, 19);
contentPane.add(lblNewLabel_7);
JScrollPane scrollPane_3 = new JScrollPane();
scrollPane_3.setBounds(46, 387, 555, 37);
contentPane.add(scrollPane_3);
textArea_1_1_1 = new JTextArea();
scrollPane_3.setViewportView(textArea_1_1_1);
textArea_1_1_1.setEditable(false);
JScrollPane scrollPane_4 = new JScrollPane();
scrollPane_4.setBounds(46, 450, 555, 37);
contentPane.add(scrollPane_4);
textArea_1_1_2 = new JTextArea();
scrollPane_4.setViewportView(textArea_1_1_2);
textArea_1_1_2.setEditable(false);
JScrollPane scrollPane_5 = new JScrollPane();
scrollPane_5.setBounds(46, 511, 555, 37);
contentPane.add(scrollPane_5);
textArea_1_1_3 = new JTextArea();
scrollPane_5.setViewportView(textArea_1_1_3);
textArea_1_1_3.setEditable(false);
JScrollPane scrollPane_6 = new JScrollPane();
scrollPane_6.setBounds(46, 572, 555, 37);
contentPane.add(scrollPane_6);
textArea_1_1_4 = new JTextArea();
scrollPane_6.setViewportView(textArea_1_1_4);
textArea_1_1_4.setEditable(false);
JMenuBar menuBar = new JMenuBar();
menuBar.setBounds(0, 0, 53, 22);
contentPane.add(menuBar);
JMenu mnNewMenu = new JMenu("菜单");
menuBar.add(mnNewMenu);
JMenuItem mntmNewMenuItem_2 = new JMenuItem("查看编码效率");
mntmNewMenuItem_2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String []res;
res = pp.calculate();
for(int i = 0;i < res.length;i++)
{
try {
infopage frame = new infopage(res);
frame.setVisible(true);
} catch (Exception ee) {
ee.printStackTrace();
}
}
}
});
mnNewMenu.add(mntmNewMenuItem_2);
JMenuItem mntmNewMenuItem_1 = new JMenuItem("查看汉明编码");
mntmNewMenuItem_1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
Set<String>sets = pp.Hm2mess.keySet();
String [][] res = new String[sets.size()][3];
int i = 0;
for(String c:sets)
{
res[i][0] = String.valueOf(i);
res[i][1] = c;
res[i][2] = pp.Hm2mess.get(c);
i++;
}
new Hamming_ui(res);
} catch (Exception ee) {
ee.printStackTrace();
}
}
});
mnNewMenu.add(mntmNewMenuItem_1);
JMenuItem mntmNewMenuItem = new JMenuItem("查看哈夫曼编码");
mntmNewMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
Set<Character>sets = pp.HF_map_char2str.keySet();
String [][] res = new String[sets.size()][3];
int i = 0;
for(char c:sets)
{
res[i][0] = String.valueOf(i);
res[i][1] = String.valueOf(c);
res[i][2] = pp.HF_map_char2str.get(c);
i++;
}
new Haff(res);
} catch (Exception ee) {
ee.printStackTrace();
}
}
});
mnNewMenu.add(mntmNewMenuItem);
JLabel lblNewLabel_2_1 = new JLabel("差错的起始位置:");
lblNewLabel_2_1.setFont(new Font("Lucida Grande", Font.PLAIN, 15));
lblNewLabel_2_1.setBounds(283, 186, 140, 19);
contentPane.add(lblNewLabel_2_1);
textField = new JTextField();
textField.setFont(new Font("Lucida Grande", Font.PLAIN, 15));
textField.setBounds(402, 182, 93, 26);
textField.setText("0");
contentPane.add(textField);
textField.setColumns(10);
}
}
class warning1 extends JDialog {
private final JPanel contentPanel = new JPanel();
public warning1(String ss) {
setTitle("提示");
setBounds(100, 100, 405, 191);
getContentPane().setLayout(new BorderLayout());
contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
getContentPane().add(contentPanel, BorderLayout.CENTER);
contentPanel.setLayout(null);
{
JLabel lblNewLabel = new JLabel(ss);
lblNewLabel.setFont(new Font("Lucida Grande", Font.PLAIN, 15));
lblNewLabel.setBounds(58, 29, 277, 29);
contentPanel.add(lblNewLabel);
}
{
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
getContentPane().add(buttonPane, BorderLayout.SOUTH);
{
JButton okButton = new JButton("OK");
okButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
dispose();
}
});
okButton.setActionCommand("OK");
buttonPane.add(okButton);
getRootPane().setDefaultButton(okButton);
}
}
}
}
class Haff{
public Haff(String[][] res) {
JFrame f = new JFrame("哈夫曼编码");
f.setSize(400, 300);
f.setLocation(200, 200);
f.setLayout(new BorderLayout());
// 表格上的title
String[] columnNames = new String[] { "序号","字母","哈夫曼编码"};
JTable t = new JTable(res, columnNames);
t.setFont(new Font("Lucida Grande", Font.PLAIN, 15));
f.add(t, BorderLayout.CENTER);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JScrollPane sp = new JScrollPane(t);
// 设置列宽度
t.getColumnModel().getColumn(0).setPreferredWidth(10);
f.add(sp, BorderLayout.CENTER);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
class Hamming_ui{
public Hamming_ui(String[][] res) {
JFrame f = new JFrame("汉明编码");
f.setSize(400, 300);
f.setLocation(200, 200);
f.setLayout(new BorderLayout());
// 表格上的title
String[] columnNames = new String[] { "序号","汉明编码","哈夫曼编码"};
JTable t = new JTable(res, columnNames);
t.setFont(new Font("Lucida Grande", Font.PLAIN, 15));
f.add(t, BorderLayout.CENTER);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JScrollPane sp = new JScrollPane(t);
// 设置列宽度
t.getColumnModel().getColumn(0).setPreferredWidth(10);
f.add(sp, BorderLayout.CENTER);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
class infopage extends JFrame {
private JPanel contentPane;
public infopage(String[] res) {
setTitle("查看编码效率");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 334);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JLabel lblNewLabel = new JLabel("查看编码效率:");
lblNewLabel.setFont(new Font("Lucida Grande", Font.PLAIN, 15));
lblNewLabel.setBounds(23, 23, 156, 31);
contentPane.add(lblNewLabel);
JScrollPane scrollPane = new JScrollPane();
scrollPane.setBounds(23, 53, 370, 191);
contentPane.add(scrollPane);
JTextPane textPane = new JTextPane();
textPane.setEditable(false);
Style style = textPane.getStyledDocument().addStyle(null, null);
StyleConstants.setFontFamily(style, "楷体");// 为style样式设置字体属性
StyleConstants.setFontSize(style, 15);// 为style样式设置字体大小
try {
textPane.getStyledDocument().insertString(textPane.getStyledDocument().getLength(),res[0]+"\n\n",style);
textPane.getStyledDocument().insertString(textPane.getStyledDocument().getLength(),res[1]+"\n\n",style);
textPane.getStyledDocument().insertString(textPane.getStyledDocument().getLength(),res[2]+"\n\n",style);
} catch (BadLocationException e) {
e.printStackTrace();
}
scrollPane.setViewportView(textPane);
}
}
第一次写Java图形化界面很多地方比较冗余,有错误欢迎指出。
本文地址:https://blog.csdn.net/qq_43650421/article/details/112226592
上一篇: python基础之循环语句