Java数据结构之《构造哈夫曼树》题目

一、前言:

  这是怀化学院的:Java数据结构中的一道难度中等(偏难理解)的一道编程题(此方法为博主自己研究,问题基本解决,若有bug欢迎下方评论提出意见,我会第一时间改进代码,谢谢!) 后面其他编程题只要我写完,并成功实现,会陆续更新,记得三连哈哈! 所有答案供参考,不是标准答案,是博主自己研究的写法。(这一个题书上也有现成类似的代码,重要的是理解它的算法原理!)

二、题目要求如下:

(第 16 题)构造哈夫曼树(难度系数85+%5)(自己添加的%5哈哈)

构造哈夫曼树
题目描述:
根据给定的叶结点字符及其对应的权值创建哈夫曼树。
输入:
第一行为叶子结点的数目n(1<=n<=100)。第二行为一个字符串,包含n个字符,每个字符对应一个叶子结点,第三行为每个叶子结点的概率(即权值),要求根据各叶结点构造哈夫曼树。构造哈夫曼树的原则是先两个最小的,构造一个父结点,其中最小的结点为左孩子,次小的为右孩子,如果两个最小的叶结点相等,则取排在前一个位置的为左孩子。
输出:
哈夫曼树的权值,左孩子,右孩子及其对应的父亲,相邻数据之间用空格隔开;
输入样例:
5
abcde
15 25 15 20 25
输出样例:
15 0 0 6
25 0 0 7
15 0 0 6
20 0 0 7
25 0 0 8
30 1 3 8
45 4 2 9
55 5 6 9
100 7 8 0

补充:题目意思一定要深度揣摩一下,没有提示就得自己根据它题目给的输入输出来推一下原理了,不然就是盲目下手出错很多!

三、代码实现: (代码的做题原理全部在代码注释中,若还有疑问也可以翻书关于哈夫曼树的构造原理的内容) 

补充:应该当你放到考试系统里检测代码是否正确时,请把所有的代码注释去掉哦!不过是自己的编译器应该没问题的

(1)我把所有的实现细节全部放到一个类里了:(解释已经尽力详细了...)

package com.fs.demo;
import java.util.Scanner;
public class HuffmanTree {
    //构建结点静态内部类
    private static class Node{
        private int data;  //当前哈夫曼树的总值
        //题目中要求输出的左孩子和右孩子结点都是用数字表示,父结点也是一样
        private int lchild;  //左孩子
        private int rchild;  //右孩子
        private int parent;  //父结点
        //默认初始化;没有左孩子、右孩子以及父结点默认数值为0
        public Node(){
            this.data=0;
            this.lchild=0;
            this.rchild=0;
            this.parent=0;
        }
    }

    public static void main(String[] args) {
        Scanner sc =new Scanner(System.in);
        int n=sc.nextInt();  //代表最先给的叶子结点的个数
        String node01 = sc.next();   //代表n个叶子结点组成的字符串
        // 之所以把存储每个结点的数组长度设为(2*n-1),
        // 是因为在非空二叉树中,拥有2个度的结点=叶子结点个数-1,则整个构造成功的哈夫曼树的结点总数=n*n-1=2*n-1
        Node [] node = new Node[2*n-1];
        for(int i=0;i<n;i++){
            node[i]=new Node();  //在结点数组中依次给前面输入的叶子结点创建空间
            node[i].data=sc.nextInt();  //给前面几个叶子结点依次赋值
        }
        //控制最大只能到2*n-1个结点也就是到(2*n-1)-1下标
        for(int j=0;j<n-1;j++){
            int low01=-1;  //所有可以相加的叶子结点或者叶子结点+生成的父结点中两个权值最小的那个的下标
            int low02=-1;  //所有可以相加的叶子结点或者叶子结点+生成的父结点中两个权值次小的那个的下标
            //注意最后只有0~(n-1)-1的下标中还没选完的最小和次小的下标作为根节点,因为最后生成的根结点是最终的哈夫曼树的最大总权值
            for(int k=0;k<n+j;k++){  //随着新建的"父"结点加入,下标会逐渐超过原来的(n-1)
                //寻找最小下标的最终值(这里不好用文字解释,需要自己拿笔对着题目试运行去理解了)
                //也就是依次判断所有的结点的权值相比较,最小的那个
                //条件首先是要找没有父结点的结点(也就是根结点),再其次判断:该位置的结点的值:是否比假定最小下标的值还小,如果是把当前位置的下标就赋给设定的最小下标,再继续循环,直到找完所有符合条件的
                if(node[k].parent==0 && (low01==-1 || (node[k].data<node[low01].data) )){  //"||"如果前面满足后面不会执行
                    low02=low01;
                    low01=k;  //每找到一次就覆盖一次下标值
                }else if(node[k].parent==0&&(low02==-1|| (node[k].data<node[low02].data) )){  //寻找次小下标的最终值(这里不好用文字解释,需要自己拿笔对着题目试运行去理解了)
                    low02=k;
                }
            }
            //当我们找到第一组符合权值最小和次小的结点时:如下操作
            //每次相加成功的某2个叶子结点或者某1个叶子结点+生成的父结点生成的结点存放在结点数组的新位置
            node[n+j]=new Node();  //且位置下标最大不超出(2*n-1)-1下标
            node[n+j].data=node[low01].data+node[low02].data;  //新生成的这个结点的权值为:没加过的结点中的最小小标和次小下标结点的值的和
            node[n+j].lchild=low01+1;  //可以去想最开始的叶子结点是不是最小下标和次小下标都是默认-1,加1就代表0:表示没有孩子结点
            node[n+j].rchild=low02+1;  //而后面的左孩子和右孩子表示都是之前在原来最初的结点数组(也就是输入后的)所处的位置,例如(low01=0)+1=1 表示:a是它的左孩子.(low02=1)+1=2,表示:b是它的右孩子
            //例如30是第6个结点(5+0+1)
            node[low01].parent=node[low02].parent=n+j+1;
        }
        for(int i=0;i<2*n-1;i++){
            //依次输出当前状态两个结点构造的哈夫曼树的总权值、左子树、右子树与父结点的
            System.out.print(node[i].data+" "+node[i].lchild+" "+node[i].rchild+" "+node[i].parent);
            System.out.println();
        }
    }

}

 四、代码测试运行结果:

<1>题目的输入样例测试情况:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/213867.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【蓝桥杯】翻硬币

翻硬币 思路&#xff1a; 其实有点贪心的意思&#xff0c;依次比较&#xff0c;不同就1&#xff0c;然后修改自己的字符串和下一个的字符串&#xff0c;再匹配。 #include<iostream> #include<string> using namespace std;string now,res;int main(void) {cin&g…

MQ - 消息系统

消息系统 1、消息系统的演变 在大型系统中&#xff0c;会需要和很多子系统做交互&#xff0c;也需要消息传递&#xff0c;在诸如此类系统中&#xff0c;你会找到源系统&#xff08;消息发送方&#xff09;和 目的系统&#xff08;消息接收方&#xff09;。为了在这样的消息系…

java高校实验室排课学生考勤系统springboot+vue

随着各高校办学规模的迅速扩大,学科专业的不断拓宽,传统的实验教学和实验室管理方法已经不能适应学校管理的要求,特别是化学实验室的管理,化学实验室仪器药品繁杂多样,管理任务繁重,目前主要使用人工记录方法管理,使用不便,效率低下,而且容易疏漏.时间一长将产生大量的文件和数…

【面试经典150 | 二分查找】搜索二维矩阵

文章目录 写在前面Tag题目来源题目解读解题思路方法一&#xff1a;二分查找 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于本题涉及到的数据结构等…

c# OpenCV 读取、显示和写入图像(二)

读取、显示和写入图像是图像处理和计算机视觉的基础。即使在裁剪、调整大小、旋转或应用不同的滤镜来处理图像时&#xff0c;您也需要先读取图像。因此&#xff0c;掌握这些基本操作非常重要。 imread()读取图像imshow()在窗口中显示图像imwrite()将图像保存到文件目录里 我们…

细说CountDownLatch

CountDownLatch 概念 CountDownLatch可以使一个获多个线程等待其他线程各自执行完毕后再执行。 CountDownLatch 定义了一个计数器&#xff0c;和一个阻塞队列&#xff0c; 当计数器的值递减为0之前&#xff0c;阻塞队列里面的线程处于挂起状态&#xff0c;当计数器递减到0时…

力扣226:翻转二叉树

力扣226&#xff1a;翻转二叉树 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4,7,2,9,6,3,1] 示例 2&#xff1a; 输入&#xff1a;root [2,1,3]…

分享一个国内可用的免费AI-GPT网站

背景 ChatGPT作为一种基于人工智能技术的自然语言处理工具&#xff0c;近期的热度直接沸腾&#x1f30b;。 我们也忍不住做了一个基于ChatGPT的网站&#xff0c;可以免登陆&#xff01;&#xff01;国内可直接对话AI&#xff0c;也有各种提供工作效率的工具供大家使用。 可以这…

判断二叉树是否为完全二叉树

具体思路&#xff1a; 将二叉树层序遍历&#xff08;节点&#xff09;插进队列中&#xff0c;遇到空时就break&#xff08;退出循环&#xff09;&#xff0c;再重新遍历一遍&#xff0c;若空的后面又再次出现数据&#xff0c;则返回false&#xff08;不是完全二叉树&#xff0…

