• Java实现WUST 1002: 哈夫曼树


    [问题描述]
    根据给定的若干权值可以构造出一颗哈夫曼树。构造的哈夫曼树可能不唯一,但是按照下面的选取原则所构造出来的哈夫曼树应该是唯一的。
    (1)每次选取优先级最低的两个结点,优先级最低的作为左子树,优先级高的作为右子树;
    (2)结点优先级大小的比较首先比较它们的权值,权值大的优先级高,权值小的优先级低,权值相等的按照位置关系来比较,位置在前面的优先级低,位置在后面的优先级高。
    (3)增加的新结点位置依次往后。
    根据你所构造的哈夫曼树来设计每个权值的哈夫曼编码(左子树0右子树1),并计算该哈夫曼树的WPL值。

    [输入]
    包含多组数据
    每组数据包含2行,第一行输入权值个数n(0<n<20),第2行为顺序输入的n个权值,均为整数(小于100),

    [输出]
    对于每组数据,输出n+1行,前面n行为每个权值所对应的赫夫曼编码(按照输入顺序给出),第n+1行用来输出你所构造的哈夫曼树的WPL值。

    [样例输入]
    5
    11 4 2 5 7
    6
    2 3 4 7 8 9

    [样例输出]
    11
    011
    010
    00
    10
    64

    1110
    1111
    110
    00
    01
    10
    80

    PS:

    他这个是特别版的哈夫曼树,相同的权值时,位置靠左面的会小,
    所以你查询的时候,先靠左查询,其他不懂得在评论

    哈夫曼树相关的几个名词

    路径:在一棵树中,一个结点到另一个结点之间的通路,称为路径。图 1 中,从根结点到结点 a 之间的通路就是一条路径。

    路径长度:在一条路径中,每经过一个结点,路径长度都要加 1 。例如在一棵树中,规定根结点所在层数为1层,那么从根结点到第 i 层结点的路径长度为 i - 1 。图 1 中从根结点到结点 c 的路径长度为 3。

    结点的权:给每一个结点赋予一个新的数值,被称为这个结点的权。例如,图 1 中结点 a 的权为 7,结点 b 的权为 5。

    结点的带权路径长度:指的是从根结点到该结点之间的路径长度与该结点的权的乘积。例如,图 1 中结点 b 的带权路径长度为 2 * 5 = 10 。

    树的带权路径长度为树中所有叶子结点的带权路径长度之和。通常记作 “WPL” 。例如图 1 中所示的这颗树的带权路径长度为:

    WPL = 7 * 1 + 5 * 2 + 2 * 3 + 4 * 3

    在这里插入图片描述
    图1 哈夫曼树

    什么是哈夫曼树

    当用 n 个结点(都做叶子结点且都有各自的权值)试图构建一棵树时,如果构建的这棵树的带权路径长度最小,称这棵树为“最优二叉树”,有时也叫“赫夫曼树”或者“哈夫曼树”。

    在构建哈弗曼树时,要使树的带权路径长度最小,只需要遵循一个原则,那就是:权重越大的结点离树根越近。在图 1 中,因为结点 a 的权值最大,所以理应直接作为根结点的孩子结点。

    构建哈夫曼树的过程

    对于给定的有各自权值的 n 个结点,构建哈夫曼树有一个行之有效的办法:
    在 n 个权值中选出两个最小的权值,对应的两个结点组成一个新的二叉树,且新二叉树的根结点的权值为左右孩子权值的和;
    在原有的 n 个权值中删除那两个最小的权值,同时将新的权值加入到 n–2 个权值的行列中,以此类推;
    重复 1 和 2 ,直到所以的结点构建成了一棵二叉树为止,这棵树就是哈夫曼树。

    在这里插入图片描述
    图 2 哈夫曼树的构建过程

    图 2 中,(A)给定了四个结点a,b,c,d,权值分别为7,5,2,4;第一步如(B)所示,找出现有权值中最小的两个,2 和 4 ,相应的结点 c 和 d 构建一个新的二叉树,树根的权值为 2 + 4 = 6,同时将原有权值中的 2 和 4 删掉,将新的权值 6 加入;进入(C),重复之前的步骤。直到(D)中,所有的结点构建成了一个全新的二叉树,这就是哈夫曼树。

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Scanner;
    
    public class Demo10哈弗们数 {
    	public static class TreeNode implements Comparable<TreeNode>{
    		int val;
    		boolean bool;
    		TreeNode left;
    		TreeNode right;
    			
    		TreeNode(int x) {
    			val = x;
    		}
    
    		@Override
    		public int compareTo(TreeNode o) {
    			
    			// TODO 自动生成的方法存根
    			
    			if(this.val>o.val){
    				return 1;
    			}
    			else if(this.val<o.val){
    				return -1;
    			}
    			else {
    				if(this.bool){
    					return 1;
    				}
    				else if(o.bool){
    					return -1;
    				}
    				
    			}
    			return 0;
    		}
    	}
    
    	static TreeNode tree = new TreeNode(0);
    	static ArrayList<TreeNode> list = new ArrayList<TreeNode>();
    
    	static ArrayList<String> list1 = new ArrayList<String>();
    
    	public static void main(String[] args) {
    
    		Scanner sc = new Scanner(System.in);
    		while(sc.hasNext()){
    			tree = new TreeNode(0);
    			list = new ArrayList<TreeNode>();
    			list1 = new ArrayList<String>();
    			int sum = 0;
    		
    		int n = sc.nextInt();
    		int[] num = new int[n];
    		for (int i = 0; i < n; i++) {
    
    			num[i] = sc.nextInt();
    			TreeNode tree11 = new TreeNode(num[i]);
    			list.add(tree11);
    		}
    		Collections.sort(list);
    		// Arrays.sort(num);
    		madetree();
    		for (int i = 0; i < num.length; i++) {
    			findtree(tree, num[i], "");
    			System.out.println( list1.get(i));
    			sum+=num[i]*list1.get(i).length();
    
    		}
    		System.out.println(sum);
    	//	System.out.println(list1.size());
    		}
    	}
    
    	public static void findtree(TreeNode node, int n, String s) {
    		if (node.val == n && !node.bool) {
    			list1.add(s);
    			return;
    		}
    		if (node.left != null)
    			findtree(node.left, n, s + "0");
    		if (node.right != null)
    			findtree(node.right, n, s + "1");
    
    		return;
    
    	}
    
    	public static void madetree() {
    		boolean flag = true;
    		while (list.size() != 1) {
    			Collections.sort(list);
    //			int a = list.get(0);
    //			int b = list.get(1);
    		
    //			if (a > b) {
    //				int temp = a;
    //				a = b;
    //				b = temp;
    //			}
    			TreeNode treeleft = list.get(0);
    			TreeNode treeright = list.get(1);
    			list.remove(0);
    			list.remove(0);
    			TreeNode treemid = new TreeNode(treeleft.val+treeright.val);
    			treemid.left = treeleft;
    			treemid.right = treeright;
    			treemid.bool = true;
    			tree = treemid;
    //			if (flag) {
    //				flag = false;
    //
    //				TreeNode treeleft1 = null;
    //				TreeNode treeright1 = null;
    //
    //				if (treemid.val > tree.val) {
    //					treeleft1 = tree;
    //					treeright1 = treemid;
    //
    //				} else {
    //					treeleft1 = treemid;
    //					treeright1 = tree;
    //				}
    //				TreeNode treemid1 = new TreeNode(tree.val + treemid.val);
    //				treemid1.left = treeleft1;
    //				treemid1.right = treeright1;
    //				treemid1.bool = true;
    //				if (tree.val != 0) {
    //					tree = treemid1;
    //				} else {
    //					tree = treemid;
    //				}
    //			}
    
    			list.add(tree);
    		}
    	}
    
    }
    
    
  • 相关阅读:
    就是要让你彻底学会 @Bean 注解
    Redis持久化深入理解
    设计模式内容聚合
    多线程高并发内容聚合
    实战分析:事务的隔离级别和传播属性
    28个Java开发常用规范技巧总结
    面试官:你了解过Redis对象底层实现吗
    几个高逼格 Linux 命令!
    Spring核心(IoC) 入门解读
    Python Beautiful Soup模块的安装
  • 原文地址:https://www.cnblogs.com/a1439775520/p/12946727.html
Copyright © 2020-2023  润新知