#数据结构 笔记三

二叉树

1. 概念

二叉树Binary Treen个结点的有限集合。它或者是空集n=0,或者是由一个根结点以及两颗互不相交、分别称为左子树和右子树的二叉树组成。

二叉树与普通有序树不同,二叉树严格区分左子和右子,即使只有一个子结点也要区分左右。

二叉树的树度数最大为2

2. 性质*

关于树的一些基本念

(1)度数:一个节点的子树的个数(一个节点的子树的个数称为该节点的度数,3)

(2)树度数:树中节点的最大度数

(3)叶节点或终端节点: 度数为零的节点

(4)分支节点:度数不为零的节点(B一层)

(5)内部节点:除根节点以外的分支节点 (B,C,D)

(6)节点层次: 根节点的层次为1,根节点子树的根为第2层,以此类推

(7)树的深度或高度: 树中所有节点层次的最大值 (4)

  1. 二叉树的第k层上的结点最多个2k-1
  2. 深度为k的二叉树最多有2k-1个结点

Sn=a1(1-qn)/(1-q)=a1(1-2k)/(1-2)=(1-2k)/-1=2k-1

  1. 在任意一颗二叉树中,树叶的数目比度数为2的结点数目多1

N:结点的总数

N0:没有子结点的结点个数

N1:只有一个子结点的结点个数

N2:有两个子结点的结点个数

总结点 = 各节点数目之和 N = N0 + N1 + N2

总结点 = 所有子节点 + 根 N = 0 × N0 + 1 × N1 + 2 × N2 + 1

联立以上两式可得: N0 = N2 + 1

(网易)一棵二叉树有8个度为2的节点,5个度为1的节点,那么度为0的节点个数为 ( 9 )

满二叉树和完全二叉树

满二叉树:深度为k(k>=1)时,第k层结点个数为2k-1

完全二叉树:只有最下面两层有度数小于2的节点,且最下面一层的结点集中在最左边的若干位置上。

3. 实现

二叉树的存储结构有两种,分为顺序存储和链式存储

3.1. 顺序存储

二叉树的顺序存储,指的是使用顺序表(数组)存储二叉树。需要注意,顺序存储只适用于完全二叉树。换句话说,只有完全二叉树才可以用顺序表存储。因此,如果我们想要顺序存储普通二叉树,就需要将其提前转换成完全二叉树。

普通二叉树转完全二叉树的方法很简单,只需给二叉树额外添加一些结点,将其"拼凑"成一个完全二叉树即可。

如图所示:

左侧是普通二叉树,右侧是转化后的完全(满)二叉树。

完全(满)二叉树的顺序存储,仅需要从根结点开始,按照层次依次将树中结点存储到数组即可。

存储图 2 所示的完全二叉树:

存储由普通二叉树转化来的完全二叉树也是如此。

图 1 中普通二叉树在顺组中的存储状态如图:

完全二叉树中结点按照层次并从左到右依次编号(123...),若结点i有左子,则其左子的结点编号为2*i,右子编号为2*i+1

设完全二叉树的结点数为n,某结点的编号为i

i>1时(不是根结点时),有父节点,其编号为i/2

2*i <= n时,有左子,其编号为2*i,否则没有左子,没左子一定没右子,其本身为叶节点。

2*i+1 <= n时,有右子,其编号为2*i+1,否则就没有右子。

3.1.1. 遍历*

先序:根----->左----->右

A B D H I E J C F K G

中序:左----->根----->右

H D I B E J A F K C G

后序:左----->右----->根

H I D J E B K F G C A

已知遍历结果如下,试画出对应的二叉树,写出后续:

先序:A B C E H F I J D G K 根----->左----->右

中序:A H E C I F J B D K G 左----->根----->右

因为先序是根在最前面的,所以在先序中从前往后地取结点拿到中序中作为根,循环重复。

3.2. 链式存储

链式存储此二叉树,从根结点开始,将各个结点以及其左右子的地址使用链表进行存储。

3.2.1. 定义操作完全二叉树结构体*

结点结构体由三部分组成:

  1. 指向左子结点的指针(Lchild)
  2. 结点存储的数据(结点编号)
  3. 指向右子结点的指针(Rchild)

