哈夫曼树--顺序结构(建立、编码、解码)
来源:互联网 发布:mac os 自带php环境 编辑:程序博客网 时间:2024/06/08 09:11
结果:引子:
这里的哈夫曼树的建立方法和上一篇不一样,是把数据放在数组上面的,而不是链表上面。因此,采用这种方法建立的哈夫曼树对节点的操作上比链式的哈夫曼树简单很多。对于空间问题,如果有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树、编码、解码)
- IPB帧编码顺序(解码顺序)与显示顺序
- IPB帧编码顺序(解码顺序)与显示顺序
- IPB帧编码顺序(解码顺序)与显示顺序
- IPB帧编码顺序(解码顺序)与显示顺序
- IPB帧编码顺序(解码顺序)与显示顺序
- IPB帧编码顺序(解码顺序)与显示顺序
- IPB帧编码顺序(解码顺序)与显示顺序
- IPB帧编码顺序(解码顺序)与显示顺序
- 编码、解码、分支结构
- HuffmanTree建立、输出、编码及解码
- IPB帧 编码顺序 解码顺序 显示顺序
- 哈夫曼树生成,编码,解码
- 哈夫曼树,编码,解码
- IPB 帧的编码熟悉 解码顺序 与显示顺序
- AVPacket,是压缩数据的结构体(解码前或编码后的结构体)。
- 哈夫曼树数据机构的建立及哈夫曼编码与解码的C++实现
- YII的自定义路由规则类的使用(初级)
- 揭秘12306技术改造(三):传统框架云化迁移到内存数据平台
- libevent编程之bufferevent使用
- Linux(C/C++)下的文件操作open、fopen与freopen http://blog.csdn.net/a656343072/article/details/40539889
- 哈夫曼树--链式结构(建立huffman树、编码、解码)
- 哈夫曼树--顺序结构(建立、编码、解码)
- 无向图--邻接矩阵、连接矩阵、深度遍历、广度遍历、生成树
- 拓扑排序
- Routos设置ntp
- WarShall算法--图的传递闭包(进一步演变成flayd算法)
- 【转】 数学建模十大经典算法漫谈
- 字符串转换成日期,不多说,两句话 ,一句话
- hibernate查询和jdbc查询
- ROS(7):Lubuntu i386环境搭建ROS环境