《数据结构》课程综合设计(zzu校园导航)(迪杰斯特拉算法)

一、系统(问题)描述

目前根据郑州大学主校区面积区域的广大,以及南、北核心教学楼的教室分布密集且较多;另外,多数地图软件无法精细导航到一个具体的地点,容易造成原地转圈的烦恼。但是,我们转换思路,仅仅根据我们对于校园充分的熟悉度,给出了郑州大学主校区柳、荷、菊、松四个园区和南、北核心教学楼各个教室的名称信息及有线路联通的地点之间的距离,利用郑州大学主校区教室导航系统计算出给定的起点到终点之间的最近距离及最优路线。

二、系统需求

zzu教室导航系统主要提供给用户三个选项进行操作,分别为输出地图、教室导航、退出。它主要用于教室导航,根据用户输入的起点和终点,为用户显示最佳路线。

程序具有的功能:

能够根据用户输入的起点和终点给出最短距离,输出最短路线。

1、InitOutput()目录:给出用户目录以供选择。

2、initInput(Pos p)初始化点信息:存储校园各点的地名信息;

3、initGraph() 初始化图:存储校园各个地点构成的边信息;

4、Dijkstra(Pos p, int Start, int End)求两点之间的最短路径:利用算法,快速给出用户到目的地的最短距离,并存储最佳路线;

5、PrintPath(Pos p, int start, int end, char *E)输出具体路线:给出用户具体的路线过程;

6、PrintRoad(char *d, char *end)d为进的门, end为教室:教学楼内部导航信息的建立;

三、设计思想

建图:将地点根据名称转换为数字来表示,建边和后序计算最短路均使用该点所对应的编号来操作。

求最短路:利用迪杰斯特拉算法+堆结构优化。

求最短路线:利用递归访问路线数组。

(一)数据结构的选择和设计

//位置类
typedef struct Position *Pos;
struct Position
{char name[Totalcharlen];//地点名int index; //编号
};

位置类Pos,用来根据编号来找地点名。后序进行迪杰斯特拉算法和输出道路时,均是通过编号来表示该点,即会用到Pos这个数据类型。

map<string, int> mpos; //名字对应位置

Map为c++的stl结构,利用map该数据结构实现给点编号,并可以通过点的名字来访问其的编号,在建点,建边中有用到。即通过点的名字,取得其的编号,然后按照编号来表示两点之间的关系。

//边
struct ty
{int t, len, next; // t:边终点,len:边长,next指向该点连的下一条边
} edge[TotalEdge];

链式前向星算法中用来存边的结构,给每条边设定编号,edge的下标为边的编号,每条边存该边的终点t,长度len,和与该边起点相同的边的上一条边的编号next。

//堆里数据
typedef struct Index *in;
typedef struct Index Index;
struct Index
{int x, dis; //最小堆里存放的,x:当前结点编号,dis:该点到其他点的距离
};

in为堆中数组里的元素,存放着该点的编号x,dis指的是起点到该点的距离。

//最小堆
typedef struct MinHeap *Mh;
struct MinHeap
{in i;     //数组int last; //堆尾。
};

Mh为数据结构最小堆,该堆中存储了数组i和队尾的下标last。堆是一个类似于二叉树的结构,与其不同的是其父亲结点比孩子大(小),为大(小)顶堆。这里利用数组结构来表示堆,其下标从1开始,设父亲节点为i,则左孩子为2*i,右孩子为2*i+1,且定义比较的大小是对in结构体数组里的dis(起点到该点的距离)的值来比较。

(二)算法设计

首先来说明下建图的过程,建图包括建点和建边两部分:

建点:

Pos initPos(int totalpos) //初始化点
{p = (Pos)malloc(sizeof(struct Position) * total); //分配点空间for (i = 0; i < totalpos; i++)p[i].index = 0; //初始化点的编号return p;
}
Status InsertPos(Pos p, char *name) //插入点函数
{mappos[name] = ++total; //给该点编号//存该点信息p[total].index = total;strcpy(p[total].name, name);return OK;
}
Status initInput(Pos p) //初始化点  //加点
{fp = fopen("datapos.txt", "r");if (fp == NULL) //如果文件指针为空{printf("文件打开失败\n");return ERROR;}else{printf("打开成功\n");fscanf(fp, "%d", &totaldata);for (i = 0; i < totaldata; i++){fscanf(fp, "%s", pos); //该点的名InsertPos(p, pos);     //插入该点}printf("点信息输入完成!\n");}fclose(fp); //关闭文件return OK;
}

