算法设计第七周(应用哈夫曼算法解决文件归并问题)

news2024/11/19 15:39:08

一、【实验目的】

(1)进一步理解贪心法的设计思想

(2)掌握哈夫曼算法的具体应用

(3)比较不同的文件归并策略,探讨最优算法。

二、【实验内容】

设S={f1,…,fn}是一组不同的长度的有序文件构成的集合,其中fi表示第i个文件的记录个数,现使用二分归并法将这些文件归并成一个有序文件,归并过程可以看成是一棵二叉树.参考教材P102例4.7,请采用两种方法进行二分归并,其中一种为哈夫曼算法。

提示:其中n个文件可用n个数组模拟,文件的内容为数组中已排好序的整数;可以用教材例4.7中定义的S集合中6个文件的长度作为数组长度进行测试。注意,要编写两个数组进行顺序归并的程序。

三、实验源代码

四、实验结果

五、实验分析与总结

实验分析:

要求完成以下两种归并

按照哈夫曼算法的思路,先取最小的两个点进行归并,得到一个父结点。再放回去再选择两个小的。

⚠️错误写法

  • 这里用的优先队列实现了插入一个元素后排序且可以有队列的特性。
  • j用于叶子结点的创建,i用于父结点的创建。
  • returnElement函数取最小的两个元素,再加起来放回去
#include <bits/stdc++.h>
using namespace std;

int n = 6;
vector<int> s = {21, 10, 32, 41, 18, 70};
vector<int> a = s;
vector<int> temp(10);
priority_queue<int, vector<int>, greater<int>> pq; //升序队列模板

struct treeNode{
	int weight;
	int parent;
	int leftchild, rightchild;
}tree[20];

void returnElement(int& element1, int& element2)
{
	if(!pq.empty())
	{
		element1 = pq.top();
		pq.pop();
		element2 = pq.top();
		pq.pop();
		int sum = element1 + element2;
		pq.push(sum);
	}
}

void CreateHuffmanTree(){ //二分归并法最优
	//输入
	for(auto e : s)
		pq.push(e);
		
	int j=1, element1, element2;
	//初始化-1
	for(int i=1; i<=2*n-1; i++)
	{
		tree[i].parent = -1,  tree[i].leftchild = -1; 
		tree[i].rightchild = -1;
	}
	for(int i=n; i<=2*n-1; i++)
	{
		//左右孩子结点
		returnElement(element1, element2);
		tree[j].weight = element1;
		j++;
		tree[j].weight = element2;
		j++;
		//父节点
		tree[i].weight = element1 + element2;
		tree[i].leftchild = j-2;
		tree[i].rightchild = j-1;
	}
	
}
//由于中文乱码,所以输出英文
void printTree()
{
    for (int i = 1; i <=2*n-1; i++)
    {
    	cout << setw(7) << "i:" << i ;
        cout << setw(7) << "node:" << tree[i].weight << "\t";
        cout << setw(7) << "parent:" << tree[tree[i].parent].weight << "\t";
        cout << setw(7) << "leftchild:" << tree[tree[i].leftchild].weight << "\t";
        cout << setw(7) << "rightchild:" << tree[tree[i].rightchild].weight << endl;
    }
}

int main()
{
	CreateHuffmanTree();
	printTree();
	return 0;
}

行结果:

  • 叶子结点和父结点交叉存放
  • -1的值未打印出来
  • 有一些数据被覆盖掉了


对比书上的图,缺项多项

正确写法: 

【【数据结构】构造哈夫曼树手写代码】icon-default.png?t=N7T8https://www.bilibili.com/video/BV1EV4y1V7Vx/?share_source=copy_web&vd_source=7ffbd7feaeedb3d59fb21e59435a53d8 改进: 

returnElement函数弃用,改成每次在tree中寻找最小元素、和次小元素的下标。

先把叶子结点存入,以免出现交叉存放和覆盖数据

先把叶子结点存入后,直接更新父结点的值就可以了,叶子结点的parent指向父结点的下标

#include <bits/stdc++.h>
using namespace std;

int n = 6;
vector<int> s = {21, 10, 32, 41, 18, 70};
vector<int> a = s;
vector<int> temp(10);
//priority_queue<int, vector<int>, greater<int>> pq; //升序队列模板

struct treeNode{
	int weight;
	int parent;
	int leftchild, rightchild;
}tree[20];

void selectMinElementIndex(int n, int& index1, int& index2)
{
	int min = 9e8; //打擂台,用于确定最小的那个
	//寻找最小的权值下标
	for(int i=1; i<= n; i++)
	{
		if(tree[i].parent == -1 && tree[i].weight < min)
		{
			min = tree[i].weight;
			index1 = i;
		}
	}
	min = 9e8;
	//寻找次小的权值下标
	for(int i=1; i<= n; i++)
	{
		if(tree[i].parent == -1 && tree[i].weight < min && i != index1)
		{
			min = tree[i].weight;
			index2 = i;
		}
	}
}