// 1. 定义操作二叉树的结构体
typedef char datatype_tree;
typedef struct tree_node_t
{
	datatype_tree data;//数据域
	struct tree_node_t *lchild;//左子left 
	struct tree_node_t *rchild;//右子right 
}bitree_node_t,*bitree_list_t;

3.2.2. 创建二叉树*

#include "bitree.h"

// 2. 创建二叉树
// 主函数传参 n 树中结点总数; i 结点编号(从1开始)
bitree_list_t CreateBitree(int n,int i)
{
    // 2.1 开辟空间存放结构体
	bitree_list_t r = (bitree_list_t)malloc(sizeof(bitree_node_t));

	if(NULL == r)
	{
		printf("CreateBitree malloc failed\n");
		return NULL;
	}
   // 2.2 初始化结构体成员
   // 2.3 判断有无左右子
   // 2.3.1 有左子
	r->data = i;
	if(2 * i <= n)
	{
		r->lchild = CreateBitree(n,2*i);
	}
    // 2.3.2 无左子
	else
	{
		r->lchild = NULL;
	}
   // 2.3.3 有右子
	if(2*i + 1 <= n)
	{
		r->rchild = CreateBitree(n,2*i+1);
	}
   // 2.3.4 无右子
	else
	{
		r->rchild = NULL;
	}
	return r;
}

#include "bitree.h"
int main(int argc, const char *argv[])
{
	bitree_node_t *r = CreateBitree(3,1);
	return 0;
}

3.2.3. 先序遍历*

//前序
// 3. 先序遍历二叉树
// 根——左——右
void PreOrder(bitree_list_t r)
{
	if(NULL == r)
		return;
	printf("%d ",r->data);							 // 根
 // 如果有左子,则将左子作为根将该函数的全部操作走一遍
	if(r->lchild != NULL)							 // 左
		PreOrder(r->lchild);
// 如果有右子,则将右子作为根将该函数的全部操作走一遍
	if(r->rchild != NULL)
		PreOrder(r->rchild);						 // 右
}

3.2.4. 中序遍历

// 4. 中序遍历
// 左——根——右
void InOrder(bitree_list_t r)
{
	if(NULL == r)
		return;
    // 如果有左子,则将左子作为根将该函数的全部操作走一遍
	if(r->lchild != NULL)								 // 左
		InOrder(r->lchild);
	printf("%d ",r->data);								 // 根
    // 如果有右子,则将右子作为根将该函数的全部操作走一遍
	if(r->rchild != NULL)
	InOrder(r->rchild);									 // 右
}

3.2.5. 后序遍历

// 5. 后序遍历
// 左——右——根
void PostOrder(bitree_list_t r)
{
    if(NULL == r)
		return;

    // 如果有左子,则将左子作为根将该函数的全部操作走一遍
    if (r->lchild != NULL)                           // 左
        PostOrder(r->lchild);

    // 如果有右子,则将右子作为根将该函数的全部操作走一遍
    if (r->rchild != NULL)                           // 右
        PostOrder(r->rchild);

    printf("%d\t", r->data);                         // 根
}

总结:

#include "bitree.h"
bitree_list_t CreateBitree(int n,int i)
{

	bitree_list_t r = (bitree_list_t)malloc(sizeof(bitree_node_t));
	if(NULL == r)
	{
		printf("CreateBitree malloc failed\n");
		return NULL;
	}
	r->data = i;

	if(2 * i <= n)
	{
		r->lchild = CreateBitree(n,2*i);
	}
	else
	{
		r->lchild = NULL;
	}

	if(2*i + 1 <= n)
	{
		r->rchild = CreateBitree(n,2*i+1);
	}
	else
	{
		r->rchild = NULL;
	}
	return r;
}
//前序
void PreOrder(bitree_list_t r)
{
	if(NULL == r)
		return;

	printf("%d ",r->data);
	if(r->lchild != NULL)
		PreOrder(r->lchild);
	if(r->rchild != NULL)
		PreOrder(r->rchild);
}
//中序
void InOrder(bitree_list_t r)
{
	if(NULL == r)
		return;
	if(r->lchild != NULL)
		InOrder(r->lchild);
	printf("%d ",r->data);
	if(r->rchild != NULL)
	InOrder(r->rchild);
}
//后序
void PostOrder(bitree_list_t r)
{
	if(NULL == r)
		return;
	if(r->lchild != NULL)
		PostOrder(r->lchild);
	if(r->rchild != NULL)
		PostOrder(r->rchild);
	printf("%d ",r->data);

}
#include "bitree.h"
int main(int argc, const char *argv[])
{	
	bitree_node_t *r = CreateBitree(3,1);
	PreOrder(r);	
	printf("\n");
	InOrder(r);
	printf("\n");
	PostOrder(r);
	printf("\n");
	return 0;
}
#ifndef _BITREE_H_
#define _BITREE_H_
#include <stdio.h>
#include <stdlib.h>
typedef char datatype_tree;
typedef struct tree_node_t
{
	datatype_tree data;//数据域
	struct tree_node_t *lchild;//左子left 
	struct tree_node_t *rchild;//右子right 
}bitree_node_t,*bitree_list_t;
bitree_list_t CreateBitree(int n,int i);
//前序
void PreOrder(bitree_list_t r);
//中序
void InOrder(bitree_list_t r);
//后序
void PostOrder(bitree_list_t r);
//层次
void unOrder(bitree_list_t r);
#endif	

3.2.6. 层序遍历

队列的思想

不需要敲代码,看懂就行

示意图

#ifndef _BITREE_H_
#define _BITREE_H_
typedef char datatype_tree;
typedef struct tree_node_t
{
	datatype_tree data;//数据域 
	struct tree_node_t *lchild;//左子指针
	struct tree_node_t *rchild;//右子指针
}bitree_t;
//前序遍历
void preOrder(bitree_t *r);//r二叉树根节点的指针
//中序遍历
void inOrder(bitree_t * r);
//后序遍历
void postOrder(bitree_t *r);
//遍历二叉树 
//s 代表的是打印提示, void (*p)(bitree_t *)函数指针  r遍历的树
void showBitree(char *s,void (*p)(bitree_t *),bitree_t *r);
//创建二叉树,用递归函数创建
bitree_t *createBitree();
//层次遍历
void unOrder(bitree_t *r);
#endif
#ifndef _LINKQUEUE_H_
#define _LINKQUEUE_H_

#include "bitree.h"

//将 bitree_t * 改名 为datatype_linkqueue 
typedef bitree_t * datatype_linkqueue;//把队列的数据域变成指向树节点的指针
typedef struct node
{
	datatype_linkqueue data;//数据域
	struct node *next;//指针域
}linkqueue_node_t,*linkqueue_list_t;

//linkqueue_list_t p === linkqueue_node_t *
typedef struct//将队列头指针和尾指针封装到一个结构体里
{
	linkqueue_list_t front;//相当于队列的头指针
	linkqueue_list_t rear;//相当于队列的尾指针
	//有了链表的头指针和尾指针,那么我们就可以操作这个链表
}linkqueue_t;

//1.创建一个空的队列
linkqueue_t *createEmptyLinkQueue();
//2.入列 data代表入列的数据
int inLinkQueue(linkqueue_t *p,datatype_linkqueue data);
//3.出列 
datatype_linkqueue outLinkQueue(linkqueue_t *p);
//4.判断队列是否为空
int isEmptyLinkQueue(linkqueue_t *p);
//5.求队列长度的函数
int lengthLinkQueue(linkqueue_t *p);
//6.清空队列
void clearLinkQueue(linkqueue_t *p);
#endif
#include "bitree.h"
#include "linkqueue.h"
#include <stdio.h>
#include <stdlib.h>
//前序遍历
void preOrder(bitree_t *r)//r二叉树根节点的指针
{
	if(r == NULL)//递归函数的结束条件
		return;
	printf("%c ",r->data);//根
	preOrder(r->lchild);//左
	preOrder(r->rchild);//右
}
//中序遍历
void inOrder(bitree_t * r)
{
	if(r == NULL)//递归的结束条件
		return;
	inOrder(r->lchild);//左
	printf("%c ",r->data);//根
	inOrder(r->rchild);//右
}
//后序遍历
void postOrder(bitree_t *r)
{
	if(r == NULL)//递归函数的结束条件
		return;
	postOrder(r->lchild);//左
	postOrder(r->rchild);//右
	printf("%c ",r->data);//根
}
//遍历二叉树 
//s 代表的是打印提示, void (*p)(bitree_t *)函数指针  r遍历的树
void showBitree(char *s,void (*p)(bitree_t *),bitree_t *r)
{
	printf("%s",s);
	p(r);
	printf("\n");
}
//创建二叉树,用递归函数创建
bitree_t *createBitree()
{//root 
//	ABD###CE##F##
	bitree_t *r = NULL;//用来保存二叉树的根节点
	char ch;
	scanf("%c",&ch);
	if(ch == '#')//输入是'#',代表没有左子或右子
		return NULL;
	r = (bitree_t *)malloc(sizeof(bitree_t));
	if(NULL == r)
	{
		perror("r malloc failed");
		return NULL;
	}
	r->data = ch;
	r->lchild = createBitree();
	r->rchild = createBitree();
	return r;
}