利用map数据结构,即程序中的mappos将图中的点根据名字的不同实现从1开始的编号。编号后再将其存入Pos--点数组里,实现可以通过点的名称和编号双向访问。程序中,是从文件中读取点然后将其插入。

建边:

Status AddEdge(PosType x, PosType y, EdgelenType len) //链式前向星,加边
{edge[++cnt].t = y;        //存边的尾edge[cnt].len = len;      //存边的长度edge[cnt].next = head[x]; //标志为以x的点为起点的边head[x] = cnt;            //更新以x为起点的边的标记return OK;
}
Status InsertEdge(char *name1, char *name2, EdgelenType len) //插边函数
{//找到两点编号PosType x1 = mpos[name1]; //找name1所对应的编号PosType x2 = mpos[name2]; //找name2所对应的编号AddEdge(x1, x2, len); //建x1->x2AddEdge(x2, x1, len); //建x2->x1return OK;
}
Status initGraph() //初始化图  //加道路
{fp = fopen("dataedge.txt", "r");if (fp == NULL) //如果文件指针为空{printf("文件打开失败\n");return ERROR;}else{printf("打开成功\n");printf("边信息输入完成!\n");fscanf(fp, "%d", &totaldata);for (i = 0; i < totaldata; i++){char s1[Totalcharlen], s2[Totalcharlen];EdgelenType len;fscanf(fp, "%s %s %d", s1, s2, &len); //输入边的起始,终止点,长度InsertEdge(s1, s2, len);              //加双向边}}fclose(fp); //关闭文件return OK;
}

根据点的编号来建边,利用链式前向星的思想,先将head数组初始化为-1,head数组的下标代表点的编号,其存储的为该点所连的最后一条边的编号。每次建一条边,就用edge结构体数组来存储,其下标即为边的编号。

当在图中插入一条边时,先将边的总数编号+1,则此时总数为该边的编号,然后存储该边长度len,上一个同一起点的边的编号head[x该边起点)],更新head[起点] = 该边的编号。按照这样来建边。

按照这种方式来建边,使得每次访问以x为起点的边时,就从i = head[x]开始,即从以x为起点的最后一条边开始访问,edge[head[x]]即为该边信息。然后i = edge[i].next即为以x为起点的上一条边。程序中对于边的插入是通过文件读取每条边的起点,终点,长度来插入。

然后是来说明下如何求最短路:

//最短路算法
EdgelenType Dijkstra(Pos p, PosType Start, PosType End) //求两点之间的最短路径,并记下路径,返回路径
{memset(vis, 0, sizeof(vis));                   //初始化vis数组,指所有元素均未访问国memset(dis, Maxx, sizeof(dis));                //初始化dis数组,标记所有节点到start数组距离均为无穷大path = (int *)malloc(sizeof(int) * TotalEdge); //存经过路径Mh m = InitMinheap(TotalEdge);                 // 边的个数dis[Start] = 0;             //自己到自己的距离为0tmp.dis = 0, tmp.x = Start; //赋tmp值pushMinHeap(m, tmp);        //将第一个点放入堆中path[Start] = 0;            //记录下起点的path值为0,方便后序访问//遍历len,找更新所有和end的距离diswhile (!IsEmptyHeap(m)) //如果堆不为空{tmp = getHeapTop(m);                           //取出堆顶元素(即dis最小的下标)popMinHeap(m);                                       //取出下标if (vis[tmp.x])                                      //如果该下标访问过continue;                                        //跳过vis[tmp.x] = 1;                                      //未访问过就将其标记for (i = head[tmp.x]; i != -1; i = edge[i].next) //遍历该点所连的边{y = edge[i].t;                     // y值为该边所指向的终点if (edge[i].len + dis[tmp.x] < dis[y]) //如果start到x的长度(dis[x]) + 该边长度 小于 start到X的长度{dis[y] = edge[i].len + dis[tmp.x]; //更新start到y的长度(dis[y])path[y] = tmp.x;                   //记录到y,所经过点xtmp2.x = y, tmp2.dis = edge[i].len + dis[tmp.x];pushMinHeap(m, tmp2); //压入堆}}}FreeMinHeap(m);  //释放堆内存return dis[End]; //返回start到end的最短距离
}

