【数据结构】图的实现

news/2024/5/18 12:23:13/文章来源:https://blog.csdn.net/qq_53893431/article/details/128135395

文章目录

      • 1.图的基本概念
      • 2.图的存储结构
      • 3.邻接矩阵
        • 3.1邻接矩阵的优缺点
        • 3.2邻接矩阵的实现
      • 4.邻接表
        • 4.1邻接表的实现
      • 5.图的遍历
        • 5.1广度优先遍历
        • 5.2深度优先遍历
        • 5.3如何遍历不连通的图?

1.图的基本概念

图是由顶点集合及顶点间的关系组成的一种数据结构:G = (V, E),其中:

  • 顶点集合V = {x|x属于某个数据对象集}是有穷非空集合;
  • E = {(x,y)|x,y属于V}或者E = {<x, y>|x,y属于V && Path(x, y)}是顶点间关系的有穷集合,也叫
    做边的集合。
  • (x, y)表示x到y的一条双向通路,即(x, y)是无方向的;Path(x, y)表示从x到y的一条单向通路,即Path(x, y)是有方向的。

图相关的概念

  • 顶点和边:图中结点称为顶点,第i个顶点记作vi。两个顶点vi和vj相关联称作顶点vi和顶点vj之间有一条边,图中的第k条边记作ek,ek = (vi,vj)或<vi,vj>。
  • 有向图和无向图:在有向图中,顶点对<x, y>是有序的,顶点对<x,y>称为顶点x到顶点y的一条边(弧),<x, y>和<y, x>是两条不同的边,比如下图G3和G4为有向图;在无向图中,顶点对(x, y)是无序的,顶点对(x,y)称为顶点x和顶点y相关联的一条边,这条边没有特定方向,(x, y)和(y,x)是同一条边,比如下图G1和G2为无向图。注意:无向边(x, y)等于有向边<x, y>和<y, x>。

image-20221130233546990

完全图

  • 无向完全图:即图中每两个顶点都有边。在有n个顶点的无向图中,若有n * (n-1)/2条边,即任意两个顶点之间有且仅有一条边,则称此图为无向完全图 。
  • 有向完全图:在n个顶点的有向图中,若有n * (n-1)条边,即任意两个顶点之间有且仅有方向相反的边,则称此图为有向完全图。

顶点的度

  • 顶点的度:顶点v的度是指与它相关联的边的条数,记作deg(v)。在有向图中,顶点的度等于该顶点的入度与出度之和。在无向图中顶点的度等于该顶点的入度和出度,即dev(v)=indev(v) = outdev(v)。

路径

  • 路径:在图G = (V, E)中,若从顶点vi出发有一组边使其可到达顶点vj,则称顶点vi到顶点vj的顶点序列为从顶点vi到顶点vj的路径
  • 路径长度:对于不带权的图,一条路径的路径长度是指该路径上的边的条数;**对于带权的图,一条路径的路径长度是指该路径上各个边权值的总和。 **

image-20221130235744933

子图

子图:设图G = {V, E}和图G1 = {V1,E1},若V1属于V且E1属于E,则称G1是G的子图。

image-20221130235927698

**连通图:**在无向图中,若从顶点v1到顶点v2有路径,则称顶点v1与顶点v2是连通的。如果图中任
意一对顶点都是连通的,则称此图为连通图。

**强连通图:**在有向图中,若在每一对顶点vi和vj之间都存在一条从vi到vj的路径,也存在一条从vj
到vi的路径,则称此图是强连通图

生成树:一个连通图的最小连通子图称作该图的生成树。有n个顶点的连通图的生成树有n个顶点
和n-1条边。

2.图的存储结构

图的存储方式主要有两种,一种叫邻接矩阵,一种叫做邻接表。

3.邻接矩阵

因为节点与节点之间的关系就是连通与否,即为0或者1,因此邻接矩阵(二维数组)即是:先用一
个数组将定点保存,然后采用矩阵来表示节点与节点之间的关系。

无向图

image-20221201000759319

有向图

image-20221201000814567

注意:

无向图的邻接矩阵是一个对称图;第i行(列)元素之和,就是顶点i的度。有向图的邻接矩阵则不一
定是对称的,第i行(列)元素之后就是顶点i 的出(入)度。