//层次遍历
void unOrder(bitree_t *r)
{
	//1.创建一个队列,队列的数据域变成指向树节点的指针
	linkqueue_t *p = createEmptyLinkQueue();
	if(r != NULL)
		inLinkQueue(p,r);
	//2.循环打印
	while(!isEmptyLinkQueue(p))
	{
		r = outLinkQueue(p);
		printf("%c ",r->data);
		if(r->lchild != NULL)//只要左子不为空,就入列,之后出列的时候打印
			inLinkQueue(p,r->lchild);
		if(r->rchild != NULL)//只要右子不为空,就入列,之后出列的时候打印
			inLinkQueue(p,r->rchild);
	}
}
#include "linkqueue.h"
#include <stdio.h>
#include <stdlib.h>

//1.创建一个空的队列
linkqueue_t *createEmptyLinkQueue()
{
	linkqueue_t *p = (linkqueue_t *)malloc(sizeof(linkqueue_t));
	if(NULL == p)
	{
		perror("createEmptyLinkQueue p malloc failed");
		return NULL;
	}//申请空间就是为了装东西
	//申请链表的头节点空间,让rear和front都指向头结点
	p->front = p->rear = (linkqueue_list_t)malloc(sizeof(linkqueue_node_t));
	if(NULL == p->rear)
	{
		perror("p->rear malloc failed");
		return NULL;
	}
	p->rear->next = NULL;//或者用p->front->next = NULL;因为p->rear 和 p->front 指向同一个位置即头节点
	return p;
}
//2.入列 data代表入列的数据
int inLinkQueue(linkqueue_t *p,datatype_linkqueue data)
{
	//1.创建一个新的节点,用来保存即将插入的数据
	linkqueue_list_t pnew = (linkqueue_list_t)malloc(sizeof(linkqueue_node_t));
	if(NULL == pnew)
	{
		perror("inLinkQueue pnew malloc failed");
		return -1;
	}
	//2.将入列的数据放入到新的节点中
	pnew->data = data;
	pnew->next = NULL;
	//3.将新节点链链接到链表的尾巴
	p->rear->next = pnew;//新节点链接到链表的尾
	p->rear = pnew;//rear移动,因为rear永远指向当前链表的尾
	return 0;
}
//3.出列 
datatype_linkqueue outLinkQueue(linkqueue_t *p)
{
	linkqueue_list_t pdel = NULL;//指向被删除的节点
	//1.容错判断
	if(isEmptyLinkQueue(p))
	{
		printf("isEmptyLinkQueue !!\n");
		return NULL;
	}
	//2.出列数据
	//(1)定义pdel指向即将被删除的节点就是front指向的节点,出列每次删除的都是front指向的那个节点
	pdel = p->front;
	//(2)将front向后移动一个位置
	p->front = p->front->next;
	//(3)释放被删除节点
	free(pdel);
	pdel = NULL;
	//(4)将数据出列
	return p->front->data;
}
//4.判断队列是否为空
int isEmptyLinkQueue(linkqueue_t *p)
{
	return p->front == p->rear;
}
//5.求队列长度的函数
int lengthLinkQueue(linkqueue_t *p)
{
	int len = 0;
	linkqueue_list_t h = p->front;//将链表的头指针保存的地址给h,如果直接用front,求长度之后会找不到链表的头,用h的移动代替front的移动
	//求长度,相当于遍历有头的单向链表
	while(h->next != NULL)
	{
		h = h->next;
		len++;
	}
	return len;
}
//6.清空队列
void clearLinkQueue(linkqueue_t *p)
{
	while(!isEmptyLinkQueue(p))//只要不为空,就出列
		outLinkQueue(p);
}
#include "bitree.h"
#include <stdio.h>
#include <stdlib.h>