利用堆优化+迪杰斯特拉算法,vis数组表示起点到该点的最短距离是否已经求出。若为1,表示已求出,为0表示未求出。先初始化vis数组全为0,表示此时起点到该点的最短距离均未求出。dis数组表示起点到其他点的最短距离,先初始化为最大值。

开始计算最短路,每次从小顶堆顶中取出与起点距离最短的点,然后判断该点是否访问过,即是否已经求出起点到该点的最短距离,访问过就跳过该点,未访问过,就将该点x作为中间节点来更新起点到其他未求出最短距离的节点的距离,并标记该点访问过了。如果起点到该点的距离dis[x]+该点到其他点y的距离<起点到y的最短距离dis[y],就更新这个最短距离dis[y],然后将该点y的信息放入堆中。

输出道路:

//输出道路算法
void PrintPath(Pos p, PosType start, PosType end, char *E) //输出道路
{if (path[end] == 0) //因为起始点的path为0,因此此时递归到起始点{printf("%s", p[start].name); //输出起始点return;}else{PrintPath(p, start, path[end], E);   //一直递归到起始点后,开始输出if (!strcmp(p[end].name, E))         //如果当前点的下一个为终点strcpy(door, p[path[end]].name); //保存当前门(终点为教室,门为教室的上一个点)printf("->%s", p[end].name); //输出当前遍历的点名}
}

在迪杰斯特拉算法中,还维护了一个数组path。先将path[start] = 0,然后每次更新到起点到其他节点y的最短距离时,也同时更新y的path,即path[y] = x(中间节点),即path数组,除了起点外,其存储的为最短距离要经过path下标节点的道路的上一个节点。

然后在输出道路的函数中,递归输出,即从终点的path值开始递归,直到终点的path值为0,即此时终点的path值和起点相同,输出起点,这时回退,输出上一层终点的path值,再输出点,以此类推。

最小堆:

Status pushMinHeap(Mh m, Index x) //将x存入堆
{m->last++;                                      //堆数组最后的下标+1m->i[m->last] = x;                              //将X存入堆数组的最后一个位置。parent = m->last / 2, i = m->last;          // parent指向最后一个元素的父亲节点下标,i指向最后一个元素下标while (m->i[parent].dis > x.dis && parent != 0) //从下往上滤{swap(m->i[parent], m->i[i]); //因为为最小堆,如果父亲节点大于儿子节点,就交换i = parent;                  //儿子 = 父亲parent /= 2;                 //父亲 = 父亲的父亲}return OK;
}

对于堆的插入操作,首先是将堆的最后一个下标自增1,即last++,然后将插入的元素x插入堆中数组下标为last值的位置,开始从下到上调整堆的结构。即用一个指针i指向x元素的下标,一个指针p指向x元素的父亲节点,开始比较两者大小,如果父亲节点大于孩子节点并且此时父亲节点不为0(因为数组下标从1开始),说明不满足最小堆的要求,将二者调换,然后i指向p,p再指向i的父亲,再次比较,以此类推,直到父亲节点小于孩子节点,或者父亲节点下标为0为止。

Status popMinHeap(Mh m) //将堆头元素删除
{m->i[1] = m->i[m->last];                                           //先将第一个赋值为最后一个元素,也算删除了第一个元素i = 1;                                                         // i指向第一个元素的下标m->last--;                                                         //最后一个元素下标-1child = i * 2;                                                 //指向第一个元素的左孩子if (m->i[child].dis > m->i[child + 1].dis && child + 1 <= m->last) //如果有右孩子,且右孩子比左孩子小child++;                                                       //那么就指向右孩子while (m->i[child].dis < m->i[i].dis && child <= m->last)          //从上往下滤{swap(m->i[child], m->i[i]);                                        //如果i节点指向元素比最小的孩子还小,就交换i = child;                                                         // i指向孩子child *= 2;                                                        //孩子指向孩子的孩子if (m->i[child].dis > m->i[child + 1].dis && child + 1 <= m->last) //再次找最小的孩子child++;}return OK
}

