多元哈夫曼编码-树-搬运石子问题

因为之前写过一个多元哈夫曼编码问题,但是随后发现代码有问题,现附上我重新更正的代码

对问题的描述,请点击

主要还是懒要不然就在这里写问题描述了

  • 代码实现需要三个类
    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;

    }
}

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值