【数据结构-树】哈夫曼树

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。
img

  • 推荐:kuan 的首页,持续学习,不断总结,共同进步,活到老学到老
  • 导航
    • 檀越剑指大厂系列:全面总结 java 核心技术点,如集合,jvm,并发编程 redis,kafka,Spring,微服务,Netty 等
    • 常用开发工具系列:罗列常用的开发工具,如 IDEA,Mac,Alfred,electerm,Git,typora,apifox 等
    • 数据库系列:详细总结了常用数据库 mysql 技术点,以及工作中遇到的 mysql 问题等
    • 懒人运维系列:总结好用的命令,解放双手不香吗?能用一个命令完成绝不用两个操作
    • 数据结构与算法系列:总结数据结构和算法,不同类型针对性训练,提升编程思维,剑指大厂

非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。💝💝💝 ✨✨ 欢迎订阅本专栏 ✨✨

博客目录

    • 一.哈夫曼算法
      • 1.什么是编码?
      • 2.编码传输规则
      • 3.Huffman 编码
    • 二.哈夫曼树
      • 1.什么 Huffman 树?
      • 2.哈夫曼树特点
      • 3.节点总数证明
      • 4.Huffman 树特点
    • 三.常见方法
      • 1.内部 Node 节点
      • 2.构造方法
      • 3.编码
      • 4.解码
      • 5.完整代码
    • 四.练习题
      • 1.连接棒材的最低费用-力扣 1167 题

一.哈夫曼算法

1.什么是编码?

简单说就是建立【字符】到【数字】的对应关系,如下面大家熟知的 ASC II 编码表,例如,可以查表得知字符【a】对应的数字是十六进制数【0x61】