对于堆的删除操作,因为堆中只能删除堆顶元素,即取出最小元素,那么就将堆中数组的最后一个元素提上来覆盖掉堆顶元素,然后开始从上往下调整。指针i指向根结点,指针c指向i的左孩子,先比较i的左孩子和右孩子谁更小,如果右孩子更小,则c指向右孩子。然后开始比较i指向的值和孩子节点值的大小,如果孩子节点的值小于父亲节点,说明不符合最小堆的性质,这时将两个节点进行交换,然后再将i指向c节点, c指向i的最小的孩子节点,然后再次比较,以此类推,直到符合最小堆性质为止。 

四、实现细节说明

求最短路径:迪杰斯特拉+堆优化,

利用迪杰斯特拉算法,用数组的下标表示点的编号,利用链式前向星思想来找每一个点的边,利用最小堆来存储每个点到起点的距离,然后每次从堆顶取出到起点距离最小的点来更新其他点到起点的最小距离,每次更新将该点的上一个点给记住,方便后序输出道路。

如以上界面,输入起始地点,终点。然后输出最短距离和道路。

系统根据用户输入的起点,先从系统中找该点是否存在,存在则继续下一步,,不存在就让用户再次输入。然后是判断用户输入的终点是否存在,且是否为教室,若不满足要求,则再次输入。若为教室则继续下一步,利用迪杰斯特拉算法计算两点间的最短距离,并保存路线,然后输出。

五、测试数据及测试结果

大体说明:

根据我们的测试结果,与我们校园实地的情况是一致的。

校园地图测试:

导航路线测试:

具体说明:

首先说明下系统中文件的导入:

点文件:用来存放所有地图上要初始化的点,即用户可以输入的地点,系统根据该文件来建点。

第一个311指总共有311个点。

然后每行一个地点。

边文件:用来存放所有边的文件,系统通过该文件内容建边。

第一个1121指总共有1121条边。

每行一条边,按照起点、终点、长度排列顺序。例如第二行的指从秋实西1到厚德北1长度为161米,且厚德北1到秋实西1也有一条161的边,实际上一行为两条边。

然后是介绍用户输入所实现的功能:

输入1,输出简化地图:

输入2,根据用户输入的起点和终点教室,输出路线。

如图所示,选择起点为本源南1,终点教室为南4-302。然后程序给出了具体走法,该走法可以参照地图来理解。

再次输入:

这次输入的起点为厚德北1,终点教室为为北3-204。

如图所示为程序给出的最佳路径。

输入3,退出系统,并释放内存。

六、总结

(一)系统特点及创新

特点:

1、简洁输出关键有用的信息,输出界面有简化地图的展示,输出距离和路线简洁明了。

2、更人性化,到达教学楼区域,有文字引导方向至具体教室。

创新性:

1、利用地点名到序号的映射,使代码写起来更清晰易懂。可以直接通过地点名来进行建图。

2、利用链式前向星的思想来建边,可以使访问一个点所连的边更快,避免了访问其他没有连边的节点。

3、利用堆来优化迪杰斯特拉算法,使算法效率提升。

4、利用数组递归方式来输出最短路线。

5、结合实际,将每个门如何到达教室的具体路线完善。

(二)遇到的问题及解决思路

1、路线距离测量困难

解决方法:我们通过查阅资料,在电脑端高德地图找到了测距尺,快速确定了各个地点间的距离。

2、地点名难与序号一一对应

解决方法:刚开始考虑的是利用哈希表,然后思考如何定义一种求有效快速的关键字的设计,实现更好的根据名字来定位元素。但是因为地点名为中文,有关中文如何编码不是很清楚,有想过将中文改为拼音来建图。但是拼音很容易就会打出错,对于系统维护来说不是很方便,因此就利用了c++的stl里面的map结构,来实现名字对应序号,至于序号对应名字,就可以利用结构体数组的下标来实现。

3、建点和建边部分的程序很长,且没太大意义

解决方法:将其用文件的方式输出。刚开始使用文件,发现根本运行不了,发现原来是对于中文的编码,文件要选择ANSI的格式。

4、程序输出最佳路线无法明确指向教室

解决方法:将教学楼的大门与每一个可以从该门口到达的教室连一条为0长度的边,这样用户输入教室终点时,其路线的终点就会指向教室了。

5、对于用户输入的起点和终点缺少判断,导致随便输入代码也会继续执行出错

