org.nervousync.huffman.HuffmanTree Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of utils-jdk11 Show documentation
Show all versions of utils-jdk11 Show documentation
Java utility collections, development by Nervousync Studio (NSYC)
/*
* Licensed to the Nervousync Studio (NSYC) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.nervousync.huffman;
import org.nervousync.commons.Globals;
import org.nervousync.utils.StringUtils;
import java.util.Hashtable;
import java.util.Optional;
/**
* Huffman Tree
* 霍夫曼树
*.0
* @author Steven Wee [email protected]
* @version $Revision: 1.0.0 $ $Date: Nov 3, 2017 16:39:41 $
*/
public final class HuffmanTree {
/**
* Node counter
* 节点计数器
*/
private int nodeCount = 0;
/**
* Root node instance
* 根节点实例对象
*/
private Node rootNode = null;
/**
* Code mapping table
* 编码映射表
*/
private Hashtable codeMapping = new Hashtable<>();
/**
* Constructor method for HuffmanTree
* HuffmanTree构造方法
*/
public HuffmanTree() {
}
/**
* Private constructor method for HuffmanTree
* HuffmanTree私有构造方法
*
* @param codeMapping Code mapping table
* 编码映射表
*/
private HuffmanTree(Hashtable codeMapping) {
this.codeMapping = codeMapping;
}
/**
* Insert huffman node into current huffman tree
* 插入一个霍夫曼节点到当前的霍夫曼树
*
* @param huffmanNode Huffman node who will insert into current huffman tree
* 即将插入当前霍夫曼树的霍夫曼节点
*/
public void insertNode(final Node huffmanNode) {
if (this.rootNode == null) {
this.rootNode = huffmanNode;
} else {
Node currentNode = this.rootNode;
Node previousNode = null;
while (currentNode.getFrequency() < huffmanNode.getFrequency()) {
previousNode = currentNode;
if (currentNode.getNextNode() == null) {
currentNode = null;
break;
} else {
currentNode = currentNode.getNextNode();
}
}
if (previousNode == null) {
huffmanNode.setNextNode(this.rootNode);
this.rootNode = huffmanNode;
} else if (currentNode == null) {
previousNode.setNextNode(huffmanNode);
} else {
previousNode.setNextNode(huffmanNode);
huffmanNode.setNextNode(currentNode);
}
}
this.nodeCount++;
}
/**
* Build code mapping table
* 构建编码映射表
*/
public void build() {
while (this.nodeCount > 1) {
this.mergeNode();
}
this.buildCodeMapping(this.rootNode, Globals.DEFAULT_VALUE_STRING);
}
/**
* Static method for encode given content string to huffman tree result string using given code mapping
* 静态方法,使用给定的编码映射表将给定的内容字符串编码为霍夫曼结果字符串
*
* @param codeMapping Code mapping table
* 编码映射表
* @param content Content string
* 内容字符串
*
* @return Generated huffman result string or zero length string if content string is empty
* 生成的霍夫曼树编码字符串,当内容字符串为空字符串时返回长度为0的空字符串
*/
public static String encodeString(final Hashtable codeMapping, String content) {
HuffmanTree huffmanTree = new HuffmanTree(codeMapping);
return Optional.ofNullable(huffmanTree.encodeString(content))
.map(Result::getHuffmanValue)
.orElse(Globals.DEFAULT_VALUE_STRING);
}
/**
* Encode given content string to huffman tree result instance using current code mapping
* 使用当前的编码映射表将给定的内容字符串编码为霍夫曼结果实例对象
*
* @param content Content string
* 内容字符串
*
* @return Generated huffman result instance or null if content string is empty
* 生成的霍夫曼结果实例对象,当内容字符串为空字符串时返回null
*/
public Result encodeString(final String content) {
if (StringUtils.isEmpty(content)) {
return null;
}
String string = content;
StringBuilder stringBuilder = new StringBuilder();
while (string.length() > 0) {
String keyword = String.valueOf(string.charAt(0));
stringBuilder.append(this.codeMapping.get(keyword));
string = string.substring(1);
}
return new Result(this.codeMapping, stringBuilder.toString());
}
/**
* Build code mapping table
* 构建编码映射表
*
* @param currentNode Current huffman node
* 当前霍夫曼节点
* @param currentCode Code symbol
* 编码符号
*/
private void buildCodeMapping(final Node currentNode, final String currentCode) {
if (currentNode.getKeyword() != null) {
this.codeMapping.put(currentNode.getKeyword(), currentCode);
} else {
this.buildCodeMapping(currentNode.getLeftNode(), currentCode + "0");
this.buildCodeMapping(currentNode.getRightNode(), currentCode + "1");
}
}
/**
* Merge huffman node which two frequency was lowest
* 合并两个权重最低的节点,并将合并后的节点添加到霍夫曼树中
*/
private void mergeNode() {
Node leftNode = this.pollNode();
Node rightNode = this.pollNode();
if (leftNode != null && rightNode != null) {
Node mergeNode = new Node(leftNode.getFrequency() + rightNode.getFrequency());
mergeNode.setLeftNode(leftNode);
mergeNode.setRightNode(rightNode);
this.insertNode(mergeNode);
}
}
/**
* Retrieves and removes the head of this queue
* 取出并移除当前队列的第一个节点
*
* @return Retrieved node or returns null if this queue is empty.
* 取出的节点,如果队列为空则返回null。
*/
private Node pollNode() {
if (this.rootNode == null) {
return null;
}
Node removeNode = this.rootNode;
this.rootNode = this.rootNode.getNextNode();
this.nodeCount--;
return removeNode;
}
/**
* Huffman Node
* 霍夫曼节点
*
* @author Steven Wee [email protected]
* @version $Revision: 1.0.0 $ $Date: Nov 3, 2017 16:26:45 $
*/
public static final class Node {
/**
* Keyword
* 关键词
*/
private String keyword;
/**
* Frequency
* 权重
*
*/
private int frequency;
/**
* Left Node
* 左节点
*/
private Node leftNode;
/**
* Right Node
* 右节点
*/
private Node rightNode;
/**
* Next Node, using for chain table
* 下一节点,用于链表
*/
private Node nextNode;
/**
* Constructor method for HuffmanNode
* HuffmanNode构造方法
*
* @param frequency Frequency
* 权重
*/
public Node(final int frequency) {
this.frequency = frequency;
}
/**
* Constructor method for HuffmanNode
* HuffmanNode构造方法
*
* @param keyword Keyword
* 关键词
* @param frequency Frequency
* 权重
*/
public Node(final String keyword, final int frequency) {
this.keyword = keyword;
this.frequency = frequency;
}
/**
* Getter method for keyword
* 关键词的Getter方法
*
* @return Keyword
* 关键词
*/
public String getKeyword() {
return keyword;
}
/**
* Setter method for keyword
* 关键词的Setter方法
*
* @param keyword Keyword
* 关键词
*/
public void setKeyword(final String keyword) {
this.keyword = keyword;
}
/**
* Getter method for frequency
* 权重的Getter方法
*
* @return Frequency
* 权重
*/
public int getFrequency() {
return frequency;
}
/**
* Setter method for frequency
* 权重的Setter方法
*
* @param frequency Frequency
* 权重
*/
public void setFrequency(final int frequency) {
this.frequency = frequency;
}
/**
* Getter method for left node
* 左节点的Getter方法
*
* @return Left Node
* 左节点
*/
public Node getLeftNode() {
return leftNode;
}
/**
* Setter method for left node
* 左节点的Setter方法
*
* @param leftNode Left Node
* 左节点
*/
public void setLeftNode(final Node leftNode) {
this.leftNode = leftNode;
}
/**
* Getter method for right node
* 右节点的Getter方法
*
* @return Right Node
* 右节点
*/
public Node getRightNode() {
return rightNode;
}
/**
* Setter method for right node
* 右节点的Setter方法
*
* @param rightNode Right Node
* 右节点
*/
public void setRightNode(final Node rightNode) {
this.rightNode = rightNode;
}
/**
* Getter method for next node
* 下一节点的Getter方法
*
* @return Next Node, using for chain table
* 下一节点,用于链表
*/
public Node getNextNode() {
return nextNode;
}
/**
* Setter method for next node
* 下一节点的Setter方法
*
* @param nextNode Next Node, using for chain table
* 下一节点,用于链表
*/
public void setNextNode(final Node nextNode) {
this.nextNode = nextNode;
}
}
/**
* Huffman Result
* 霍夫曼编码结果
*
* @author Steven Wee [email protected]
* @version $Revision: 1.0.0 $ $Date: Nov 6, 2017 14:13:35 $
*/
public static final class Result {
/**
* Code mapping table
* 编码映射表
*/
private final Hashtable codeMapping = new Hashtable<>();
/**
* Result string
* 编码字符串
*/
private final String huffmanValue;
/**
* Constructor method for HuffmanResult
* HuffmanResult构造方法
*
*
* @param codeMapping Code mapping table
* 编码映射表
* @param huffmanValue Result string
* 编码字符串
*/
public Result(final Hashtable codeMapping, final String huffmanValue) {
if (codeMapping != null) {
this.codeMapping.putAll(codeMapping);
}
this.huffmanValue = huffmanValue;
}
/**
* Convert coding map to JSON string
* 转换编码映射表为JSON字符串
*
* @return Converted JSON string of current code mapping
* 当前编码映射表转换后的JSON字符串
*/
public String codeMappingToString() {
return StringUtils.objectToString(this.codeMapping, StringUtils.StringType.JSON, Boolean.TRUE);
}
/**
* Getter method for code mapping
* 编码映射表的Getter方法
*
* @return Code mapping table
* 编码映射表
*/
public Hashtable getCodeMapping() {
return this.codeMapping;
}
/**
* Getter method for result string
* 编码字符串的Getter方法
*
* @return Result string
* 编码字符串
*/
public String getHuffmanValue() {
return huffmanValue;
}
}
}