\000102030405060708090a0b0c0d0e0f
0000000102030405060708090a0b0c0d0e0f
0010101112131415161718191a1b1c1d1e1f
002020!"#$%&()*+,-./
00300123456789:;<=>?
0040@ABCDEFGHIJKLMNO
0050PQRSTUVWXYZ[\]^_
0060`abcdefghijklmno
0070pqrstuvwxyz{|}~7f

注:一些直接以十六进制数字标识的是那些不可打印字符

2.编码传输规则

传输时的编码

  • java 中每个 char 对应的数字会占用固定长度 2 个字节
  • 如果在传输中仍采用上述规则,传递 abbccccccc 这 10 个字符
    • 实际的字节为 0061006200620063006300630063006300630063(16 进制表示)
    • 总共 20 个字节,不经济

现在希望找到一种最节省字节的传输方式,怎么办?

假设传输的字符中只包含 a,b,c 这 3 个字符,有同学重新设计一张二进制编码表,见下图

  • 0 表示 a
  • 1 表示 b
  • 10 表示 c

现在还是传递 abbccccccc 这 10 个字符

  • 实际的字节为 01110101010101010 (二进制表示)
  • 总共需要 17 bits,也就是 2 个字节多一点,行不行?

不行,因为解码会出现问题,因为 10 会被错误的解码成 ba,而不是 c

  • 解码后结果为 abbbababababababa,是错误的

怎么解决?必须保证编码后的二进制数字,要能区分它们的前缀(prefix-free)

用满二叉树结构编码,可以确保前缀不重复

image-20230616094945068

  • 向左走 0,向右走 1
  • 走到叶子字符,累计起来的 0 和 1 就是该字符的二进制编码

再来试一遍

  • a 的编码 0
  • b 的编码 10
  • c 的编码 11

现在还是传递 abbccccccc 这 10 个字符

  • 实际的字节为 0101011111111111111(二进制表示)
  • 总共需要 19 bits,也是 2 个字节多一点,并且解码没有问题了,行不行?

这回解码没问题了,但并非最少字节,因为 c 的出现频率高(7 次)a 的出现频率低(1 次),因此出现频率高的字符编码成短数字更经济

3.Huffman 编码

考察下面的树

image-20230616095129461

  • 00 表示 a
  • 01 表示 b
  • 1 表示 c

现在还是传递 abbccccccc 这 10 个字符

  • 实际的字节为 000101 1111111 (二进制表示)
  • 总共需要 13 bits,这棵树就称之为 Huffman 树
  • 根据 Huffman 树对字符和数字进行编解码,就是 Huffman 编解码

二.哈夫曼树

1.什么 Huffman 树?

哈夫曼树,英文名 huffman tree,它是一种的叶子节点带有权重的特殊二叉树,也叫最优二叉树。

哈夫曼(Huffman)编码是上个世纪五十年代由哈夫曼教授研制开发的,它借助了数据结构当中的树型结构,在哈夫曼算法的支持下构造出一棵最优二叉树,我们把这类树命名为哈夫曼树。

哈夫曼树是带权路径长度最短的树,权值较大的节点离根较近。

2.哈夫曼树特点

哈夫曼树的特点:

  • 没有度为1的节点(每个非叶子节点都是由两个最小值的节点构成)

  • n 个叶子节点的哈夫曼树总共有2n-1个节点;

  • 哈夫曼树的任意非叶节点的左右子树交换后仍是哈夫曼树

  • 对同一组权值{w1,w2,…},存在不同构的两个哈夫曼树,但是它们的总权值相等。

  • 形成了这样的一颗哈夫曼树,这也是二叉树的前序

3.节点总数证明

证明哈夫曼树中有 n 个叶子节点的树总共有 2n-1 个节点可以使用数学归纳法。以下是证明的步骤:

步骤 1:基础情况
当 n=1 时,只有一个叶子节点,因此整棵哈夫曼树只有一个节点。这是一个基础情况。

步骤 2:归纳假设
假设对于某个正整数 k,当哈夫曼树有 k 个叶子节点时,它总共有 2k-1 个节点。

步骤 3:归纳证明
现在,考虑有 k+1 个叶子节点的情况。我们可以将这个问题分成两个部分:

部分 1: 从 k 个叶子节点构建一个哈夫曼树,根据归纳假设,这个树有 2k-1 个节点。

部分 2: 现在,我们添加一个额外的叶子节点,构建一个新的哈夫曼树。在这个新树中,我们需要添加一个新的内部节点,作为新叶子节点和部分 1 中的树的根节点的父节点。这个新树总共有 2k 个叶子节点和 1 个额外的内部节点,所以共有 2k+1 个节点。

现在,将部分 1 和部分 2 合并在一起,我们得到了有 k+1 个叶子节点的哈夫曼树,总共有(2k-1) + (2k+1) = 2k-1 + 2k+1 = 2(k-1+2) = 2k+1-1 个节点。

这证明了对于 k+1 个叶子节点的情况,有 2k+1-1 个节点,即当 n=k+1 时,也成立。

由于基础情况成立,并且我们已经证明了当 n=k+1 时成立,所以根据数学归纳法,对于所有正整数 n,有 n 个叶子节点的哈夫曼树总共有 2n-1 个节点。

4.Huffman 树特点

哈夫曼树(Huffman Tree)是一种用于数据压缩的树形数据结构,它具有以下几个特点:

  1. 最优编码:哈夫曼树被设计用来实现最优的数据压缩编码,这意味着它可以生成具有最小平均编码长度的编码方案,以便在数据传输或存储时能够节省空间。

  2. 基于频率:哈夫曼树的构建是基于数据中各个字符(或符号)的出现频率来进行的。频率高的字符被赋予较短的编码,而频率低的字符被赋予较长的编码。

  3. 唯一性:对于给定的数据集,存在唯一的哈夫曼树。这意味着如果两个人使用相同的数据集和相同的构建规则来创建哈夫曼树,它们将得到相同的树结构和编码。

  4. 前缀编码:哈夫曼编码是一种前缀编码,意味着没有一个字符的编码是另一个字符编码的前缀。这个特性确保在解码时不会产生歧义。

  5. 树形结构:哈夫曼树是一种二叉树,它由内部节点和叶子节点组成。叶子节点对应于数据集中的字符,而内部节点是用于构建编码的辅助节点。

  6. 压缩率:哈夫曼编码通常能够实现较高的压缩率,尤其是对于具有不同频率分布的数据集。频率高的字符使用较短的编码,从而实现更好的压缩效果。

  7. 动态性:哈夫曼编码可以动态地根据数据集的特性进行调整,以适应不同的数据。这使得它在各种应用中都具有灵活性。

总之,哈夫曼树是一种用于数据压缩的有效工具,其特点包括最优编码、基于频率、唯一性、前缀编码、树形结构、高压缩率和动态性。通过合理构建哈夫曼树,可以实现高效的数据压缩和解压缩操作。

三.常见方法

1.内部 Node 节点

/*** Node代表字符节点*/
static class Node {/*** 字符*/Character ch;/*** 频次*/int freq;/*** 左子节点*/Node left;/*** 右子节点*/Node right;/*** 编码*/String code;public Node(Character ch) {this.ch = ch;}public Node(int freq, Node left, Node right) {this.freq = freq;this.left = left;this.right = right;}int freq() {return freq;}boolean isLeaf() {return left == null;}@Overridepublic String toString() {return "Node{" + "ch=" + ch + ", freq=" + freq + '}';}
}

2.构造方法

public HuffmanTree(String str) {this.str = str;// 功能1:统计字符的频率char[] chars = str.toCharArray();for (char c : chars) {Node node = map.computeIfAbsent(c, Node::new);node.freq++;}// 功能2: 构造树PriorityQueue<Node> queue = new PriorityQueue<>(Comparator.comparingInt(Node::freq));queue.addAll(map.values());while (queue.size() >= 2) {Node x = queue.poll();Node y = queue.poll();int freq = x.freq + y.freq;queue.offer(new Node(freq, x, y));}root = queue.poll();// 功能3:计算每个字符的编码,int sum = dfs(root, new StringBuilder());for (Node node : map.values()) {System.out.println(node + " " + node.code);}// 功能4:字符串编码后占用 bitsSystem.out.println("总共会占用 bits:" + sum);
}private int dfs(Node node, StringBuilder code) {int sum = 0;if (node.isLeaf()) {node.code = code.toString();sum = node.freq * code.length();} else {sum += dfs(node.left, code.append("0"));sum += dfs(node.right, code.append("1"));}if (code.length() > 0) {code.deleteCharAt(code.length() - 1);}return sum;}

3.编码

public String encode() {//abbcccccccchar[] chars = str.toCharArray();StringBuilder sb = new StringBuilder();for (char c : chars) {sb.append(map.get(c).code);}return sb.toString();
}

4.解码

public String decode(String str) {/*从根节点,寻找数字对应的字符数字是 0 向左走数字是 1 向右走如果没走到头,每走一步数字的索引 i++走到头就可以找到解码字符,再将 node 重置为根节点a 00b 10c 1i0   0   0   1   0   1   1   1   1   1   1   1   1*/char[] chars = str.toCharArray();int i = 0;StringBuilder sb = new StringBuilder();Node node = root;//             i = 13  node=root// 0001011111111while (i < chars.length) {if (!node.isLeaf()) { // 非叶子if (chars[i] == '0') { // 向左走node = node.left;} else if (chars[i] == '1') { // 向右走node = node.right;}i++;}if (node.isLeaf()) {sb.append(node.ch);node = root;}}return sb.toString();
}

5.完整代码

/*** Huffman 树的构建过程* 1. 将统计了出现频率的字符,放入优先级队列* 2. 每次出队两个频次最低的元素,给它俩找个爹* 3. 把爹重新放入队列,重复 2~3* 4. 当队列只剩一个元素时,Huffman 树构建完成** @author : qinyingjie* @date : 2023/9/26*/
public class HuffmanTree {/*** Node代表字符节点*/static class Node {/*** 字符*/Character ch;/*** 频次*/int freq;/*** 左子节点*/Node left;/*** 右子节点*/Node right;/*** 编码*/String code;public Node(Character ch) {this.ch = ch;}public Node(int freq, Node left, Node right) {this.freq = freq;this.left = left;this.right = right;}int freq() {return freq;}boolean isLeaf() {return left == null;}@Overridepublic String toString() {return "Node{" + "ch=" + ch + ", freq=" + freq + '}';}}String str;/*** 统计字符数量,key是字符,value是节点*/Map<Character, Node> map = new HashMap<>();/*** 根节点*/Node root;public HuffmanTree(String str) {this.str = str;// 功能1:统计字符的频率char[] chars = str.toCharArray();for (char c : chars) {Node node = map.computeIfAbsent(c, Node::new);node.freq++;}// 功能2: 构造树PriorityQueue<Node> queue = new PriorityQueue<>(Comparator.comparingInt(Node::freq));queue.addAll(map.values());while (queue.size() >= 2) {Node x = queue.poll();Node y = queue.poll();int freq = x.freq + y.freq;queue.offer(new Node(freq, x, y));}root = queue.poll();// 功能3:计算每个字符的编码,int sum = dfs(root, new StringBuilder());for (Node node : map.values()) {System.out.println(node + " " + node.code);}// 功能4:字符串编码后占用 bitsSystem.out.println("总共会占用 bits:" + sum);}private int dfs(Node node, StringBuilder code) {int sum = 0;if (node.isLeaf()) {node.code = code.toString();sum = node.freq * code.length();} else {sum += dfs(node.left, code.append("0"));sum += dfs(node.right, code.append("1"));}if (code.length() > 0) {code.deleteCharAt(code.length() - 1);}return sum;}// 编码public String encode() {//abbcccccccchar[] chars = str.toCharArray();StringBuilder sb = new StringBuilder();for (char c : chars) {sb.append(map.get(c).code);}return sb.toString();}// 解码public String decode(String str) {/*从根节点,寻找数字对应的字符数字是 0 向左走数字是 1 向右走如果没走到头,每走一步数字的索引 i++走到头就可以找到解码字符,再将 node 重置为根节点a 00b 10c 1i0   0   0   1   0   1   1   1   1   1   1   1   1*/char[] chars = str.toCharArray();int i = 0;StringBuilder sb = new StringBuilder();Node node = root;//             i = 13  node=root// 0001011111111while (i < chars.length) {if (!node.isLeaf()) { // 非叶子if (chars[i] == '0') { // 向左走node = node.left;} else if (chars[i] == '1') { // 向右走node = node.right;}i++;}if (node.isLeaf()) {sb.append(node.ch);node = root;}}return sb.toString();}public static void main(String[] args) {HuffmanTree tree = new HuffmanTree("abbccccccc");String encoded = tree.encode();System.out.println(encoded);System.out.println(tree.decode(encoded));}
}

四.练习题

1.连接棒材的最低费用-力扣 1167 题

题目编号题目标题算法思路
1167(Plus 题目)连接棒材的最低费用Huffman 树、贪心

为了装修新房,你需要加工一些长度为正整数的棒材 sticks。

如果要将长度分别为 X 和 Y 的两根棒材连接在一起,你需要支付 X + Y 的费用。

由于施工需要,你必须将所有棒材连接成一根。

返回你把所有棒材 sticks 连成一根所需要的最低费用。注意你可以任意选择棒材连接的顺序。

示例 1:
输入:sticks = [2,4,3]
输出:14
解释:先将 2 和 3 连接成 5,花费 5;再将 5 和 4 连接成 9;总花费为 14。
示例 2:
输入:sticks = [1,8,3,5]
输出:30
提示:
1 <= sticks.length <= 10^4
1 <= sticks[i] <= 10^4

题解

/*** <h3>连接棒材的最低费用</h3>* <p>为了装修新房,你需要加工一些长度为正整数的棒材。如果要将长度分别为 X 和 Y 的两根棒材连接在一起,你需要支付 X + Y 的费用。 返回讲所有棒材连成一根所需要的最低费用。</p>*/
public class Leetcode1167 {/*举例 棒材为 [1,8,3,5]如果以如下顺序连接(非最优)- 1+8=9- 9+3=12- 12+5=17总费用为 9+12+17=38如果以如下顺序连接(最优)- 1+3=4- 4+5=9- 8+9=17总费用为 4+9+17=30*/int connectSticks(int[] sticks) {PriorityQueue<Integer> queue = new PriorityQueue<>();for (int stick : sticks) {queue.offer(stick);}int sum = 0;while (queue.size() >= 2) {Integer x = queue.poll();Integer y = queue.poll();int c = x + y;sum += c;queue.offer(c);}return sum;}public static void main(String[] args) {Leetcode1167 leetcode = new Leetcode1167();System.out.println(leetcode.connectSticks(new int[]{1, 8, 3, 5})); // 30System.out.println(leetcode.connectSticks(new int[]{2, 4, 3})); // 14}
}

觉得有用的话点个赞 👍🏻 呗。
❤️❤️❤️本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄

💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍

🔥🔥🔥Stay Hungry Stay Foolish 道阻且长,行则将至,让我们一起加油吧!🌙🌙🌙

img

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

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

相关文章

汽车电子——产品标准规范汇总和梳理(自动驾驶)

文章目录 前言 一、分级 二、定位 三、地图 四、座舱 五、远程 六、信息数据 七、场景 八、智慧城市 九、方法论 总结 前言 见《汽车电子——产品标准规范汇总和梳理》 一、分级 《GB/T 40429-2021 汽车驾驶自动化分级》 《QC/T XXXXX—XXXX 智能网联汽车 自动驾…

C语言动态内存管理malloc、calloc、realloc、free函数的讲解

一.为什么存在动态内存管理&#xff1a; 我们知道&#xff0c;在此之前向内存申请空间的方式有以下两种&#xff1a;&#xff08;变量和数组&#xff09; 但这两种方法有几个缺陷&#xff1a; ①&#xff1a;空间开辟大小是固定的&#xff1b; ②&#xff1a;数组在声明的时候&…

Qt扫盲-QSqlQueryModel理论总结

QSqlQueryModel理论总结 一、概述二、使用1. 与 view 视图 绑定2. 分离视图&#xff0c;只存数据 一、概述 QSqlQueryModel是用于执行SQL语句和遍历结果集的高级接口。它构建在较低级的 QSqlQuery之上&#xff0c;可用于向QTableView 等视图类提供数据&#xff0c;也是使用了Q…

微信开发者工具appdata\local\微信开发者工具有啥用,能删掉吗?占用空间8G

你好这边 微信开发者工具\User Data 存储的都是一些用户开发者在工具的一些数据存储&#xff0c;不建议全部删除&#xff0c;这样可能你较常用的一些项目记录和缓存信息就会找不到&#xff0c;如果需要清理的话&#xff0c;可以考虑删除&#xff1a; WeappApplication 应用更新…

【Java 基础篇】Java 接口组成与更新详解

在Java编程中&#xff0c;接口&#xff08;interface&#xff09;是一种非常重要的概念。它允许类定义一组抽象方法&#xff0c;这些方法可以在不同的类中实现。接口在Java中起到了重要的角色&#xff0c;被广泛应用于代码的组织和设计中。本文将详细解释Java接口的组成和最新的…

QT 绘画功能的时钟

.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QPaintEvent> #include <QDebug> //信息调试类 #include <QPainter> #include <QPixmap> //图像引擎类 #include <QTime> #include <QTimer> …

crypto:password

题目 下载题目所给的压缩包后解压&#xff0c;可得到文本提示信息 根据key提示&#xff0c;密码为十位 再结合生日和姓名的长度刚好十位&#xff0c;推测密码的组合为姓名字母&#xff0b;生日的组合排列 经过尝试 key为zs19900315 即得flag

详解Nacos和Eureka的区别

文章目录 Eureka是什么Nacos是什么Nacos的实现原理 Nacos和Eureka的区别CAP理论连接方式服务异常剔除操作实例方式自我保护机制 Eureka是什么 Eureka 是Spring Cloud 微服务框架默认的也是推荐的服务注册中心, 由Netflix公司与2012将其开源出来,Eureka基于REST服务开发,主要用…

crypto:摩丝

题目 根据题目所给的压缩包下载后解压&#xff0c;打开文本提示 摩斯密码&#xff0c;对照表可解码得到flag

【RabbitMQ实战】06 3分钟部署一个RabbitMQ集群

一、集群的安装部署 我们还是利用docker来安装RabbitMQ集群。3分钟安装一个集群&#xff0c;开始。 前提条件&#xff0c;docker安装了docker-compose。如果没安装的话&#xff0c;参考这里 docker-compose文件参考bitnami官网&#xff1a;https://github.com/bitnami/contai…

tsar-性能监控工具

简介 tsar是淘宝自己开发的一个采集工具&#xff0c;主要用来收集服务器的系统信息&#xff08;如cpu&#xff0c;io&#xff0c;mem&#xff0c;tcp等&#xff09;&#xff0c;以及应用数据&#xff08;如squid haproxy nginx等&#xff09;。收集到的数据存储在磁盘上&#…

机器人中的数值优化|【四】L-BFGS理论推导与延伸

机器人中的数值优化|【四】L-BFGS理论推导与延伸 往期内容回顾 机器人中的数值优化|【一】数值优化基础 机器人中的数值优化|【二】最速下降法&#xff0c;可行牛顿法的python实现&#xff0c;以Rosenbrock function为例 机器人中的数值优化|【三】无约束优化&#xff0c;拟牛…

OWASP Top 10漏洞解析(1)- A1:Broken Access Control 访问控制失效

作者&#xff1a; gentle_zhou 原文链接&#xff1a;OWASP Top 10漏洞解析&#xff08;1&#xff09;- A1:Broken Access Control 访问控制失效-云社区-华为云 Web应用程序安全一直是一个重要的话题&#xff0c;它不但关系到网络用户的隐私&#xff0c;财产&#xff0c;而且关…

解决电脑桌面软件图标变白的问题

文章目录 前言一、软件图标变白的原因二、解决方法1、显示隐藏项目2、清除图标缓存 前言 桌面软件太多了&#xff0c;导致有些杂乱&#xff0c;换了个显示器后&#xff0c;想着将桌面的软件分类&#xff0c;将其放到不同的目录下&#xff0c;结果有些软件放入文件夹后图标变成…

手把手教你实现:将后端SpringBoot项目部署到华为云服务器上

前言 前提&#xff1a;有一个后端项目&#xff0c;项目能够运行在本地&#xff0c;可以通过本地访问&#xff08;localhost&#xff09; 如果没有可以看这篇&#xff1a;一个基于SpringBoot的后端项目 注册华为云账号 华为云官网 购买云服务器 产品 -> 华为云耀云服务器…

基于微信小程序的民宿短租酒店预订系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言系统主要功能&#xff1a;具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计…

8款常见的自动化测试开源框架

在如今开源的时代&#xff0c;我们就不要再闭门造车了&#xff0c;热烈的拥抱开源吧&#xff01;本文针对性能测试、Web UI 测试、API 测试、数据库测试、接口测试、单元测试等方面&#xff0c;为大家整理了github或码云上优秀的自动化测试开源项目&#xff0c;希望能给大家带来…

CentOS下安装MySQL 8.1及备份配置

1 卸载原来的MySQL版本 移除之前部署的mysql软链接 # unlink /etc/init.d/mysql # unlink /usr/bin/mysql2 下载最新的MySQL版本 https://dev.mysql.com/downloads/mysql/8.0.html 我这里直接把地址放在这里&#xff1a;https://cdn.mysql.com//Downloads/MySQL-8.1/mysql…

IP地址最终弹,DNS,数据链路层,特殊地址

目录 一、特殊地址 二、数据链路层 三、DNS 一、特殊地址 将IP地址中的主机IP全部设置为0&#xff0c;就成了网络号&#xff0c;代表这个局域网&#xff08;不可给具体的设备分配这个IP&#xff09; 将IP地址中的主机IP全部设置为1&#xff0c;就成了广播地址&#xff0c;给同…

初识网络原理

网络发展史 独立模式 计算机之间相互独立 网络互联模式 将多台计算机连接在一起&#xff0c;完成数据共享。 数据共享本质上是网络数据传输,即计算机之间通过网络来传输数据&#xff0c;也称为网络通信。 根据网络互连的规模不同&#xff0c;可以划分为局域网和广域网。 …