解决方法:首先是对起始点的判断,起始点输入的,要为点文件中给出的已经初始化的点,通过map的性质进行判断,如果用户输入的点不在map中,那么直接该点的map值为0,而我们初始化点的序号从1开始,就可以判断了。对于终点输入是否为教室的判断,读取点文件,看输入的教室是否存在来判断。

最后,可能以上的程序还是存在瑕疵,大家可以适当修改和完善,感谢阅读!

完整代码:

【免费】数据据结构课程设计-zzu校园导航(迪杰斯特拉算法)资源-CSDN文库

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

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

相关文章

js中map,filter,find,foreach的用法介绍

js中map&#xff0c;filter&#xff0c;find&#xff0c;foreach的用法介绍 在 JavaScript 中&#xff0c;数组提供了一些常用的迭代方法&#xff0c;如 map、filter、find 和 forEach&#xff0c;这些方法允许你对数组中的每个元素进行操作&#xff0c;下面是它们的用法和区别…

Python爬虫实战:利用青果代理IP获取跨境电商数据

文章目录 一、跨境电商数据的作用1.1 市场趋势预测与洞察1.2 消费者行为分析1.3 库存管理优化1.4 定价策略制定 二、爬取目标三、环境准备四、代理IP获取4.1 为什么爬虫要用代理IP&#xff1f;4.2 为什么选择青果代理IP&#xff1f;4.3 青果代理IP领取4.4 利用代码获取IP 五、爬…

excel 表格中url转图片

待处理的单元格通过如下公式获取目标格式&#xff1a; "<table><img src"&A4&" height20></table>" 然后下拉后获取多列的单元格转换结果&#xff0c; 然后将这些转换后的结果拷贝到纯文本文档中&#xff0c; 然后再将纯文本…

新基建下的园区智慧化变革 | 科技驱动未来开放式智慧园区

在数智化浪潮席卷之下&#xff0c;千行百业的数字化转型步伐加快。智慧园区建设借助创新的数字化、智能化技术&#xff0c;对园区内的人、机、物、事进行建模和重构&#xff0c;克服传统园区数据割裂、分散管理、无集成、体验差的问题&#xff0c;构建更智慧的管理方式、服务体…

unity学习-雾的渲染

在Light面板下的Other Settings中勾选fog就会让场景中生成雾气 Coloer&#xff1a;颜色 Mode&#xff1a;预设 Density&#xff1a;密度 当Mode调整为Linear模式会多出两个选项 Start&#xff1a;往前从多少米开始 End&#xff1a;到多少米有雾气 Start&#xff1a;设置…

[单master节点k8s部署]41.部署springcloud项目

在之前的文章中我们配置了mysql和harbor&#xff0c;现在我们可以将一个springcloud部署在k8s集群中了。 项目概述 这个springcloud项目将采用maven进行打包部署。首先安装maven&#xff1a; yum install java-1.8.0-openjdk maven-3.0.5* -y 然后将该项目上传到k8s集群的m…

c#编写的各类应用程序

001 课程简介&#xff0c;C# 语言简介&#xff0c;开发环境准备 (yuque.com)https://www.yuque.com/yuejiangliu/dotnet/timothy-csharp-001 一个Solution里包含多个Project 一、见识 C# 编写的各类应用程序 二、类库的引用&#xff08;黑/白盒引用&#xff09; 1、黑盒引用&a…

C++从入门到起飞之——(multi)set与(multi)map的的使用 全方位剖析!

&#x1f308;个人主页&#xff1a;秋风起&#xff0c;再归来~&#x1f525;系列专栏&#xff1a;C从入门到起飞 &#x1f516;克心守己&#xff0c;律己则安 目录 1. 序列式容器和关联式容器 2. set系列的使⽤ 2.1 set和multiset参考⽂档 2.2 set类的介绍 2.3 se…

打印自然常数E

自然常数E 自然常数&#xff0c;符号e&#xff0c;为数学中一个常数&#xff0c;是一个无限不循环小数&#xff0c;且为超越数&#xff0c;其值约为2.718281828459045。它是自然对数函数的底数。 我们打印表达式(11/x)的x次方的值以及获取第一次大于2.718的正整数 新建C#控制…

Linux系统:Ubuntu上安装Chrome浏览器

