哈夫曼编码学习记录C++



//哈夫曼编码
//https://www.bilibili.com/video/BV1wf421q7b8?vd_source=f8adf0d316b7398e145b8753f523e680&spm_id_from=333.788.player.switch
//https://www.bilibili.com/video/BV1qu411F7Zs?vd_source=f8adf0d316b7398e145b8753f523e680&spm_id_from=333.788.videopod.sections
#include<iostream>
#include<fstream>
#include<string>

using namespace std;

struct HTNode {
	//未存入字符则为'*'可以用其他不冲突的字符代替
	char word = '*';//字符
	double weight;//权重
	int Pn;//父结点Parent-Node
	int Ln, Rn;//左右子结点Left/Right-Node
};
typedef HTNode* HuffmanTree;

//找出森林集合中根权值最小的两个结点
void Select(HuffmanTree HT, int n, int& si, int& s2);
//构建哈夫曼树
void CreatHuffmanTree(HuffmanTree HT, int& n);
//先序遍历
void preOrder(HuffmanTree HT, int n);
//哈夫曼编码
void HuffmanCoding(HuffmanTree HT, int code[], int n);
//各字符的哈夫曼编码
void WordCoding(HuffmanTree HT, int node, int code[]);

int main()
{
	cout << "请输入一串字符:" << endl;
	//-------------------------------------
	//该区域为文件操作
	//读入文件至 字符串str
	//未解决'\n'字符无法读入的问题
	ifstream ifs;
	ifs.open("HaffmanFile.txt");

	string str;
	if (ifs.is_open()) {
		getline(ifs, str);
	}
	//不进行文件操作时由该被注释代码进行输入即可
	//cin >> str;//待处理字符串
	ifs.close();
	cout << str << endl;
	//------------------------------------
	//该数组记录字符频率
	HTNode array[256];
	for (int i = 0; i < 256; i++) {
		//初始化array数组
		array[i].weight = 0;
		array[i].Pn = 0;
		array[i].Ln = array[i].Rn = -1;
	}
	array[1].word = str[0];
	//记录存入字符的长度
	//即array所含元素的长度
	int length = 1;
	bool ifAdd = true;
	//字符数据存入-----
	for (int i = 0; i < str.size(); i++) {
		for (int j = 1; j <= length; j++) {
			if (array[j].word == str[i]) {
				array[j].weight++;
				ifAdd = false;
			}
		}
		if (ifAdd) {
			length++;
			array[length].word = str[i];
			array[length].weight++;
		}
		else {
			ifAdd = true;
		}
	}
	//------------------------
	cout << endl << length << endl;
	//输出各字符元素的权---
	for (int i = 1; i <= length; i++) {
		array[i].weight /= str.size();
		cout << array[i].word << " " << array[i].weight << endl;
	}
	//------------------------
	cout << endl;
	cout.setf(ios::showpoint);
	CreatHuffmanTree(array, length);
	//构成哈夫曼树后
	//将树的各结点输出
	for (int i = 1; i <= length; i++) {
		cout << "[" <<  i << "]" << array[i].word << " " << array[i].weight << endl;
		cout << "Pn[" << array[i].Pn << "]\t" << "Ln[" << array[i].Ln << "]\t" << "Rn[" << array[i].Rn << "]\n" << endl;
		//分割字符结点与结合结点
		if (array[i].word != '*' && array[i + 1].word == '*') {
			cout << "\n------------------------------------------------------------------------\n";
		}
	}

	preOrder(array, length);

	cout << endl;
	//将各结点的编码映射至该数组
	//0-1
	int code[256];
	HuffmanCoding(array, code, length);
	//测试code数组
	//for (int i = 0; i <= length; i++) {
	//	cout << code[i];
	//}
	cout << endl;
	//输出各字符的哈夫曼编码
	for (int i = 1; i <= length; i++) {
		//仅留下字符结点
		if (array[i].word == '*') break;
		cout << array[i].word << " ";
		WordCoding(array, i, code);
		cout << endl;
	}

	return 0;
}
//-------------------------------------------------------------
//
 void Select(HuffmanTree HT, int n, int& s1, int& s2) {
	int min = 1;
	for (int i = 1; i <= n; i++) {
		if (HT[i].Pn == 0) {
			min = i;
			break;
		}
	}
	for (int i = 1; i <= n; i++) {
		if (HT[i].Pn == 0 && HT[i].weight <= HT[min].weight && i != min) {
			min = i;
		}
	}
	s1 = min;

	for (int i = 1; i <= n; i++) {
		if (HT[i].Pn == 0 && i != s1) {
			min = i;
			break;
		}
	}
	for (int i = 1; i < n; i++) {
		if (i != s1) {
			if (HT[i].Pn == 0 && HT[i].weight <= HT[min].weight && i != min) {
				min = i;
			}
		}
	}
	s2 = min;
}

void CreatHuffmanTree(HuffmanTree HT, int& n) {
	int s1, s2;
	while (true) {
		Select(HT, n, s1, s2);
		if (s1 == s2) {
			break;
		}
		//直接在array(HT)数组后
		//添加结合结点
		//以形成树结构
		//
		//n表示节点数量
		//是在array(HT)数组所存入字符数量(length)上自增
		//相当于记录了
		//树的结点数量
		++n;
		HT[n].Ln = s1;
		HT[s1].Pn = n;
		HT[n].Rn = s2;
		HT[s2].Pn = n;
		HT[n].weight = HT[s1].weight + HT[s2].weight;
	}
}

