哈夫曼树--顺序结构(建立、编码、解码)
2015-09-15 13:46
483 查看
引子: 这里的哈夫曼树的建立方法和上一篇不一样,是把数据放在数组上面的,而不是链表上面。因此,采用这种方法建立的哈夫曼树对节点的操作上比链式的哈夫曼树简单很多。对于空间问题,如果有m个item,那么需要建立2*m长度的数组,具体解释请看下面注释! package tree; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import tree.ListHuffManTree.Node; public class ListHuffManTreeTest { public static void main(String[] args) { ListHuffManTree t = new ListHuffManTree(26); t.add(4, "A"); t.add(6, "E"); t.add(1, "C"); t.add(8, "D"); t.add(3, "U"); t.add(5, "P"); t.add(7, "B"); t.add(93, "F"); t.add(45, "G"); t.add(34, "H"); t.add(12, "I"); t.add(34, "K"); t.add(22,"O"); t.add(23, "L"); //创建哈夫曼树 t.createHuffmanTree(); t.print(); //建立哈夫曼编码表 t.buildCodeTable(); t.printCode(); //编码字符串hellogoogle List<String> codeList = t.encode("HELLOGOOLE"); //解码 List<String> decodeList = t.decode(codeList); System.out.println(); System.out.print("解码: "); for(String s: decodeList){ System.out.print(s); } System.out.println(); } } class ListHuffManTree{ private Node[] nodes = null; //实际的叶子数 private int size; //最多的叶子数 private int maxSize; //保存编码和源码,其中key为源码 Map<String,List<String>> codeMap = null; public ListHuffManTree(int maxSize){ this.maxSize = maxSize; this.size = 0; //叶子有maxSize个,则非叶子有maxSize-1个,因为第一个没用,所以有2*maxSize个 nodes = new Node[2*maxSize]; codeMap = new HashMap<>(); } public boolean isFull(){ return size == maxSize; } public void add(int weight, String item){ size++; nodes[size] = new Node(weight, item); } /** * 选择权重最小的两个节点 * @return */ private List<Integer> select(){ List<Integer> list = new ArrayList<Integer>(); int index1 = -1; int index2 = -1; int temp = Integer.MAX_VALUE; int i = 1; for(; i <= size; i++){ if(nodes[i].parent == 0 && temp > nodes[i].weight){ temp = nodes[i].weight; index1 = i; } } if(temp != Integer.MAX_VALUE){ nodes[index1].parent = -1; list.add(index1); } temp = Integer.MAX_VALUE; int k = 1; for(; k <= size; k++){ if(nodes[k].parent == 0 && temp > nodes[k].weight){ temp = nodes[k].weight; index2 = k; } } if(temp != Integer.MAX_VALUE){ nodes[index2].parent = -1; list.add(index2); } return list; } /** * 建立哈夫曼树 */ public void createHuffmanTree(){ int tempSize = this.size; for(int i = 0; i < tempSize; i++){ //选择权值最小的两个节点 List<Integer> list = select(); if(list.size() == 2){ int index1 = list.get(0); int index2 = list.get(1); int w1 = nodes[index1].weight; int w2 = nodes[index2].weight; //合并节点的权重 add(w1+w2, null); nodes[size].lchild = index1; nodes[size].rchild = index2; //改变父节点的index nodes[index1].parent = size; nodes[index2].parent = size; } } } /** * 打印节点的详细信息 */ public void print(){ Node node = null; for(int i = 1; i <= this.size; i++){ node = nodes[i]; System.out.println("item:"+node.item+" ;weight:"+node.weight+" ;parent:"+node.parent+" ;lchild:"+node.lchild+" ;rchild:"+node.rchild); } } /** * 建立编码表 * 思路:从每一个叶子节点依次到根节点,是父节点的左孩子,则为0,否则为1 */ public void buildCodeTable(){ for(int i = 1; i <= size; i++){ Node node = nodes[i]; //是否为叶子节点 if(node.lchild == 0 || node.rchild == 0){ //用来存储01信息,顺序和实际的相反 List<String> list = new ArrayList<>(); String tempKey = nodes[i].item; int tempInt = i; while(node.parent > 0){ int p = node.parent; if(tempInt == nodes[p].lchild){ list.add("0"); }else{ list.add("1"); } node = nodes[p]; tempInt = p; } codeMap.put(tempKey, list); } } } /** * 打印二进制编码 */ public void printCode(){ Set<Entry<String,List<String>>> set = codeMap.entrySet(); Iterator<Entry<String,List<String>>> iter = set.iterator(); while(iter.hasNext()){ Entry<String,List<String>> entry = iter.next(); System.out.print(entry.getKey()+": "); List<String> list = entry.getValue(); for(int i = list.size()-1; i >= 0; i--){ System.out.print(list.get(i)); } System.out.println(); } } public List<String> encode(String target){ System.out.print(target+" 的编码: "); List<String> li = new ArrayList<String>(); int len = target.length(); for(int i = 0; i < len; i++){ String temp = String.valueOf(target.charAt(i)); List<String> list = codeMap.get(temp); for(int k = list.size()-1; k >= 0; k--){ System.out.print(list.get(k)); li.add(list.get(k)); } } return li; } /** * 解码 * @param codeList 二进制编码 * @return 解码结果 */ public List<String> decode(List<String> codeList){ List<String> list = new ArrayList<String>(); int tempSize = size; for(String s : codeList){ if("0".equals(s)){ int lch = nodes[tempSize].lchild; String itemString = nodes[lch].item; if(itemString != null){ list.add(itemString); tempSize = size; continue; } tempSize = lch; }else if("1".equals(s)){ int rch = nodes[tempSize].rchild; String itemString = nodes[rch].item; if(itemString != null){ list.add(itemString); tempSize = size; continue; } tempSize = rch; } } return list; } /** * 节点 * @author LiangYH * */ class Node{ //parent index int parent; //left child index int lchild; //right child index int rchild; //rate int weight; // String item; public Node(){ this.item = null; this.lchild = 0; this.rchild = 0; this.parent = 0; this.weight = -1; } public Node(int weight, String item){ this.weight = weight; this.item = item; this.parent = 0; this.lchild = 0; this.rchild = 0; } } }结果:
思考:上面选择权值最小的两个节点的方法不是特别理想,如何改进?
相关文章推荐
- 哈夫曼树--链式结构(建立huffman树、编码、解码)
- Jquery动态操作checkbox
- oracle exp 命令导大数据
- 任意2n个整数,从其中选出n个整数,使得选出的n个整数和同剩下的n个整数之和的差最小
- ios开发系列之NSDate,NSDateFormatter,NSDateComponents和NSCalendar
- 压缩文件(zip)--适用于目录下既有目录又有文件的情况
- stripes framework(框架)入门教程(附案例分析)
- spring整合mybatis(入门级简单教程5)--使用mybatis的API
- spring整合mybatis(入门级简单教程4)--扫描mapper类
- spring整合mybatis(入门级简单教程3)--获取sqlSession对象
- spring整合mybatis(入门级简单教程2)
- spring整合mybatis(入门级简单教程1)--在spring中配置c3p0,并成功测试
- IDEA加密文件Base64转换String传输以及报文摘要MD5防止恶意篡改
- 使用struts2框架来实现CRUD(create、read、update、delete)
- MVC、JSP实现mysql的增删改查功能的封装和简陋的界面交互
- java坦克游戏
- 贪吃蛇游戏(java)
- 考研成绩查询系统(jsp、mysql、java)
- 用java实现优先级别队列
- 用Java实现单向链表