int main(int argc, const char *argv[])
{
	bitree_t *r = createBitree();
	showBitree("前序:",preOrder,r);
	showBitree("中序:",inOrder,r);
	showBitree("后序:",postOrder,r);
	showBitree("层次:",unOrder,r);
	return 0;
}

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

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

相关文章

AR视频技术与EasyDSS流媒体视频管理平台:打造沉浸式视频体验

随着增强现实&#xff08;AR&#xff09;技术的飞速发展&#xff0c;其在各个领域的应用日益广泛。这项技术通过实时计算摄影机影像的位置及角度&#xff0c;将虚拟信息叠加到真实世界中&#xff0c;为用户带来超越现实的感官体验。AR视频技术不仅极大地丰富了我们的视觉体验&a…

3.js - premultiplyAlpha

你瞅啥啊&#xff01;&#xff01;&#xff01; 先看效果图吧 代码 // ts-nocheck // 引入three.js import * as THREE from three // 导入轨道控制器 import { OrbitControls } from three/examples/jsm/controls/OrbitControls // 导入lil.gui import { GUI } from three/ex…

万字总结随机森林原理、核心参数以及调优思路

万字总结随机森林原理、核心参数以及调优思路 在机器学习的世界里&#xff0c;随机森林&#xff08;Random Forest, RF&#xff09;以其强大的预测能力和对数据集的鲁棒性而备受青睐。作为一种集成学习方法&#xff0c;随机森林通过构建多个决策树并将它们的预测结果进行汇总&…

高精度定位技术:赋能电网智能化转型的新引擎

在当今社会&#xff0c;电力作为经济发展的血脉&#xff0c;其稳定高效运行对于国家能源安全与社会发展至关重要。随着科技的飞速进步&#xff0c;高精度定位技术正逐步渗透至电网管理的各个环节&#xff0c;成为推动电网智能化转型的关键力量。本文将深入探讨高精度定位技术在…

下载安装MySQL

1.软件的下载 打开官网下载mysql-installer-community-8.0.37.0.msi 2.软件的安装 mysql下载完成后&#xff0c;找到下载文件&#xff0c;双击安装 3.配置环境变量 4.自带客户端登录与退出

B站大课堂-自动化精品视频(个人存档)

基础知识 工业通信协议 Modbus 施耐德研发&#xff0c;有基于以太网的 ModbusTCP 协议和使用 485/232 串口通信的 ModbusRTU/ASCII。 Modbus 协议面世较早、协议简洁高效、商用免费、功能灵活、实现简单&#xff0c;是目前应用最广泛的现场总线协议。 我的笔记里边有一些推荐…

利用自定义注解,反射,cglib代理实现spring框架的IOC

对比jdk代理&#xff0c;cglib不用实现任何接口&#xff0c;使用的范围更宽广。cglib实质上是创建了目标对象类的子类对象。 使用自定义注解MyService和MyTransactional代替spring框架提供的注解Service Transactional 创建自定义注解类MyService 创建自定义注解类MyTransacti…

收银系统源码-收银台营销功能-购物卡

1. 功能描述 购物卡&#xff1a;基于会员的电子购物卡&#xff0c;支持设置时效、适用门店、以及可用商品&#xff1b;支持售卖和充值赠送&#xff0c;在收银台可以使用&#xff1b; 2.适用场景 会员充值赠送活动&#xff0c;例如会员充值1000元&#xff0c;赠送面值100元购…

Android广播机制

