`
tianchenqitan
  • 浏览: 8104 次
  • 性别: Icon_minigender_1
  • 来自: 重庆
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

java实现三种信源编码

阅读更多
信息通过信道传输到信宿的过程即为通信。
信源编码的目的是要减少冗余,提高编码效率。

一、香农码
编码步骤:
   1)将个信源符号按概率递减的方式进行排列;
   2)按香农不等式计算出每个信源符号的码长;
   3)为了编成惟一可译码,计算第i个信源符号的累加概率
   4)将累加概率    用二进制数表示;
   5)取   对应二进制数的小数点后位构成该信源符号的二进制码字。
public class Shannon {

	/**Shannon算法
	 * 
	 * 1.符号按概率递减的方式排列
	 * 2.计算每一个符号的码长l
	 * 3.计算累加概率
	 * 4.将累加概率用二进制表示
	 * 5.取小数点后l位为信源符号的二进制码字
	 * 
	 */
	double cumu = 0;//累加概率
	Data data;//符号集
	double prob;//概率
	int codelength;//码长
//	List list = new ArrayList();
	
	/*累加概率的二进制转换*/
	public static String getBinary(double cumu,int length){
		
		String  codeword = "";
		for(int i = 0; i < length; i++){
			cumu *= 2;//小数转化二进制乘以2
			if(cumu >= 1){
				cumu -= 1;
				codeword += 1;//大于1取1
			}else{
				codeword += 0;//小于1取0
			}
		}
		return codeword;
	}
	/*实现香农编码*/
	public List isShannon(List list){
		for(int i = 0;i < list.size();i++){
			data = (Data)list.get(i);//得到每一个符号
			prob = data.getProb();//取出符号概率
			codelength =(int)Math.ceil(Math.log(1/prob)/Math.log((double)2));//计算码长
		    data.setCodeLength(codelength);//添加码长
		    data.setCodeword(getBinary(cumu, codelength));//添加码字
		    list.set(i, data);//改变符号列表信息
		    cumu += prob;//累加概率
		}
		return list;
	}
}

二、费诺码
编码步骤:
    1)信源符号以概率递减的次序排列起来;
    2)将排列好的信源符号按概率值划分成两大组,使每组    的概率之和接近于相等,并对每组各赋予一个二元码符号“0”和“1”;
    3)将每一大组的信源符号再分成两组,使划分后的两个组的概率之和接近于相等,再分别赋予一个二元码符号;
    4)依次下去,直至每个小组只剩一个信源符号为止;
    5)信源符号所对应的码字即为费诺码。
public class Fano {

	/**Fano算法
	 * 
	 * 1.信源符号按概率递减的方式排列
	 * 2.将排列好的符号分成两组,使每组的概率之和接近相等并对赋于0和1
	 * 3.将每一大组再分组,同2
	 * 4.依次下去,直到只剩一个信源符号
	 * 5.信源符号所对应的码字即为费诺码
	 */
	Data data;//符号集
	double prob;//概率
	int codelength;//码长
	/*费诺码的实现*/
	public List isFano(List list){
		double[] arr = new double[list.size()];
		for(int i = 0;i < list.size();i++){
			data = (Data)list.get(i);//得到每一个符号
			prob = data.getProb();//取出符号概率
			arr[i] = prob;//将概率存放在一个数组中
		}
		String[] codeword = getGroup(arr,0,arr.length-1);//符号编码
		for(int i = 0; i < codeword.length; i++){
			data = (Data)list.get(i);//得到每一个符号
			data.setCodeword(codeword[i]);//加上码字
			data.setCodeLength(codeword[i].length());//加上码长
			list.set(i, data);//加上符号
		}
		
		
		return list;//返回改变的列表
	}
	/*用分组法求出符号的编码*/
	public static  String[] getGroup(double[] a,int i,int j){

		String[] p = new String[a.length]; //返回的字符编码
		for(int t = 0; t < a.length; t++){
			p[t] = "";//初始化
		}
		int flag = 0;//分组间隔点
		if(i < j){
			//采用递归法,将数组分为两半
			double sum = 10;//比较中间量
			for(int k = i; k <= j; k++){
				//取累和间距最小量
				if(Math.abs(sumGroup(a,i,k)-sumGroup(a, k+1, j)) < sum){
					//以flag为中间点,分别累加左边和右边,然后比较
					sum=Math.abs(sumGroup(a,i,k)-sumGroup(a, k+1, j));
					flag = k;//取出中间点
				}
			}
			String[] p1 = getGroup(a, i, flag);//递归第一组(左边)
			String[] p2 = getGroup(a, flag+1, j);//递归第二组(右边)
			for(int m = i; m <= flag; m++){
				p[m] = "0" + p1[m];//第一组赋值0
			}
				for(int m = flag+1; m <= j; m++){
					p[m] = "1" + p2[m];//第二组赋值1
				}
		}
		
		return p;//得到分组后的码字
	}
	/*求数组第i位到第j位的和*/
	public static double sumGroup(double[] a, int i, int j ){
		double total = 0;
		for(int k = i; k <= j; k++){
			total = total + a[k];
		}
		return total;
	}
}

三、霍夫曼码
编码步骤:
    1)将q个信源符号按概率递减的方式排列起来;
    2)用“0”、“1”码符号分别表示概率最小的两个信源符号,并将这两个概率最小的信源符号合并成一个新的符号,从而得到只包含q-1个符号的新信源,称之为S信源的S1缩减信源;
    3)将缩减信源中的符号仍按概率大小以递减次序排列,再将其最后两个概率最小的符号合并成一个符号,并分别用“0”、“1”码符号表示,这样又形成了由q-2个符号构成的缩减信源S2;
    4)依次继续下去,直到缩减信源只剩下两个符号为止,将这最后两个符号分别用“0”、“1”码符号表示;
    5)从最后一级缩减信源开始,向前返回,沿信源缩减方向的反方向取出所编的码元,得出各信源符号所对应的码符号序列,即为对应信源符号的码字。
public class Huffman {

	/**Huffman算法
	 * 
	 * 1.信源符号按概率递减的方式排列
	 * 2.用0、1分别表示最小的两个符号,将这两个符号合并成一个新的符号,从而得到一个新信源
	 * 3.将新信源重排列,再取最后两位最小的分别用0、1表示,并合并,得到一个缩减信源
	 * 4.重复步骤3,直到只有两符号为止,将这两个符号分别用0、1表示
	 * 5.从最后一级缩减信源开始向前返回,反向列出所编码元,得到各信源符号的码字
	 */
	/*霍夫曼的实现*/
	public void isHuffman(List l){
		List list = new ArrayList();//新建一个表
		list.addAll(l);//复制
		for(int i = list.size()-1; i >=0 ; i--){
			double d = ((Data)list.get(i)).getProb();//得到概率
			TreeNode root = new TreeNode(d);//将概率作为根结点
			list.remove(i);//移除最后一项
			list.add(i, root);//将结点添加到最后一项
		}
		createTree(list);//创建树
		TreeNode root = (TreeNode)list.get(0);//得到最终树的根结点
		list.clear();//清空列表
		printTree(root,list);//根据树的叶子得到码字、码长
		for(int i = 0; i < list.size(); i ++){
			Data data = new Data();
			data.setSymbol(((Data)l.get(i)).getSymbol());//取出符号
			data.setProb(((Data)l.get(i)).getProb());//取出概率
			data.setCodeLength(((Data)list.get(i)).getCodeLength());//取出码长
			data.setCodeword(((Data)list.get(i)).getCodeword());//取出码字
			l.set(i, data);//将新得的Data对象加到列表
		}
	}
	//创建树
	public static void createTree(List list){
		double d1 = ((TreeNode)list.get(list.size()-1)).data;//取出倒数第一个
		double d2 = ((TreeNode)list.get(list.size()-2)).data;//取出倒数第二个
		double cumu = d1 + d2;//最小两个相加
		TreeNode root = new TreeNode(cumu);//将和作为树根结点
		root.left = (TreeNode)list.get(list.size()-1);//将倒数第一个作为左孩子
		root.right = (TreeNode)list.get(list.size()-2);//将倒数第二个作为右孩子
		list.remove(list.size()-1);//移除最后二个
		list.remove(list.size()-1);
		sortList(list, root);//将根结点加到列表,并排序
		if(list.size() > 1){
			createTree(list);//只要list大于1时就递归创建树
		}else{
			
		}
	}
	//将树转为码字
	public static void printTree(TreeNode root,List list){
 		Data data = new Data();
		if(root.left != null){
 			root.left.codeword = root.codeword + "0";//左孩子加0
 			printTree(root.left,list);//遍历左孩子
 		}
 		if(root.right != null){
 			root.right.codeword = root.codeword  + "1";//右孩子加1
 			printTree(root.right,list);//遍历右孩子
 		}
 		//如果是树的叶子,刚将其作为对应的码字
 		if(root.left == null && root.right == null){
 			data.setProb(root.data);//概率
 			data.setCodeLength(root.codeword.length());//码长
 			data.setCodeword(root.codeword);//码字
 			Util.sortList(list, data);//将Data对象加入列表
 		}
	}
	/*将根结点顺序插入list*/
	public static void sortList(List list,TreeNode root){
		int i = 0;
		if(list.size() == 0){
			list.add(root);//list为空,直接插入
		}else{
			while(i < list.size()){
				if(((TreeNode)list.get(i)).data <= root.data){
					list.add(i,root);//将根结点按顺序插入
					break;
				}else{
					i++;
				}
			}
			if(i == list.size()){
				list.add(i,root);//走到最后为最小,直接插入
			}
		}
	}
}
/*创建一棵树*/
class TreeNode {

    public double data;//结点数据
    public String codeword = "";//码字
    public TreeNode left;//左孩子
    public TreeNode right;//右孩子
    
    public TreeNode(double data){
    	this.data = data;
    }
}


0
0
分享到:
评论
1 楼 Harry.Z.Wang 2013-04-27  
问下你那个Data改导入哪个包哦

相关推荐

Global site tag (gtag.js) - Google Analytics