void preOrder(HuffmanTree HT, int n) {
	if (n == 0 || n == -1)return;
	if (HT[n].Ln == -1 || HT[n].Rn == -1) cout << HT[n].weight << " ";
	preOrder(HT, HT[n].Ln);
	preOrder(HT, HT[n].Rn);
}

//哈夫曼编码不唯一
//与根节点 子结点的 标记的区别(0/1)有关
void HuffmanCoding(HuffmanTree HT, int code[], int n) {
	//n为树的结点数量
	//也是根节点的位置
	//node为结点编号
	int node = n;
	code[0] = 0;
	code[n] = 0;
	while (node != 0) {
		if (HT[HT[node].Pn].Ln == node) {
			code[node] = 0;
		}
		if (HT[HT[node].Pn].Rn == node) {
			code[node] = 1;
		}
		--node;
	}
}

void WordCoding(HuffmanTree HT, int node, int code[]) {
	int next[256];
	//num记录编码长度
	//记录了最大下标
	int num = 0;
	while (true) {
		next[num] = code[node];
		node = HT[node].Pn;
		if (node == 0) break;
		++num;
	}
	//根节点到该结点的编码为哈夫曼编码
	for (int i = num; i >= 0; i--) {
		cout << next[i];
	}
}

//2024-12-03;
<think>好的,用户想了解HS400模式下200MHz的配置或相关信息。首先,我需要回忆HS400是什么,它属于eMMC规范中的高速接口模式。HS400代表High Speed SDR 400,支持双倍数据率(DDR),最高时钟频率200MHz,每个时钟周期传输两次数据,所以理论速度达到400MB/s。 接下来,配置HS400的步骤可能包括硬件和软件两方面。硬件上,设备必须支持HS400模式,PCB布线要符合信号完整性要求,比如走线长度匹配、阻抗控制。电源稳定性也很重要,因为高速信号对噪声敏感。 软件配置方面,首先需要初始化eMMC设备,设置总线宽度为8位,切换到HS200模式进行校准,再切换到HS400。可能需要调整驱动强度和采样点,确保信号质量。设备树(Device Tree)的配置是否正确,比如是否启用了HS400相关属性,也是关键。 还要考虑用户提到的引用内容,比如引用[4]中的存储测试工具,可能用memtester和fio来验证配置后的性能。此外,调试方法如示波器检查信号质量,以及查看内核日志确认模式切换是否成功,都是必要的步骤。 用户可能遇到的问题包括模式切换失败、数据错误或系统不稳定,需要逐一排查硬件设计、驱动配置和电源问题。最后,确保引用的相关信息正确,比如引用[4]中的测试工具是否适用于HS400的验证,可能需要补充说明。</think>### HS400 200MHz 模式配置信息 HS400(High Speed SDR 400)是eMMC 5.1及更高版本中定义的高速接口模式,通过200MHz时钟频率和双倍数据率(DDR)实现更高的传输速率。以下是相关配置信息: #### 1. **硬件要求** - **设备支持**:存储设备(如eMMC芯片)需支持HS400模式[^4]。 - **信号完整性**:200MHz高频信号对PCB布线要求严格,需确保走线长度匹配、阻抗控制(通常50Ω差分阻抗)及减少串扰。 - **电源稳定性**:需提供稳定的1.8V或3.3V电源,噪声需控制在±5%以内。 #### 2. **软件配置步骤** 1. **初始化模式切换**: - 从默认模式切换至HS200模式,完成信号校准。 - 通过CMD6命令切换至HS400模式,并启用8位总线宽度。 ```c // 示例:eMMC模式切换命令(Linux内核驱动参考) mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, HS400_TIMING); ``` 2. **驱动强度调整**:通过设备树(Device Tree)配置驱动强度采样点: ```dts &mmc { bus-width = <8>; mmc-hs400-1_8v; hs400-ds = "strength_high"; // 驱动强度 hs400-reduced-tx = <0>; // 采样点调整 }; ``` 3. **时钟配置**:确保主机控制器支持200MHz时钟输出,并配置PLL参数。 #### 3. **调试验证** - **信号质量测试**:使用示波器检查CLKDATA信号的眼图,确保建立/保持时间符合要求。 - **性能测试**:通过`fio`工具验证读写速度(引用[4]中提到的存储测试方法): ```bash fio --name=hs400_test --rw=randrw --bs=128k --direct=1 --ioengine=libaio --runtime=60 --numjobs=4 --group_reporting --filename=/dev/mmcblk0 ``` - **内核日志检查**:通过`dmesg`查看eMMC模式切换是否成功: ``` mmc0: new HS400 MMC card at address 0001 ``` #### 4. **常见问题优化** - **模式切换失败**:检查设备树配置或电压是否匹配。 - **数据错误**:优化PCB走线或调整驱动强度。 - **性能瓶颈**:启用命令队列(CQHCI)或优化DMA配置[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值