SpringSecurity和JWT实现认证和授权

SpringSecurity和JWT实现认证和授权 框架介绍SpringSecurityJWT组成实例JWT实现认证和授权的原理 Hutool 使用表整合SpringSecurity及JWT在pom.xml中添加依赖添加JWT token的工具类添加RbacAdminService&#xff1a;添加自定义mapper创建SpringSecurity配置类添加ProjectSecuri…

软件工程精品课程教学网站的设计与实现

系统功能需求分析 本系统要求采用Browser/Server模式设计开发&#xff0c;可以作为一般高等院校的网络学堂&#xff1b;可以为教师的辅助教学或者网络教学提供一个完善的教学网站&#xff1b;学生可以利用本教学网站来完成一些课程的学习任务。 2.2.1 功能划分 《软件工程》教学…

分享一个简单的基于C语言嵌入式GUI界面切换代码

目录 前言 一、数据类型 二、页面调度 三、页面显示 四、视频展示 前言 最近在用LVGL写一个简单的UI界面&#xff0c;需要进行几个页面的切换&#xff0c;所以就自己写了一个简单页面切换代码&#xff0c;方便进行页面切换&#xff0c;同时使UI代码结构更加清晰。这个结构…

如何使用注解实现接口的幂等性校验

如何使用注解实现接口的幂等性校验 背景什么是幂等性为什么要实现幂等性校验如何实现接口的幂等性校验1. 数据库唯一主键2. 数据库乐观锁3. 防重 Token 令牌4. redis 如何将这几种方式都组装到一起结语 背景 最近在小组同学卷的受不了的情况下&#xff0c;我决定换一个方向卷去…

人工智能轨道交通行业周刊-第67期(2023.11.27-12.3)

本期关键词&#xff1a;列车巡检机器人、城轨智慧管控、制动梁、断路器、AICC大会、Qwen-72B 1 整理涉及公众号名单 1.1 行业类 RT轨道交通人民铁道世界轨道交通资讯网铁路信号技术交流北京铁路轨道交通网上榜铁路视点ITS World轨道交通联盟VSTR铁路与城市轨道交通RailMetro…

使用Prometheus监控Padavan路由器

Prometheus监控Padavan路由器 1、背景 近期在Synology&#xff08;群辉&#xff09;中安装一套Prometheus监控程序&#xff0c;目前已经监控Synology&#xff0c;然后家中有有路由器&#xff08;Padavan&#xff09;型号&#xff0c;也准备使用PrometheusGrafan进行监控。 ‍…

Java基本数据类型详解

✨个人主页&#xff1a;全栈程序猿的CSDN博客 &#x1f4a8;系列专栏&#xff1a;Java从入门到精通 ✌座右铭&#xff1a;编码如诗&#xff0c;Bug似流星&#xff0c;持续追求优雅的代码&#xff0c;解决问题如同星辰般自如 Java是一种强类型语言&#xff0c;数据类型在程序中起…

如何成为一名高效的前端开发者(10X开发者)

如今&#xff0c;每个人都想成为我们所说的“10倍开发者”。然而&#xff0c;这个术语经常被误解和高估。 本质上&#xff0c;一个高效或者10倍开发者&#xff0c;在我看来&#xff0c;是指那些能够充分利用所有可用工具的人&#xff0c;通过让这些工具处理冗余和重复的任务&am…

Java线程池的使用和最佳实践

第1章&#xff1a;引言 处理并发问题时&#xff0c;如果每次都新建线程&#xff0c;那系统的压力得有多大&#xff1f;这时候&#xff0c;线程池就像一个英雄一样出现了&#xff0c;它帮我们有效地管理线程&#xff0c;提高资源利用率&#xff0c;降低开销。那么&#xff0c;为…

iOS 自动签名打包,并用脚本上传appstore

背景&#xff1a; 1&#xff09;测试环境给测试&#xff0c;产品&#xff0c;或者其他业务人员打测试包时&#xff0c;经常存在需要添加设备&#xff0c;不得不重新生成描述文件&#xff0c;手动去更新打包机描述文件配置 2&#xff09;证书&#xff0c;描述文件过期造成打包失…

Lag-Llama:基于 LlaMa 的单变量时序预测基础模型

文章构建了一个通用单变量概率时间预测模型 Lag-Llama&#xff0c;在来自Monash Time Series库中的大量时序数据上进行了训练&#xff0c;并表现出良好的零样本预测能力。在介绍Lag-Llama之前&#xff0c;这里简单说明什么是概率时间预测模型。概率预测问题是指基于历史窗口内的…
最新文章