带权图

对于有权值的图:边的关系就用权值代替,如果两个顶点不通,则使用无穷大代替。

image-20221201001552642

3.1邻接矩阵的优缺点

优点:

  • 能够快速知道两个顶点是否连通。

缺点:

  • 顶点比较多,边比较少时,矩阵中存储了大量的0成为系数矩阵,比较浪费空间,并且要求两个节点之间的路径不是很好求。

3.2邻接矩阵的实现

基本接口框架:包括构造函数,边的添加函数,返回下标等

namespace matrix
{template <class V, class W, W MAX_W = INT64_MAX, bool Direction = false>class Graph{struct edge{size_t _srci; //起点下标size_t _dsti; //指向下标W _w;         //权值edge(size_t srci, size_t dsti, W w) : _srci(srci), _dsti(dsti), _w(w){}bool operator>(const edge &e) const{return _w > e._w;}};typedef Graph<V, W, MAX_W, Direction> self;public:Graph() = default;//构造函数Graph(const V *v, size_t n){_vertexs.reserve(n);for (size_t i = 0; i < n; i++){_vertexs.push_back(v[i]);_indexmap[v[i]] = i;}//为存储边的矩阵开辟空间_matrix.resize(n);for (size_t i = 0; i < _matrix.size(); i++){_matrix[i].resize(n, MAX_W);}}//返回顶点的下标size_t GetVertexIndex(const V &v);//边的添加函数void addedge(const V &src, const V &dst, const W &w);//打印邻接矩阵函数void Print();private:unordered_map<V, int> _indexmap; //记录顶点和下标的映射关系vector<V> _vertexs;              // 顶点集合的集合vector<vector<W>> _matrix;       // 存储边集合的矩阵};
}

返回顶点的下标

顶点和顶点下标的映射关系,由一个Hash表存储。可以直接访问Hash表得到顶点的下标

//获取顶点的下标API
size_t GetVertexIndex(const V &v)
{auto it = _indexmap.find(v);if (it != _indexmap.end()){return _indexmap[v];}else{std::cout << "不存在这样的节点" << std::endl;return -1;}
}

添加边API

添加边时,需要判断图是否为有向图。如果是一个无向图,那么天需要添加两次。

void _addedge(size_t srci, size_t dsti, const W &w)
{_matrix[srci][dsti] = w;if (Direction == false){_matrix[dsti][srci] = w;}
}
void addedge(const V &src, const V &dst, const W &w)
{size_t srci = GetVertexIndex(src);size_t dsti = GetVertexIndex(dst);assert(srci != -1);assert(dsti != -1);_addedge(srci, dsti, w);
}

打印临界矩阵

如果两个顶点直接没有边,就使用*表示

void Print()
{//先打印顶点for (int i = 0; i < _vertexs.size(); i++){cout << "[" << i << "]"<< "->" << _vertexs[i]<<endl;}cout << endl;// 横下标cout << "  ";for (size_t i = 0; i < _vertexs.size(); ++i){// cout << i << " ";printf("%4d", i);}cout << endl;for (size_t i = 0; i < _matrix.size(); ++i){cout << i << " "; // 竖下标for (size_t j = 0; j < _matrix[i].size(); ++j){// cout << _matrix[i][j] << " ";if (_matrix[i][j] == MAX_W){// cout << "* ";printf("%4c", '*');}else{// cout << _matrix[i][j] << " ";printf("%4d", _matrix[i][j]);}}cout << endl;}cout << endl;
}

接口测试结果

void test_matrix(){matrix::Graph<char, int, INT64_MAX, true> g("0123", 4);g.addedge('0', '1', 1);g.addedge('0', '3', 4);g.addedge('1', '3', 2);g.addedge('1', '2', 9);g.addedge('2', '3', 8);g.addedge('2', '1', 5);g.addedge('2', '0', 3);g.addedge('3', '2', 6);g.Print();
}
int main()
{test_matrix();return 0;
}

image-20221201013812819

4.邻接表

邻接表:使用数组表示顶点的集合,使用链表表示边的关系。

无向图邻接表

image-20221201130808813

**注意:**无向图中同一条边在邻接表中出现了两次。如果想知道顶点vi的度,只需要知道顶点vi边链表集合中结点的数目即可。

有向图邻接表

image-20221201140055317

**注意:**有向图中每条边在邻接表中只出现一次,与顶点vi对应的邻接表所含结点的个数,就是该顶点的出度,也称出度表,要得到vi顶点的入度,必须检测其他所有顶点对应的边链表,看有多少边顶点的dst取值是i。

4.1邻接表的实现

基本接口框架:包括构造函数,边的添加函数,返回下标等;

namespace link_table
{template <class V, class W, W MAX_W = INT64_MAX, bool Direction = false>class Graph{typedef Graph<V, W, MAX_W, Direction> self;struct edge{//由于是链表,起点就是当前点,所以一般都省略// int _srci;size_t _dsti; //目标点W _w;        //权值//用一个链表将于该顶点相连的顶点连接起来edge *_next;edge(size_t dsti, const W& w): _dsti(dsti), _w(w), _next(nullptr){}};public://构造函数Graph() = default;Graph(const V *a, size_t n){_vertexs.reserve(n);//添加顶点for (size_t i = 0; i < n; i++){_vertexs.push_back(a[i]);_indexmap[a[i]] = i;}_tables.resize(n, nullptr);}//获取顶点的下标size_t GetVertexIndex(const V &v);//添加边的APIvoid addedge(const V &src, const V &dst, const W &w);//打印接口APIvoid Print();private:unordered_map<V, int> _indexmap; //记录顶点和下标的映射关系vector<V> _vertexs;              // 顶点集合的集合vector<edge *> _tables;          //邻接表};
};

获取顶点的下标

顶点和顶点下标的映射关系,由一个Hash表存储。可以直接访问Hash表得到顶点的下标。

//获取顶点的下标
size_t GetVertexIndex(const V &v)
{auto it = _indexmap.find(v);if (it != _indexmap.end()){return _indexmap[v];}else{std::cout << "不存在这样的节点" << std::endl;return -1;}
}

添加边

//添加边
void addedge(const V &src, const V &dst, const W &w)
{size_t srci = GetVertexIndex(src);size_t dsti = GetVertexIndex(dst);//头插的方式edge *head = _tables[srci];edge *eg = new edge(dsti, w);eg->_next = head;_tables[srci] = eg;//如果是无向图if (Direction == false){edge *eg = new edge(srci, w);eg->_next = _tables[dsti];_tables[dsti] = eg;}
}

打印邻接表

void Print()
{//打印顶点for (size_t i = 0; i < _vertexs.size(); i++){cout << "[" << i << "]"<< "->" << _vertexs[i] << endl;}//打印边for (size_t i = 0; i < _tables.size(); i++){cout << _vertexs[i] << "[ " << i << "]->";edge *cur = _tables[i];while (cur){cout << "[" << _vertexs[cur->_dsti] << ":" << cur->_dsti << ":" << cur->_w << "]->";cur = cur->_next;}cout << "nullptr" << endl;}
}

测试邻接表的实现

void test_table()
{string a[] = {"张三", "李四", "王五", "赵六"};link_table::Graph<string, int> g1(a, 4);g1.addedge("张三", "李四", 100);g1.addedge("张三", "王五", 200);g1.addedge("王五", "赵六", 30);g1.Print();
}
int main()
{test_table();return 0;
}

image-20221201151708559

5.图的遍历

图的遍历有两种方式,一种是广度优先遍历(BFS),另一种是深度优先遍历(DFS)。下面以邻接矩阵为例,实现图的广度优先遍历和深度优先遍历。

5.1广度优先遍历

比如现在你需要找你的钥匙,有三个抽屉,东西在哪个抽屉不清楚,现在要将其找到,广度优先遍历的做法是:

  • 先将三个抽屉打开,在三个抽屉的最外层找一遍
  • 依次打开三个抽屉的第二层,再找一遍。
  • 如果没有找到,依次打开第三个抽屉的第三层,再找一边…
  • 重复上面的操作,直到找到钥匙…

image-20221201152535817

邻接矩阵的广度优先遍历实现

思路:像树的层序遍历一样,借助一个队列实现广度遍历。

image-20221201153122462

但是可能会出现重复遍历的问题,造成死循环。

解决办法:使用一个标记数组,记录顶点是否已经被遍历。如果顶点已经被遍历,则不再入队列。

image-20221201154220153

void BFS(const V &src)
{size_t srci = GetVertexIndex(src);//遍历队列queue<int> q;//标记数组vector<bool> visited(_vertexs.size(), false);q.push(srci);visited[srci] = true;int n = _vertexs.size();int num = 0;int size = 1;while (!q.empty()){cout << "第" << num << "层:" << endl;for (int i = 0; i < size; i++){int front = q.front();q.pop();cout << front << ":" << _vertexs[front] << " ";for (int i = 0; i < n; i++){if (_matrix[front][i] != MAX_W && !visited[i]){q.push(i);visited[i] = true;}}cout << endl;}num++;size = q.size();}cout << endl;
}

测试程序

void test_matrix()
{matrix::Graph<char, int, INT64_MAX, false> g("ABCDEFGHI", 9);g.addedge('A','B',1);g.addedge('A','C',1);g.addedge('A','D',1);g.addedge('B','E',1);g.addedge('B','C',1);g.addedge('C','F',1);g.addedge('D','F',1);g.addedge('E','G',1);g.addedge('F','H',1);g.addedge('H','I',1);g.Print();g.BFS('A');
}

image-20221201161456928

美团的面试题:六度人脉理论

image-20221201163507488

这个题的思路需要用到广度优先遍历,每一层就是小点的一度人脉。

void test_matrix()
{string name[]={"小美","小团","小卓","小越","小诚","小信"};matrix::Graph<string, int> g(name, 6);g.addedge("小美","小团",1);g.addedge("小美","小卓",1);g.addedge("小美","小诚",1);g.addedge("小团","小诚",1);g.addedge("小卓","小越",1);g.addedge("小卓","小信",1);g.addedge("小信","小越",1);g.BFS("小美");
}

image-20221201164456383

5.2深度优先遍历

image-20221201163100588

深度优先遍历的遍历顺序与顶点插入顺序有关,不同的插入顺序可能有不同的遍历结果。

image-20221201163312306

void _DFS(size_t srci, vector<bool> &visited)
{cout << srci << ":" << _vertexs[srci] << " ";visited[srci] = true;for (int i = 0; i < _vertexs.size(); i++){if (_matrix[srci][i] != MAX_W && !visited[i]){_DFS(i, visited);}}
}
void DFS(const V &src)
{size_t srci = GetVertexIndex(src);vector<bool> visited(_vertexs.size(), false);_DFS(srci, visited);cout << endl;
}

测试结果

void test_matrix()
{matrix::Graph<char, int, INT64_MAX, false> g("ABCDEFGHI", 9);g.addedge('A','B',1);g.addedge('A','C',1);g.addedge('A','D',1);g.addedge('B','E',1);g.addedge('B','C',1);g.addedge('C','F',1);g.addedge('D','F',1);g.addedge('E','G',1);g.addedge('F','H',1);g.addedge('H','I',1);g.Print();g.DFS('A');
}

image-20221201163417801

5.3如何遍历不连通的图?

image-20221201164644666

比如上面的图:

在进行图的遍历的时候,我们使用了一个遍历数组记录该顶点是否被遍历。

如何遍历不连通的图:在bool数组中寻找还没有遍历过的点进行遍历。

以上面的图为例:

void test_matrix()
{matrix::Graph<char, int> g("ABCDEFGHI",9);g.addedge('A','B',1);g.addedge('A','D',1);g.addedge('B','E',1);g.addedge('E','G',1);g.addedge('C','F',1);g.addedge('F','H',1);g.addedge('H','I',1);g.BFS('A');
}

广度优先遍历

void _BFS(size_t srci, vector<bool> &visited)
{//遍历队列queue<int> q;q.push(srci);visited[srci] = true;int n = _vertexs.size();int num = 0;int size = 1;while (!q.empty()){cout << "第" << num << "层:" << endl;for (int i = 0; i < size; i++){int front = q.front();q.pop();cout << front << ":" << _vertexs[front] << " ";for (int i = 0; i < n; i++){if (_matrix[front][i] != MAX_W && !visited[i]){q.push(i);visited[i] = true;}}cout << endl;}num++;size = q.size();}cout << endl;
}void BFS(const V &src)
{//标记数组vector<bool> visited(_vertexs.size(), false);size_t srci = GetVertexIndex(src);_BFS(srci, visited);for (int i = 0; i < visited.size(); i++){if (!visited[i]){cout << endl;_BFS(i, visited);}}
}

image-20221201170049423

深度优先遍历

void _DFS(size_t srci, vector<bool> &visited)
{cout << srci << ":" << _vertexs[srci] << " ";visited[srci] = true;for (int i = 0; i < _vertexs.size(); i++){if (_matrix[srci][i] != MAX_W && !visited[i]){_DFS(i, visited);}}
}
//非连通图的遍历
void DFS(const V &src)
{size_t srci = GetVertexIndex(src);vector<bool> visited(_vertexs.size(), false);_DFS(srci, visited);for (int i = 0; i < visited.size(); i++){if (!visited[i]){cout << endl;_DFS(i, visited);}}cout << endl;
}

image-20221201170400122

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

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

相关文章

BERT-of-Theseus

最近了解到一种称为"BERT-of-Theseus"的BERT模型压缩方法&#xff0c;源自论文《BERT-of-Theseus: Compressing BERT by Progressive Module Replacing》。这是一种以"可替换性"为出发点所构建的模型压缩方案&#xff0c;相比常规的剪枝、蒸馏等手段&#…

streptavidin-PEG-6-FAM 链霉亲和素-聚乙二醇-6-羧甲基荧光素

产品名称&#xff1a;链霉亲和素-聚乙二醇-6-羧甲基荧光素 英文名称&#xff1a;streptavidin-PEG-6-FAM 纯度&#xff1a;95% 存储条件&#xff1a;-20C&#xff0c;避光&#xff0c;避湿 外观:固体或粘性液体&#xff0c;取决于分子量 PEG分子量可选&#xff1a;350、550、75…

自助建站工具

每用一次自助建站工具&#xff0c;就有一个程序员失业。 作为企业老板的你&#xff0c;要为公司的获客&#xff0c;企业推广发愁&#xff0c;但是预算有限&#xff0c;招人也很困难&#xff0c;不仅要面试程序员&#xff0c;后续还要检验这个程序员的功力&#xff0c;实在是太…

谷歌浏览器

引言&#xff1a;众所周知&#xff0c;一个好的浏览器可以提高我们的工作效率&#xff0c;那么今天教大家如何安装超 nice 的浏览器 —— 谷歌浏览器 文章目录一、安装谷歌浏览器二、修改谷歌浏览器搜索引擎三、修改谷歌浏览器默认下载位置一、安装谷歌浏览器 打开&#x1f5b…

GJB 5000B二级-II实施基础

本实践域为新增实践域   思想:以GJB5000A的共用过程域中不乏实践为基础进行提炼并提升,结合各个行业的优秀实践和行业特点,坚持问题导向,使标准更具有指导性和可操作性;充分借鉴GJB9001C中:“4组织环境”、“7支持”的相关内容,形成实施基础实践域。本实践域强调突出重…

0111 栈与队列Day1

剑指offer09.用两个栈实现队列 用两个栈实现一个队列。队列的声明如下&#xff0c;请实现它的两个函数 appendTail 和 deleteHead &#xff0c;分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素&#xff0c;deleteHead 操作返回 -1 ) 示例 1&#x…

Java ArrayLIst与顺序表

什么是集合类&#xff1f; Java当中的集合类&#xff0c;其实就是封装号的数据结构 原始的数据结构——>Java当中封装成的集合对应的那个原始的数据结构——>用Java封装的集合对应的。 集合类所在的包&#xff1a;java.util这个包底下 顺序表的底层是一个数组&#xff0…

结构力学常用公式表,早晚用得到!

来源&#xff1a;360个人图书馆 常用截面几何与力学特征表​​​​​​​ 注&#xff1a; I 称为截面对主轴&#xff08;形心轴&#xff09;的截面惯性矩 (mm4)。基本计算公式如下&#xff1a; W称为截面抵抗矩 (mm)&#xff0c;它表示截面抵抗弯曲变形能力的大小&#xff0c…

皕杰报表之隐藏处理

第一步&#xff0c;新建报表&#xff0c;然后新建参数 参数type设置成中文描述为统计类型、数据类型为字符串。 参数year设置成中文描述为年、数据类型为日期、时间日期格式为yyyy。 参数month设置成中文描述为月、数据类型为日期、时间日期格式为MM。 参数day设置成中文描…

python安全工具开发笔记(三)——python 多线程

一、Python线程和进程 进程 进程是程序的一次执行。每个进程都有自己的地址空间、内存、数据栈及其它记录其运行轨迹的辅助数据。 线程 所有的线程运行在同一个进程当中&#xff0c;共享相同的运行环境。线程有开始顺序执行和结束三个部分。 帮助理解&#xff1a; 1、计算…

VM系列振弦采集模块传感器激励方法

VM系列振弦采集模块传感器激励方法 通过修改寄存器 EX_METH.[3:0]来完成激励方法的选择&#xff0c; EX_METH[4]用于设置是否忽略传感器的接入检测而强制发送激励信号。 高压脉冲激励法 高压脉冲激励法 HPM&#xff08; High Voltage Pulse Excitation Method&#xff09;。 向…

桌面画图工具:Pointofix(fertig)

Pointofix桌面画图工具 Pointofix - der virtuelle Textmarker fr Ihren Bildschirm - Freeware 一、软件下载 官方网址https://www.pointofix.de/ 二、进入下载页面&#xff0c;需要下载安装文件和语言包两个文件 三、网站还提供了一个语言设置小程序&#xff0c;但我没用 …

教师如何创建百度百科词条?这篇带你了解

互联网时代&#xff0c;如果你是小有名气的人物&#xff0c;或是某个领域的专家&#xff0c;对于社会有一定的贡献或是影响力&#xff0c;就可以在百度上搜到一个你的专属词条。 百度百科词条就是个人的一张网络名片&#xff0c;人物的一些基本信息、生平事迹、代表作品、所获…

mac下安装nodejs跟vscode

1.打开官网 Node.js 2.点击下载 3.下载完成&#xff0c;根据提示下一步安装&#xff0c;安装完成后&#xff0c;在vscode中新建一个js文件&#xff0c;执行node test.js

基于STM32单片机的篮球计时记分器proteus仿真原理图PCB

功能&#xff1a; 0.本系统采用STC89C52作为单片机 1.LCD1602液晶实时显示比赛剩余时间&#xff0c;球队分数 2.默认计时器为4节&#xff0c;每节10分钟&#xff0c;每节比赛结束&#xff0c;蜂鸣器报警 3.按键功能介绍: 1’键——加1分 4’键——减1分 2’键——加2分 5’键—…

[附源码]计算机毕业设计springboot人体健康管理app

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

静态路由配置案例

静态路由配置案例配置静态路由原理命令&#xff1a;案例&#xff1a;最后结果&#xff1a;配置静态路由原理命令&#xff1a; [Huawei]ip route-static 来源ip 子网掩码 去向ip [Huawei]ip route-static 192.168.20.1 255.255.255.0 192.168.1.2 案例&#xff1a; pc1,pc2,a…

MySQL数据库实现主从复制,docker实现版

我这里是在同一台电脑上使用docker实现的主从复制&#xff0c;在物理机上整体思路是一致的 预备工作&#xff1a;安装好docker 使用docker运行MySQL 拉取MySQL镜像 docker pull mysql:5.7运行mysql master容器 sudo docker run -p 33061:3306 --name mysql-master-v /myda…

Docker with IPV6

1、绪论 在 Docker 容器或群服务中使用 IPv6 之前&#xff0c;您需要在 Docker 守护进程中启用 IPv6 支持。之后&#xff0c;您可以选择对任何容器、服务或网络使用 IPv4 或 IPv6&#xff08;或两者&#xff09; 2、配置默认 Docker IPv6 注意&#xff1a;IPv6 网络仅在 Lin…

揭秘你代理商做不起来货卖不出去的原因,探讨其背后的商业逻辑

现在很多代理商&#xff0c;大都是可以归于“个体户”性质。这些也代表了微小型企业&#xff0c;从前期的蓬勃发展&#xff0c;到现在的经营受限&#xff0c;特别是疫情等影响&#xff0c;很多人的经营都处于举步维艰的状态&#xff0c;如果你们现在是代理商&#xff0c;仓库里…