Ubuntu系统版本&#xff1a;23.04 在Ubuntu系统上安装Google Chrome浏览器&#xff0c;可以通过以下步骤进行&#xff1a; 终端输入以下命令&#xff0c;先更新软件源&#xff1a; sudo apt update 或 sudo apt upgrade终端输入以下命令&#xff0c;下载最新的Google Chrome .…

HarmonyNext保存Base64文件到Download下

本文介绍如何保存Base64的文件到Download下 参考文档地址&#xff1a; 保存用户文件-Harmony Next 用到的是DOWNLOAD模式保存文件 用户在使用save接口时&#xff0c;可以将pickerMode配置为DOWNLOAD模式&#xff0c;该模式下会拉起授权接口&#xff0c;用户确认后会在公共路径…

net core 微信公众号发送模板消息完整实现

第一完整看一下微信官方的文档 链接&#xff1a;开发前必读 / 首页 (qq.com) 想要发送模板消息分为一下几步 第一步&#xff1a;想要发消息需要有这几个参数&#xff0c; openid&#xff0c;这是给谁发消息 access_token&#xff0c;调用接口必要的 appid、secret 这两个是生…

如何替换OCP节点(二):使用 antman脚本 | OceanBase应用实践

前言&#xff1a; OceanBase Cloud Platform&#xff08;简称OCP&#xff09;&#xff0c;是 OceanBase数据库的专属企业级数据库管理平台。 在实际生产环境中&#xff0c;OCP的安装通常是第一步&#xff0c;先搭建OCP平台&#xff0c;进而依赖OCP来创建、管理和监控我们的生…

开放式蓝牙耳机哪个品牌好用?开放式耳机排行榜测评!

开放式耳机&#xff0c;因其特殊的不入耳佩戴模式&#xff0c;让使用者在享受音乐或者进行通话的过程中&#xff0c;依然可以对外界声音保持敏感。在户外运动场景下&#xff0c;这种特性优势尽显&#xff0c;既保证了耳机佩戴的稳定和舒适&#xff0c;又提高了运动的安全性。为…

如何做好项目管理,实现高效协作?

项目管理难&#xff0c;难于上青天&#xff01; 小卫&#xff0c;某服装生产企业项目经理&#xff0c;说到项目难管理&#xff0c;他有话要说&#xff1a; 做项目&#xff0c;看似简单&#xff0c;不同部门各司其职&#xff0c;但也正因为涉及跨部门协作&#xff0c;管理难度也…

Qt:图片文字转base64程序

目录 一.Base64 1.编码原理 2.应用场景 3.优点 4.限制 5.变种 二.文字与Base64互转 1.ui设计 2.文字转Base64 3.Base64转文字 三.图片与Base64互转 1.ui设计 2.选择图片与图片路径 3.图片转Base64 4.Base64转图片 四.清空设置 五.效果 六.代码 base64conver…

基于SpringBoot+Vue+uniapp的时间管理小程序的详细设计和实现(源码+lw+部署文档+讲解等)

详细视频演示 请联系我获取更详细的演示视频 项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而不…

大厂面试一上来就手撕 Transformer,心凉半截

在这两年&#xff0c;尤其是大模型问世之后&#xff0c;有关 Transformer 的面试题不仅数量众多&#xff0c;而且颇具新意。 今日&#xff0c;我将分享 18 道 Transformer 高频面试题&#xff08;如需获取更多专业面试题&#xff0c;扫描文末二维码即可&#xff09;&#xff0…

关于为什么蒸馏后的小模型和一开始的小模型的区别是什么?

起初&#xff0c;我想写这个博客是因为无意间看到了一个采访&#xff0c;无意间浏览才发现这段说的给我一种恍然大悟的感觉。 主持人提问&#xff1a;训练一个大模型&#xff0c;然后再将其压缩蒸馏成一个小模型&#xff0c;那和直接训练一个小模型&#xff0c; 这两者的区别是…

再Android10上实现检测AHD摄像头是否接入

项目有个需要&#xff0c;需要知道tp9951是否接入AHD摄像头 1&#xff0c;驱动层可以通过读取寄存器的值来检测是否接入AHD摄像头 tp9951_write_reg(0x40, 0x00); //select decoder page tp9951_write_reg(0x41, ch); val tp9951_read_reg(TP_INPUT_STATUS_REG);…