void CreateHuffmanTree(){ //二分归并法最优
	sort(s.begin(), s.end());	
	int index1, index2;
	//初始化-1
	for(int i=1; i<=2*n-1; i++)
	{
		tree[i].parent = -1,  tree[i].leftchild = -1; 
		tree[i].rightchild = -1;
	}
	//放入叶子结点
	for(int i=1; i<=n; i++)
	{
		tree[i].weight = s[i-1];
	}
	
	for(int i=n+1; i<=2*n-1; i++)
	{
		//传入了i-1,保证在新建立的父节点和叶子结点中寻找两个最小
		selectMinElementIndex(i-1, index1, index2);
		// 左右孩子结点指向父结点
		tree[index1].parent = i;
		tree[index2].parent = i;
		//父结点更新值
		tree[i].weight = tree[index1].weight + tree[index2].weight;
		tree[i].leftchild = index1;
		tree[i].rightchild = index2;
	}
}
//由于中文乱码,所以输出英文
void printTree()
{
    for (int i = 1; i <= 2*n-1; i++)
    {
    	cout << setw(7) << "i:" << i << "  ";
        cout << setw(7) << "node:" << tree[i].weight << "\t";
        cout << setw(7) << "parent:" <<  (tree[i].parent != -1 ? tree[tree[i].parent].weight : -1) << "\t";
        cout << setw(7) << "leftchild:" <<  (tree[i].leftchild != -1 ? tree[tree[i].leftchild].weight : -1) << "\t";
        cout << setw(7) << "rightchild:" << (tree[i].rightchild != -1 ? tree[tree[i].rightchild].weight : -1) << endl;
    }
}

void CreateATree(){ //另一种二分归并法
	
	int j=1;
	//初始化-1
	for(int i=1; i<=2*n-1; i++)
	{
		tree[i].parent = -1,  tree[i].leftchild = -1; 
		tree[i].rightchild = -1;
	}
	//放入叶子结点
	for(int i=1; i<=n; i++)
	{
		tree[i].weight = s[i-1];
	}
	
	for(int i=n+1; i<=2*n-1; i++)
	{
		// 左右孩子结点指向父结点,j直接选两个平推过去
		tree[j].parent = i;
		tree[j+1].parent = i;
		//父结点更新值
		tree[i].weight = tree[j].weight + tree[j+1].weight;
		tree[i].leftchild = j;
		tree[i].rightchild = j+1;
		j += 2;
	}
}

int main()
{
	cout << "The another method:" << endl;
	CreateATree();
	printTree();
	cout << "The best method:" << endl;
	CreateHuffmanTree();
	printTree();
	return 0;
}

【运行结果】

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue脚手架与创建vue项目

一、前言 vue脚手架的安装与创建vue项目需要先行安装配置node与npm&#xff0c;详情可以看node、npm的下载、安装、配置_node 下载安装-CSDN博客 二、vue脚手架的使用 1、vue与vue脚手架的版本 Vue脚手架&#xff08;Vue CLI&#xff09;是Vue.js官方提供的一个命令行工具&…

打乱一维数组中数据(小练习)

