当前位置: 首页 > news >正文

【数据结构 】哈夫曼编译码器

数据结构-----哈夫曼编译码器

  • 题目
    • 题目描述
    • 基本要求
    • 算法分析
  • 代码实现
    • 初始化
    • 编码
    • 解码
    • 打印代码
    • 打印哈夫曼树
  • 总结

题目

题目描述

  • 利用哈夫曼编码进行信息通信可大大提高信道利用率,缩短信息传输时间,降低传输成本。
    要求:在发送端通过一个编码系统对待传数据预先编码;在接收端将传入的数据进行译码(复原)。对于双工信道(即可以双向传输信息的信道),每端都需要个完整的编/译码系统。试为这样的信息收发站写一个哈夫曼的编/译码系统。

基本要求

  • 基本要求
    系统应具有以下功能:
    ① I:初始化.从终端读入字符集大小n及n个字符和n个权值,建立哈夫曼树,井将它存于文件HuffmanTree中。
    ② C:编码。利用已建立好的哈夫曼树(如不在内存,则从文件HuffmanTree中读入)。对文件tobetrans中的正文进行编码,然后将结果存入文件codefile中。
    ③ D:解码。利用已建立好的哈夫曼树将文件codefile中的代码进行译码,结果存入testfile中。
    ④ P:打印代码文件。将文件codefile以紧凑格式显示在终端上,每行50个代码。同时将此字符形式的编码文件写入文件codeprint中。
    ⑤ T:打印哈夫曼树。将已在内存中的哈夫曼树直观的方式(树或凹入表形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件treeprint中。

算法分析

  • 本题例主要用到3个算法如下:
    ① 哈夫曼编码。在初始化(I)的过程中,要用输入的字符和权值建立哈夫曼树并求得哈夫曼编码。先将输入的字符和权值放到一个结构体数据中,建立哈夫曼树,将计算所得的哈夫曼编码存储到另一个结构体数组中。
    ② 串的匹配。在解码(D)的过程中,要对已经编码过的代码进行译码,可利用循环,将代码中与哈夫曼编码长度相同的串与这个哈夫曼编码进行比较,如果相等就回显并存入文件。
    ③二叉树的遍历。在打印哈夫曼树(T)的过程中,因为哈夫曼树也是二叉树,所以就要利用二叉树的前序遍历将哈夫曼树输出。

代码实现

代码部分参考了《数据结构-C语言版第2版》这本书中代码以及C++风格进行书写,测试文件tobetrans中的内容为"ABCABC"

初始化

题目要求从终端读入字符集大小n及n个字符和n个权值,建立哈夫曼树,并将它存于文件HuffmanTree中,可以先将哈夫曼树构建起来,得到哈夫曼树及其对应叶子节点的编码,再通过文件的输入输出将这些编码写入文件HuffmanTree中即可

  • 构造哈夫曼树
/*找出森林集合中根权值最小的两个*/
void Select(HuffmanTree HT,int len,int &s1,int &s2)
{int i,min1=0x3f3f3f3f,min2=0x3f3f3f3f;//先赋予最大值for(i=1;i<=len;i++){if(HT[i].weight<min1&&HT[i].parent==0){min1=HT[i].weight;s1=i;}	}int temp=HT[s1].weight;//将原值存放起来,然后先赋予最大值,防止s1被重复选择HT[s1].weight=0x3f3f3f3f;for(i=1;i<=len;i++){if(HT[i].weight<min2&&HT[i].parent==0){min2=HT[i].weight;s2=i;}}HT[s1].weight=temp;//恢复原来的值
}/*构建哈夫曼树*/
void CreatHuffmanTree(HuffmanTree &HT,int n)
{//构造赫夫曼树HTint m,s1,s2,i;if(n<=1) return;m=2*n-1;HT=new HTNode[m+1];  		//0号单元未用,所以需要动态分配m+1个单元,HT[m]表示根结点   for(i=1;i<=m;++i)        	//将1~m号单元中的双亲、左孩子,右孩子的下标都初始化为0   { HT[i].parent=0;  HT[i].lchild=0;  HT[i].rchild=0; }cout<<"请输入叶子结点的字符和权值:\n";for(i=1;i<=n;++i)        	//输入前n个单元中叶子结点的权值  cin>>HT[i].s>>HT[i].weight;  /*――――――――――初始化工作结束,下面开始创建赫夫曼树――――――――――*/ for(i=n+1;i<=m;++i) {  	//通过n-1次的选择、删除、合并来创建赫夫曼树Select(HT,i-1,s1,s2);//在HT[k](1≤k≤i-1)中选择两个其双亲域为0且权值最小的结点,// 并返回它们在HT中的序号s1和s2HT[s1].parent=i; 	HT[s2].parent=i;   //得到新结点i,从森林中删除s1,s2,将s1和s2的双亲域由0改为iHT[i].lchild=s1;   HT[i].rchild=s2;							//s1,s2分别作为i的左右孩子HT[i].weight=HT[s1].weight+HT[s2].weight; 	//i 的权值为左右孩子权值之和}											
}
  • 哈夫曼编码
/*哈夫曼树编码*/
void CreatHuffmanCode(HuffmanTree HT,HuffmanCode &HC,int n)
{//从叶子到根逆向求每个字符的赫夫曼编码,存储在编码表HC中int i,start,c,f;HC=new char*[n+1];         						//分配n个字符编码的头指针矢量char *cd=new char[n];							//分配临时存放编码的动态数组空间cd[n-1]='\0';                            		//编码结束符for(i=1;i<=n;++i){                      							//逐个字符求赫夫曼编码start=n-1;                          		//start开始时指向最后,即编码结束符位置c=i; f=HT[i].parent;                 			//f指向结点c的双亲结点while(f!=0){                          					//从叶子结点开始向上回溯,直到根结点--start;                          		//回溯一次start向前指一个位置if(HT[f].lchild==c)  cd[start]='0';						//结点c是f的左孩子,则生成代码0else cd[start]='1';                 		//结点c是f的右孩子,则生成代码1c=f; f=HT[f].parent;             			//继续向上回溯}                                  			//求出第i个字符的编码      HC[i]=new char[n-start];         			// 为第i 个字符编码分配空间strcpy(HC[i], &cd[start]);        			//将求得的编码从临时空间cd复制到HC的当前行中}delete cd;                            			//释放临时空间
}
  • 将编码写入到文件HuffmanTree
    这里通过循环将构造好的哈夫曼编码直接写入到文件
//编码写入文件HuffmanTree.txt
void printCreatHuffmanCode(HuffmanTree HT, HuffmanCode HC,int n)
{ofstream hFile("HuffmanTree.txt");if (!hFile.is_open()) {cout << "文件HuffmanTree.txt打开失败." << endl;exit(1);} cout<<"各字符对应的编码如下:"<<endl; for (int i = 1; i <=n; i++){cout << HT[i].s << HC[i] << endl;hFile << HT[i].s << HC[i]<<endl; }hFile.close();cout << "成功写入文件HuffmanTree.txt" << endl;
}

初始化部分运行截图如下:
哈夫曼树及其编码初始化

编码

思路:通过文件逐行读出字符,并将其存放到数组,通过遍历该数组以及哈夫曼树,从而将对应的编码写入到文件codefile.txt中

//编码部分 
void Huffmancode(HuffmanTree HT,HuffmanCode HC,int n) {// 函数用于对 "tobetrans.txt" 文件中的内容进行编码,并将结果存储在 "codefile.txt" 文件中// 假设 "tobetrans.txt" 包含要编码的内容,每一行表示一个要编码的字符串。ifstream tFile("tobetrans.txt");//读 ofstream cFile("codefile.txt");//写 if (!tFile.is_open()) {cout << "文件tobetrans.txt打开失败.\n"<<endl;exit(1);}if (!cFile.is_open()) {cout << "文件codefile.txt打开失败.\n"<<endl;exit(1);}char tobetrans[100];//临时存放文件中每一行的字符 // 逐行读取内容while (tFile.getline(tobetrans, sizeof(tobetrans))) {//行不空 int m= strlen(tobetrans);//数组长度,即每一行字符个数cout<<"tobetrans内容:"<<tobetrans; cout<<endl; for (int i = 0; i <m; i++) {//遍历数组 for(int j=1;j<=n;j++) //遍历树节点(0号单元为根节点未启用) {if (HT[j].s == tobetrans[i]) {//相等则将其对应的编码写入文件 cFile << HC[j];}}}}tFile.close();cFile.close();cout<<"成功写入文件codefile.txt"<<endl;}

编码部分运行截图如下:
将文件中的内容进行编码

解码

思路:和编码部分一样,先从文件逐行读出存入数组,接着再遍历该数组和树的节点,从而将对应的字符写入到testfile.txt中

//译码部分 
void HuffmanDecode(HuffmanTree HT, int n) {//函数用于利用已建立好的哈夫曼树将文件"codefile.txt"中的代码进行译码,结果存入"testfile.txt"中ifstream codeFile("codefile.txt");//读 ofstream testFile("testfile.txt");//写 if (!codeFile.is_open()) {cout << "文件codefile.txt打开失败.\n"<<endl;exit(1);}if (!testFile.is_open()) {cout << "文件testfile.txt打开失败.\n"<<endl;exit(1);}char pwd[100];codeFile.getline(pwd, sizeof(pwd));//每次读取一行放入数组pwd中进行译码 int len = strlen(pwd);int i = 0;int node = 2 * n - 1;//从根节点开始 while (i < len) {  // 循环遍历读取数组中的每个字符while (HT[node].lchild != 0 && HT[node].rchild != 0) {  // 当当前节点不是叶子节点时循环if (pwd[i] == '0') {  // 如果当前读取的字符是 '0'node = HT[node].lchild;  // 移动到当前节点的左孩子节点} else if (pwd[i] == '1') {  // 如果当前读取的字符是 '1'node = HT[node].rchild;  // 移动到当前节点的右孩子节点}i++;  // 移动到下一个字符}testFile << HT[node].s;  // 将叶子节点对应的字符写入到输出文件中node = 2 * n - 1;  // 将节点移动回到根节点}codeFile.close();testFile.close();cout << "成功写入文件testfile.txt" << endl;}

解码部分运行截图如下:
将已经编译好的字符码进行解码

打印代码

思路:通过文件逐行读出二进制码,在根据题目要求将对应的格式输出到终端输入到文件(我这里以每5行为例)

//打印代码文件 
void Print()
{//函数用于将文件codefile.txt以紧凑格式显示在终端上,每行5个代码。//同时将此字符形式的编码文件写入文件codeprint.txt中。 char str[1000];//存储codefile.txt的0-1编码 int num = 0;ifstream file1("codefile.txt");//读出 ofstream file2("codeprint.txt");//写入 if(file1.fail()){cout<<"文件codefile.txt打开失败"<<endl;exit(0);}if(file2.fail()){cout<<"文件codeprint.txt打开失败"<<endl;exit(0);}file1.getline(str, 10000);//读取每一行cout<<"str内容"<<str; cout<<endl;cout<<"文件codefile.txt内容显示如下:"<<endl; while(str[num]){if(num%5==0&&num!=0)//每输出5个字符换行,由于数组下标从0开始所以要忽略num==0这个情况 {cout<<endl; file2<<endl;//文件里也是每5个字符换行 }cout<<str[num];file2<<str[num];//写入文件 num++; 				}cout<<endl;file1.close();file2.close();cout<<"成功写入文件codeprint.txt"<<endl;	}

打印代码部分运行截图如下:
打印代码文件

打印哈夫曼树

这里结合树的前序遍历,并以凹入表的形式进行输出

void PrintHuffmanTree(HuffmanTree HT, int root, int level) {// 递归打印哈夫曼树的结构(凹入表形式)if (root != 0) {// 打开文件 treeprint.txtofstream treeFile("treeprint.txt", ios::app);  // 使用 ios::app 追加模式if (treeFile.fail()) {cout << "文件 treeprint.txt 打开失败" << endl;exit(0);}// 输出当前节点信息(以凹入表形式)cout << string(4 * level, ' ');  // 控制缩进cout << HT[root].weight;//输出节点权值 if (HT[root].s) {cout << " (" << HT[root].s << ")";//节点字符 }cout << endl;treeFile << string(4 * level, ' ');treeFile << HT[root].weight;if (HT[root].s) {treeFile << " (" << HT[root].s << ")";}treeFile << endl;// 递归打印左右子树PrintHuffmanTree(HT, HT[root].lchild, level + 1);PrintHuffmanTree(HT, HT[root].rchild, level + 1);}
}

打印哈夫曼树运行截图如下:
打印哈夫曼树

总结

关于如何书写一个哈夫曼编译码器,以上代码大家可以参考,仅供参考!!!毕竟我写的也不是很优秀,只能做到题目的要求,代码中还有许多可以优化的地方,介于自己能力有限,就先分享这么多,大家如果在参考以上代码存在问题时,需要我自己书写的完整代码可以私信我哦,在此感谢各位大佬的支持!

相关文章:

【数据结构 】哈夫曼编译码器

数据结构-----哈夫曼编译码器 题目题目描述基本要求算法分析 代码实现初始化编码解码打印代码打印哈夫曼树 总结 题目 题目描述 利用哈夫曼编码进行信息通信可大大提高信道利用率&#xff0c;缩短信息传输时间&#xff0c;降低传输成本。 要求&#xff1a;在发送端通过一个编…...

大屏项目:react中实现3d效果的环形图包括指引线

参考链接3d环形图 3d效果的环形图 项目需求实现方式指引线&#xff08;线的样式字体颜色&#xff09; 项目需求 需要在大屏上实现一个3d的环形图&#xff0c;并且自带指引线&#xff0c;指引线的颜色和每段数据的颜色一样&#xff0c;文本内容变成白色&#xff0c;数字内容变…...

【STM32】STM32学习笔记-FlyMCU串口下载和STLINK Utility(30)

00. 目录 文章目录 00. 目录01. 串口简介02. 串口连接电路图03. FlyMCU软件下载程序04. 串口下载原理05. FlyMCU软件其它操作06. STLINK Utility软件07. 软件下载08. 附录 01. 串口简介 串口通讯(Serial Communication)是一种设备间非常常用的串行通讯方式&#xff0c;因为它简…...

oracle rac 12.2.0.1CPU使用率100%

oracle rac 12.2.0.1 CPU使用率100% 查看是集群的java进程"oracle.ops.opsctl.OPSCTLDriver config database"占用cpu 根据进程号查找父进程,发现是/oracle/GRID/122/perl/bin/perl /oracle/GRID/122/tfa/gcmproddb01/tfa_home/bin/tfactl.pl rediscover -mode full …...

LeetCode、2542. 最大子序列的分数【中等,排序+小顶堆】

文章目录 前言LeetCode、2542. 最大子序列的分数【中等&#xff0c;排序小顶堆】题目及类型思路及代码实现 资料获取 前言 博主介绍&#xff1a;✌目前全网粉丝2W&#xff0c;csdn博客专家、Java领域优质创作者&#xff0c;博客之星、阿里云平台优质作者、专注于Java后端技术领…...

Linux_Docker图形化工具Portainer如何安装并结合内网穿透实现远程访问

文章目录 前言1. 部署Portainer2. 本地访问Portainer3. Linux 安装cpolar4. 配置Portainer 公网访问地址5. 公网远程访问Portainer6. 固定Portainer公网地址 前言 本文主要介绍如何本地安装Portainer并结合内网穿透工具实现任意浏览器远程访问管理界面。Portainer 是一个轻量级…...

【Spring Boot 3】【Redis】集成Jedis

【Spring Boot 3】【Redis】集成Jedis 背景介绍开发环境开发步骤及源码工程目录结构总结背景 软件开发是一门实践性科学,对大多数人来说,学习一种新技术不是一开始就去深究其原理,而是先从做出一个可工作的DEMO入手。但在我个人学习和工作经历中,每次学习新技术总是要花费…...

C++设计模式(李建忠)笔记3

C设计模式&#xff08;李建忠&#xff09; 本文是学习笔记&#xff0c;如有侵权&#xff0c;请联系删除。 参考链接 Youtube: C设计模式 Gtihub源码与PPT&#xff1a;https://github.com/ZachL1/Bilibili-plus 豆瓣: 设计模式–可复用面向对象软件的基础 文章目录 C设计模…...

计算机考研408的准备

计算机考研408的准备 一&#xff1a;专硕和学硕 计算机的学硕叫做计算机科学与技术&#xff0c;而计算机的专硕叫计算机技术。这么区分的意义就在于我们的就业形势和科研形式。 二&#xff1a;就业形势 由于本科的严重扩招以及课程设置的问题&#xff0c;相当大量的人在毕业…...

2.【Linux】(进程的状态||深入理解fork||底层剖析||task_struct||进程优先级||并行和并发||详解环境变量)

一.进程 1.进程调度 Linux把所有进程通过双向链表的方式连接起来组成任务队列&#xff0c;操作系统和cpu通过选择一个task_struct执行其代码来调度进程。 2.进程的状态 1.运行态&#xff1a;pcb结构体在运行或在运行队列中排队。 2.阻塞态&#xff1a;等待非cpu资源就绪&am…...

【管理篇 / 升级】❀ 13. FortiOS 7.4固件升级新规则 ❀ FortiGate 防火墙

【简介】飞塔防火墙的固件升级一直是所有厂家中最好的。只要有注册官方帐号&#xff0c;有注册设备&#xff0c;并且只要有一台设备在服务期内&#xff0c;即可下载所有型号的所有版本的固件。即使其它设备服务期已过&#xff0c;也可以通过固件文件手动升级&#xff0c;避免防…...

【前端】vue.js从入门到项目实战笔记

文章目录 第三章3.1 插值绑定&#xff08;{{}}&#xff0c; v-html&#xff09;3.1.1 文本插值3.1.2 HTML插值 3.2 属性绑定 v-bind3.2.1 指令v-bind3.2.3 类名和样式绑定 【前端目录贴】 第三章 3.1 插值绑定&#xff08;{{}}&#xff0c; v-html&#xff09; 文本插值中的代…...

flex布局(3)

九、骰子 *{margin:0;padding: 0;box-sizing: border-box; } .flex{display: flex;flex-flow: row wrap;justify-content: space-between;align-items: center;align-content: space-between;padding:20px; } .touzi{width: 120px;height: 120px;background-color: aliceblue;…...

JVM知识总结

1.概述 JVM指的是Java虚拟机&#xff0c;本质上是一个运行在计算机上的程序&#xff0c;他的职责是运行Java字节码文件&#xff0c;作用是为了支持跨平台特性。 功能&#xff1a; 装载字节码&#xff0c;解释/编译为机器码 管理数据存储和垃圾回收 优化热点代码提升效率 …...

读书笔记-《数据结构与算法》-摘要8[桶排序]

桶排序和归并排序有那么点点类似&#xff0c;也使用了归并的思想。大致步骤如下&#xff1a; 设置一个定量的数组当作空桶。Divide - 从待排序数组中取出元素&#xff0c;将元素按照一定的规则塞进对应的桶子去。对每个非空桶进行排序&#xff0c;通常可在塞元素入桶时进行插入…...

【STM32调试】寄存器调试不良问题记录持续版

STM32寄存器调试不良问题记录 NVIC&#xff08;内嵌的中断向量控制器&#xff09;EXTI&#xff08;外部中断/事件&#xff09; 记录一些stm32调试过程中&#xff1a;不易被理解、存在使用误区、不清不楚、是坑、使用常识等方面的一些记录。本记录只包含stm32的内核以及外设等寄…...

centos7 arm服务器编译升级安装动态库libstdc++.so.6,解决GLIBC和CXXABI版本低的问题

前言 由于centos7内置的libstdc.so.6版本太低&#xff0c;导致安装第三方包的时候&#xff0c;会报“CXXABI_1.3.8”不存在等问题。 自带的打印如下&#xff1a; strings /usr/lib64/libstdc.so.6 | grep GLIBC strings /usr/lib64/libstdc.so.6 | grep CXXABI 如图 升级 注…...

自动驾驶轨迹规划之碰撞检测(三)

欢迎大家关注我的B站&#xff1a; 偷吃薯片的Zheng同学的个人空间-偷吃薯片的Zheng同学个人主页-哔哩哔哩视频 (bilibili.com) 目录 1.基于圆覆盖 2.BVH 3.MATLAB自动驾驶工具箱 4 ROS内置的模型 自动驾驶轨迹规划之碰撞检测&#xff08;一&#xff09;-CSDN博客 自动驾…...

如何用pandas处理财报数据删除金融行业数据

要删除财报数据中的金融行业数据&#xff0c;您可以按照以下步骤使用pandas进行处理&#xff1a; 导入pandas库&#xff1a; import pandas as pd读取财报数据文件&#xff1a; df pd.read_csv(财报数据.csv)查看数据中的行业分类列&#xff1a; print(df[行业分类])确定金…...

oracle 19c容器数据库data dump数据泵传输数据(4)---网络传输

Transporting a Database Over the Network: Example 这个的方式导入可以不需要传输dmp文件&#xff0c;我原本是想从11g导入到pdb2的&#xff0c;但是因为版本的原因&#xff0c;就直接实验从pdb1导入到pdb2吧。 这种方式和前面完全传输的方式类似&#xff0c;不需要事先在目…...

JavaSec-RCE

简介 RCE(Remote Code Execution)&#xff0c;可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景&#xff1a;Groovy代码注入 Groovy是一种基于JVM的动态语言&#xff0c;语法简洁&#xff0c;支持闭包、动态类型和Java互操作性&#xff0c…...

超短脉冲激光自聚焦效应

前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应&#xff0c;这是一种非线性光学现象&#xff0c;主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场&#xff0c;对材料产生非线性响应&#xff0c;可能…...

ubuntu搭建nfs服务centos挂载访问

在Ubuntu上设置NFS服务器 在Ubuntu上&#xff0c;你可以使用apt包管理器来安装NFS服务器。打开终端并运行&#xff1a; sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享&#xff0c;例如/shared&#xff1a; sudo mkdir /shared sud…...

基于服务器使用 apt 安装、配置 Nginx

&#x1f9fe; 一、查看可安装的 Nginx 版本 首先&#xff0c;你可以运行以下命令查看可用版本&#xff1a; apt-cache madison nginx-core输出示例&#xff1a; nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

YSYX学习记录(八)

C语言&#xff0c;练习0&#xff1a; 先创建一个文件夹&#xff0c;我用的是物理机&#xff1a; 安装build-essential 练习1&#xff1a; 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件&#xff0c;随机修改或删除一部分&#xff0c;之后…...

unix/linux,sudo,其发展历程详细时间线、由来、历史背景

sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库&#xff0c;例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体&#xff0c;比如 SnowballFight、Huggy the Do…...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用

1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...

2023赣州旅游投资集团

单选题 1.“不登高山&#xff0c;不知天之高也&#xff1b;不临深溪&#xff0c;不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek

文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama&#xff08;有网络的电脑&#xff09;2.2.3 安装Ollama&#xff08;无网络的电脑&#xff09;2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...