因为之前写过一个多元哈夫曼编码问题,但是随后发现代码有问题,现附上我重新更正的代码
主要还是懒要不然就在这里写问题描述了
- 代码实现需要三个类
Node类
package cn.sg.huffman;
class Node {
int pow;// 结点石子的权值
Node(int pow) {
this.pow = pow;
}
}
TreeNode类
package cn.sg.huffman;
public class TreeNode {
Node node;//要存储在树结点中的数据
TreeNode[] childType;//子树数组
public TreeNode() {
}
TreeNode(Node node, int k) {
this.node = node;
childType = new TreeNode[k];
}
}
主函数
package cn.sg.huffman;
import java.util.ArrayList;
import java.util.Scanner;
//45 13 12 16 9 5 22
public class HuffMan {
//树节点存放于数组中用于排序,不被修改
private static ArrayList<TreeNode> treeNodeList = new ArrayList<>();
//工作数组,该数组内数据会被删除修改
private static ArrayList<TreeNode> array = new ArrayList<>();
public static void main(String[] args) {
int n, k;//n-->多少堆,k-->最大每次移动多少堆
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
k = sc.nextInt();
//输入每堆的石子个数
for (int i = 0; i < n; i++) {
// 将每堆石子的权重生成树节点
treeNodeList.add(new TreeNode(new Node(sc.nextInt()), k));
}
// 获取最大搬运费用
array = (ArrayList<TreeNode>) treeNodeList.clone();
sort('<');
int maxFee = getFee(2, '<');
System.out.println(maxFee);
//获取最小搬运费用
array = (ArrayList<TreeNode>) treeNodeList.clone();
sort('>');
int minFee = getFee(k, '>');
System.out.println(minFee);
}
/**
* 获取费用
*
* @param k 孩子节点的个数
* @param ch 排序的变量
* @return 返回搬运的费用
*/
private static int getFee(int k, char ch) {
TreeNode tNode = null;
while (array.size() > 1) { // 当链表中的结点数大于1个的时候,将结点不断的加入到哈夫曼树中
TreeNode[] node = new TreeNode[k];
for (int i = 0; i < k; i++) {
node[i] = array.get(i);
}
// 生成新的节点
tNode = product(k, node);
// 生成新的节点之后,清空当前数组存放的它的孩子节点
if (k > 0) {
array.subList(0, k).clear();
}
array.add(0, tNode);
sort(ch);// 再将新的链表进行排序
}
// 通过获取非叶子节点的权重,计算出费用
TreeNode root = tNode;
assert root != null;
return Fee(root, k);
}
/**
* @param root 数根节点
* @param k 孩子节点的个数
* @return 费用
*/
private static int Fee(TreeNode root, int k) {
// 防止根节点反复被加,所以提前赋值到费用
int fee = root.node.pow;
// 一条路走到黑,深度搜索
for (int i = 0; i < k; i++) {
// 根节点的位置不能动
TreeNode temp = root.childType[i];
while (temp.childType[i] != null) {
fee += temp.node.pow;
temp = temp.childType[i];
}
}
return fee;
}
/**
* 对节点数组进行排序,采用插入排序
* 因为最大费用和最小费用采取的排序方式不同
* 为了防止代码冗余,引入变量,控制排序符号
*
* @param ch 运算符号
*/
private static void sort(char ch) {
for (int i = 1; i < array.size(); i++) {
int min;
int j;
TreeNode tNode = array.get(i);
for (j = i; j > 0; j--) {
TreeNode lastNode = array.get(j - 1);
if (ch == '>' && tNode.node.pow > lastNode.node.pow)
break;// 找到第一个比他小的数据时。退出循环
else if (ch == '<' && tNode.node.pow < lastNode.node.pow)
break;// 找到第一个比他大的数据时。退出循环
}
min = j;
if (min != i) {// 如果,min值发生变化,即前面有比pow大的数
array.remove(tNode);
array.add(min, tNode);
}
}
}
/**
* 生成新的节点
* 为了实现代码的复用,将传递的参数个数,设置为了动态的
*
* @param k 孩子节点个数
* @param childNode 孩子节点
* @return 返回生成的节点
*/
private static TreeNode product(int k, TreeNode... childNode) {
int pow = 0;
for (TreeNode treeNode : childNode) {
pow += treeNode.node.pow;
}
TreeNode tNode = new TreeNode(new Node(pow), k);// 生成的结点
//数组拷贝,将节点的孩子节点拷贝到树的关系中
System.arraycopy(childNode, 0, tNode.childType, 0, childNode.length);
return tNode;
}
}