int[] tempArr{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; 要求&#xff1a;打乱一维数组的数据&#xff0c;并按照4个一组的方式添加到二维数组中。 package chengyu4; import java.util.Random; public class Test{public static void main(String args[]) {int[] temArr {1…

CM2038A 3W 双通道立体声音频功率放大器芯片IC

功能说明: CM2038A是一双路音频功率放大器&#xff0c;它能够在5V 电源电压下给一个4Ω负载提供THD小于10%、最大平均值为3W的输出功率。另外&#xff0c;在驱动立体声耳机时耳机输入引脚可以使放 大器工作在单边模式。 CM2038A是为提供高保真音频输出而专门设计…

【每日一坑】KiCAD 覆铜区域约束

【每日一坑】 1.螺丝孔周围不想要要铜皮&#xff1b; 2、首先在CTRLshiftK;画一个区域&#xff0c;比如铺一个GND; 3、选择CUTOUT; 4、画线&#xff0c;画好闭合图形&#xff1b;如下图 5、就是这样了&#xff0c;就是还没有画圆或者异形的&#xff1b;

如何制定一个有效的现货黄金投资策略(EEtrade)

制定一个有效的现货黄金投资策略涉及多方面的考量。以下是几个步骤和考虑因素&#xff0c;可以帮助您建立一个坚实的投资策略&#xff1a; 1. 设立清晰的投资目标 决定您投资现货黄金的主要目的。是否是为了短期利润&#xff0c;长期保值增值&#xff0c;还是为了投资组合的多…

如何通过网络性能监控和流量回溯分析提升网络效率?

目录 网络性能监控的重要性 什么是网络性能监控&#xff1f; 为什么需要网络性能监控&#xff1f; 流量回溯分析的应用 什么是流量回溯分析&#xff1f; 流量回溯分析的优势 实现网络性能监控和流量回溯分析的方法 使用高性能的分析工具 部署网络监控系统 结论 在当今…

Windows内核函数 - 创建关闭注册表

在驱动程序的开发中&#xff0c;经常会用到对注册表的操作。与Win32的API不同&#xff0c;DDK提供另外一套对注册表操作的相关函数。首先明确一下注册表里的几个概念&#xff0c;避免在后面混淆。 图1 注册表概念 有5个概念需要重申一下&#xff1a; * 注册表项&#xff1a; 注…

关于c++的通过cin.get()维持黑框的思考

1.前言 由于本科没有学过c语言&#xff0c;研究生阶段接触c上手有点困难&#xff0c;今天遇到关于通过cin.get()来让黑框维持的原因。 2.思考 cin.get()维持黑框不消失的原因一言蔽之就是等待输入。等待键盘的输入内容并回车&#xff08;一般是回车&#xff09;后cin.get()才…

2024下半年BRC-20铭文发展趋势预测分析

自区块链技术诞生以来&#xff0c;其应用场景不断扩展&#xff0c;代币标准也在不断演进。BRC-20铭文作为基于比特币区块链的代币标准&#xff0c;自其推出以来&#xff0c;因其安全性和去中心化特性&#xff0c;受到了广泛关注和使用。随着区块链技术和市场环境的不断变化&…

NFTScan 正式上线 Mint NFTScan 浏览器和 NFT API 数据服务

2024 年 5 月 20 号&#xff0c;NFTScan 团队正式对外发布了 Mint NFTScan 浏览器&#xff0c;将为 Mint 生态的 NFT 开发者和用户提供简洁高效的 NFT 数据搜索查询服务。NFTScan 作为全球领先的 NFT 数据基础设施服务商&#xff0c;Mint 是继 Bitcoin、Ethereum、BNBChain、Po…

maven聚合工程整合springboot+mybatisplus遇到的问题

前言&#xff08;可以直接跳过看下面解决方法&#xff09; 项目结构 两个module&#xff1a; yema-terminal-boot 是springboot项目&#xff0c;子包有&#xff1a;controller、service、dao 等等。属于经典三层架构。那么&#xff0c;该module可以理解为是一个单体项目&…

python打造自定义汽车模块:从设计到组装的全过程

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言 二、定义汽车模块与核心类 三、模拟汽车组装过程 四、抽象与封装 五、完整汽车…

液氮罐内部会污染吗

液氮罐是一种常见的存储液态氮的设备&#xff0c;广泛应用于科研、生物医药、食品冷冻等领域。但是&#xff0c;人们对于液氮罐内部是否会产生污染一直存在疑问。 我们来看液氮罐内部可能的污染源。液氮罐内部主要存在以下几种潜在的污染来源&#xff1a;气体污染、杂质污染、…

飞睿智能高精度、低功耗测距,无线室内定位UWB芯片如何改变智能家居

在数字化和智能化快速发展的今天&#xff0c;定位技术已经成为我们日常生活中不可或缺的一部分。然而&#xff0c;传统的GPS定位技术在室内环境中往往束手无策&#xff0c;给我们的生活带来了诸多不便。幸运的是&#xff0c;随着科技的不断进步&#xff0c;一种名为UWB&#xf…

Octo:伯克利开源机器人开发框架

【摘要】在各种机器人数据集上预先训练的大型策略有可能改变机器人学习&#xff1a;这种通用机器人策略无需从头开始训练新策略&#xff0c;只需使用少量领域内数据即可进行微调&#xff0c;但具有广泛的泛化能力。然而&#xff0c;为了广泛应用于各种机器人学习场景、环境和任…

FM1800隧道广播插播控制器

隧道广播插播控制器是一款群载波&应急广播插播控制器采用SDR软件无线电技术&#xff0c;产生独立的插播信号与“群载波”信号&#xff0c;本设备可通过软件无线电技术将音频信号调制成调频载波或“群载波”信号&#xff0c;分别送入插播主机&#xff0c;实现隧道广播远端机…

uart_tty_驱动程序框架

UART子系统(四) TTY驱动程序框架_tty驱动框架-CSDN博客

摩尔投票法——代码实现及注释(力扣169题:找出列表中多数元素)

题源&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 目录 一、摩尔投票法 1.1 关键思想 1.2 时空复杂度 1.3 算法详细步骤 1.4 代码 1.5 算法理解 一、摩尔投票法 摩尔投票法&#xff08;Boyer–Moore Majority Vote Algorithm&#xff09;&#xff0c;也被称为…

新版idea配置git步骤及项目导入

目录 git安装 下载 打开git Bash 配置全局用户名及邮箱 查看已经配置的用户名和邮箱 在IDEA中设置Git 问题解决 项目导入 git安装 下载 进入官网 Git - Downloads 点击所属本机系统&#xff0c;window如下图 选择64位安装 按照默认步骤一直下一步即可 打开git Bash …

倒计时 1 天!「飞天技术沙龙-CentOS 迁移替换专场」演讲亮点一览

各位开发者们&#xff1a; 「飞天技术沙龙 - CentOS 迁移替换专场」即将于本周三在北京召开&#xff01;昨天&#xff0c;小龙为参会者公布了详细参会指南&#xff0c;今天带大家了解各演讲内容亮点。 活动时间&#xff1a;5 月 29 日&#xff08;本周三&#xff09; 13:30-17…