简介 某个网络的IP范围是192.168.0.XXX&#xff0c;子网 掩码是255.255.255.0&#xff0c;那么这个网络的广播地址就是192.168.0.255。广播数据包会被发送到同一 网络上的所有端口&#xff0c;这样在该网络中的每台主机都将会收到这条广播。为了便于进行系统级别的消息通知&…

145-四路16位125Msps AD FMC子卡模块

一、概述 该板卡可实现4路16bit 125Msps AD 功能&#xff0c;是xilinx开发板设计的标准板卡。FMC连接器是一种高速多pin的互连器件&#xff0c;广泛应用于板卡对接的设备中&#xff0c;特别是在xilinx公司的所有开发板中都使用。该AD&#xff0c;DA子卡模块就专门针对xilinx开发…

64.函数参数和指针变量

目录 一.函数参数 二.函数参数和指针变量 三.视频教程 一.函数参数 函数定义格式&#xff1a; 类型名 函数名(函数参数1,函数参数2...) {代码段 } 如&#xff1a; int sum(int x&#xff0c;int y) {return xy; } 函数参数的类型可以是普通类型&#xff0c;也可以是指针类…

windows环境下创建python虚拟环境

windows环境下创建python虚拟环境 使用virtualenv库创建虚拟环境&#xff0c;可使不同的项目处于不同的环境中 安装方法&#xff1a; pip install virtualenv -i https://pypi.tuna.tsinghua.edu.cn/simple pip install virtualenvwrapper-win -i https://pypi.tuna.tsinghua…

【UE5.3】笔记7 控制Pawn移动

使用A、D键控制角色左右移动 打开我们的BP_Player蓝图类&#xff0c;选择事件图表&#xff0c;添加我们的控制事件 右键&#xff0c;搜索A keyboard&#xff0c;选择A,如下图&#xff0c;D也是 添加扭矩力 首先我们要把我们的player上的模拟物理选项打开&#xff0c;这样我们…

SAPUI5基础知识10 - i18与国际化

1. 背景 i18n 是 “internationalization” 的缩写&#xff0c;其中的 18 是 “internationalization” 这个单词中间的字符数。i18n 是一种让应用程序支持多种语言的方法&#xff0c;也就是我们通常所说的国际化。 在SAPUI5中&#xff0c;i18n主要通过使用资源模型&#xff…

Matplotlib 文本

可以使用 xlabel、ylabel、text向图中添加文本 mu, sigma 100, 15 x mu sigma * np.random.randn(10000)# the histogram of the data n, bins, patches plt.hist(x, 50, densityTrue, facecolorg, alpha0.75)plt.xlabel(Smarts) plt.ylabel(Probability) plt.title(Histo…

【️讲解下Laravel为什么会成为最优雅的PHP框架?】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

540. 有序数组中的单一元素(中等)

540. 有序数组中的单一元素 1. 题目描述2.详细题解3.代码实现3.1 Python3.2 Java 1. 题目描述 题目中转&#xff1a;540. 有序数组中的单一元素 2.详细题解 方法一&#xff1a;若不限定时间复杂度&#xff0c;则扫描遍历一遍即可找到仅出现一次的数&#xff0c;具体实现见Pyth…

Maven Archetype 自定义项目模板:高效开发的最佳实践

文章目录 前言一、Maven Archetype二、创建自定义 Maven Archetype三、定制 Archetype 模板四、手动创建 Archetype 模板项目五、FAQ5.1 如何删除自定义的模板5.2 是否可以在模板中使用空文件夹 六、小结推荐阅读 前言 在软件开发中&#xff0c;标准化和快速初始化项目结构能够…

什么是JSON ,ajax和json关系

一. JSON 1 JSON概述 JavaScript对象文本表示形式&#xff08;JavaScript Object Notation : js对象简写) json是js对象 json是目前 前后端数据交互的主要格式之一 * java对象表示形式User user new User();user.setUsername("后羿");user.setAge(23);user.setSex…

开发国际短剧系统的策略解析

一、明确项目目标和需求 1、功能需求&#xff1a;确定系统应具备的基本功能&#xff0c;如用户注册、登录、浏览短剧、评论、分享、个性化推荐等。 2、性能需求&#xff1a;确保系统能够承受高并发访问&#xff0c;保证视频流畅播放&#xff0c;减少卡顿和延迟。 3、跨文化传播…