数据结构与算法实验
实验目的实验一1掌握线性表的实现。2掌握线性表的应用。实验二1掌握栈和队列的实现。2掌握栈和队列的应用。实验三掌握二叉树的实现。掌握二叉树的应用。实验四掌握图结构的实现。掌握图结构的应用实验内容与实验步骤2.1线性表的应用(1)我选定了题目一学生信息的录入。(2)定义存储结构typedef struct Node {double data;char subject[30];struct Node * next;}Node;data储存分数subject储存科目名称。基本操作a.初始化链表操作initList()创建一个带头节点的空表并返回表头b.往链表里添加元素操作addGrade(Node* list,double score,char subject[30])将分数为score的subject插入链表里c.遍历链表printList(Node* list)输出链表里所有科目及对应成绩d.寻找最高分maxScore(Node* list)和寻找最低分minScore(Node* list)找到分别找到最高分和最低分并输出分数及所属科目e.删除科目deleteSubject(Node* list,char* name)找到并删除名为name的科目及对应分数f.求平均分averageScore(Node* list)求出平均分并输出。2.2栈和队列的应用我选择算术表达式求值利用栈实现一个中缀表达式的求值定义存储结构typedef struct OPNumber{//操作数栈存放操作数int data;struct OPNumber* next;}OPNumber;typedef struct OPChar {//操作符栈存放操作符char opChar;struct OPChar* next;}OPChar基本操作初始化操作数栈initNumberStack()初始化操作符栈 initCharStack()判断栈空isNumberStackEmpty()isCharStackEmpty();入栈pushNumberStack(),pushCharStack()采用头插法入栈出栈时只需弹出头节点地下一节点即可出栈popNumberStack(),popCharStack();获取栈顶getTopOfCharStack(),getTopOfNumberStack();输入get_input();计算evaluate_expression()。2.3 二叉树的应用(1)存储结构孩子链表和二叉链表typedef struct Children {//孩子在邻接表的位置(头节点的index为链表里节点数量)int index;//后继结点struct Children* next;}Children;typedef struct CTBox {//节点在的邻接表位置int index;int perant;//数据域char name[30];int sum;//孩子链表Children* childrenList;}CTBox;typedef struct BNode {char name[30] ;int sum;struct BNode* offspring;//左子树struct BNode* sibling;//右子树}BNode;2操作创建树initTree先根遍历preRootTravel();后根遍历lastRootTravel();初始化二叉树initBTree();把树转化为二叉树toBTree();二叉树的先序、中序、后序遍历preOrder(),midOrder(),lastOrder();读取queries.txt的查询并给出回答操作getAnswer();2.4 图结构的应用1存储结构邻接表typedef struct EBox {//边int distance;//距离int cost;//费用int toVex;//终点顶点位置struct EBox* nextEdge;//下一条边}EBox;typedef struct VexBox {//结点char name[15];struct EBox* firstEdge;//第一条出边}VexBox;typedef struct Graph {//图int edgeNum, vexNum;//边数和结点数VexBox AdjList[MAX];//邻接数组}Graph;2基本操作初始化图initGraph();添加结点间的关系addVexAndEdge();深度优先遍历DFS();广度优先遍历BFS();获取最短路径shortestRoute();实验环境操作系统、调试软件名称、版本号上机地点机器台号操作系统windows11 64位操作系统调试软件visual studio2019 4.8.04161实验过程与分析实验一实验过程1初始化链表Node* initList() {Node* head (Node*)malloc(sizeof(Node));head-next NULL;head-data 0;strcpy(head-subject, 表头);return head;}头节点data域存放链表的元素个数便于在平均数求取时得到科目数量。2插入节点void addGrade(Node* list, double score, char subjectName[30]) {Node* node (Node*)malloc(sizeof(Node));node-data score;strcpy(node-subject, subjectName);node-next list-next;list-next node;list-data;}采用头插法插入结点每添加一个元素头节点data加一。3输出链表内容void printList(Node* list) {Node* node list-next;printf(成绩如下\n);printf(\n科目\t成绩\n);while (node) {printf(%s\t%.2f\n, node-subject, node-data);node node-next;}}4计算最高分void maxScore(Node* list) {Node* node list-next;Node* maxNode node;while (node) {if (node-data maxNode-data) {maxNode node;}node node-next;}printf(\n最高分\n);printf(%s\t%.2f\n, maxNode-subject, maxNode-data);}找到最低分的科目并输出其科目名称及分数5计算最低分void minScore(Node* list) {Node* node list-next;Node* minNode node;while (node) {if (node-data minNode-data) {minNode node;}node node-next;}printf(\n最低分\n);printf(%s\t%.2f\n, minNode-subject, minNode-data);}找出最低分的科目并输出科目名称和分数6删除科目void deleteSubject(Node* list, char* name) {Node* p list;Node* node p-next;while (node) {if (strcmp(node-subject, name) 0) {p-next node-next;free(node);printf(\n删除成功\n);return;}p node;node node-next;}printf(\n删除失败\n);}输入科目名称在链表中找到并删除科目名称为输入值的结点7计算平均分void averageScore(Node* list) {double sum 0;Node* node list-next;while (node) {sum node-data;node node-next;}printf(\n平均分);printf(%.2f\n, sum / list-data);}测试用例用例编号用例输入预计输出实际输出测试结果评估1语文 100数学 99英语 98化学 50生物 78语文 100数学 99英语 98化学 50生物 78最高分语文 100最低分化学 50平均分85.00输出结果符合预期2删除语文数学 99英语 98化学 50生物 78最高分数学 99最低分化学 50平均分81.25结果符合预期3语文 99.99数学 98.99英语 59.9历史 100语文 99.99数学 98.99英语 59.9历史 100最高分历史 100最低分英语 59.9平均分89.72结果符合预期4删除历史语文 99.99数学 98.99英语 59.9最高分语文 99.99最低分英语 59.9平均分86.29结果符合预期实验二实验过程初始化栈此为初始化操作数栈OPNumber * initNumberStack() {OPNumber* numberStack (OPNumber*)malloc(sizeof(OPNumber));numberStack-data 0;numberStack-next NULL;return numberStack;}创建一个带头结点地链式栈并返回头节点初始化操作符栈类似。判断栈空此为操作数栈int isNumberStackEmpty(OPNumber* stack) {if (stack-next)return 0;elsereturn 1;}栈为空返回1否则返回0操作符栈判断方法一样。入栈以操作数入栈为例void pushNumberStack(OPNumber* stack, int number) {OPNumber* node (OPNumber*)malloc(sizeof(OPNumber));node-data number;node-next stack-next;stack-next node;}使用头插法入栈操作符入栈与此类似出栈以操作数出栈为例int popNumberStack(OPNumber* stack) {if (!isNumberStackEmpty(stack)) {OPNumber* node stack-next;int number stack-next-data;stack-next stack-next-next;free(node);return number;}elseprintf(操作符栈为空\n);}栈不为空则弹出第一个结点否则出栈失败操作符出栈与此类似获取栈顶char getTopOfCharStack(OPChar* stack) {if (!isCharStackEmpty(stack)) {return stack-next-opChar;}elseprintf(栈为空\n);}得到栈顶元素用于比较运算符优先级和计算获取输入int get_input(int* n){*n 0;char ch getchar();if (!isdigit(ch)){*n ch;getchar();return true;}do{*n (*n) * 10 (ch - 0);ch getchar();} while (ch ! \n);return false;}依次获取从控制台输入的字符计算int evaluate_expression(OPNumber* numberStack,OPChar* charStack) {/* 输入元素 */int* element (int*)malloc(sizeof(int));/* 输入元素类型* type true表示输入为运算符* type false表示输入为运算数*/int type;/* 出栈元素 */int* x (int*)malloc(sizeof(*x));/* 运算出栈元素 */int* theta (int*)malloc(sizeof(int));int* a (int*)malloc(sizeof(int));int* b (int*)malloc(sizeof(int));pushCharStack(charStack, #);type get_input(element);*x #;while (*element ! # || *x ! #){/* 输入不是运算符 */if (!type){//操作数入栈pushNumberStack(numberStack, *element);type get_input(element);}else{*x getTopOfCharStack(charStack);switch (precmp(*x, *element)){case :pushCharStack(charStack, *element);type get_input(element);*x getTopOfCharStack(charStack);break;case :*x popCharStack(charStack);type get_input(element);break;case :*theta popCharStack(charStack);*b popNumberStack(numberStack);*a popNumberStack(numberStack);pushNumberStack(numberStack, compute(*a, *theta, *b));*x getTopOfCharStack(charStack);break;}}}*x getTopOfNumberStack(numberStack);free(element);free(a);free(b);free(theta);return *x;}测试用例用例编号测试输入预计输出实际输出结果评估1141630结果符合预期21416*390结果符合预期31415*9/42893.25由于程序的数据类型为int所以小数位被舍去实验结果较符合预期实验三实验过程初始化树void initTree(CTBox* Tree, char info[][3][30],char buildings[][30],int* many) {for (int i 0; i Max; i) {Tree[i].index i;strcpy(Tree[i].name, buildings[i]);Tree[i].sum *(many i);Tree[i].childrenList initChildrenList();}Tree[0].perant -1;//根节点无父节点for (int i 0; i 17; i) {int parent -1;for (int j 1; j Max; j) {if (strcmp(info[i][2], Tree[j].name) 0) {//儿子for (int k 0; k Max; k) {if (strcmp(info[i][0], Tree[k].name) 0) {//父亲Tree[j].perant k;addChild(Tree[k].childrenList, j);}}}}}}info为一个通过读取definition.txt构建的二维字符串数组存储了医院各个建筑的名称、每个建筑数量及其之间的关系buildings字符串数组存储了医院的所有不重复建筑名称many数组为对应的数量。树的先根遍历void preRootTravel(CTBox* Tree,CTBox* Root) {//先根遍历printf(\t%-30s%d\n, Root-name,Root-sum);Children* node Root-childrenList-next;while (node) {preRootTravel(Tree, Tree[node-index]);node node-next;}}先根遍历树的结点及其数量树的后根遍历void lastRootTravel(CTBox* Tree, CTBox* Root) {//后根遍历Children* node Root-childrenList-next;while (node) {lastRootTravel(Tree, Tree[node-index]);node node-next;}printf(\t%-30s%d\n, Root-name,Root-sum);}后根遍历树的结点及其数量初始化二叉树BNode* initBTree(CTBox* Tree) {BNode* BTree (BNode*)malloc(sizeof(BNode));BTree-offspring NULL;BTree-sibling NULL;toBTree(Tree, BTree, Tree[0]);return BTree;}Tree为一个多叉树调用toBTree方法后将其转为二叉树并返回根节点地址把多叉树转二叉树int toBTree(CTBox* Tree,BNode* BTree,CTBox root) {//多叉树转二叉树int i 0;BNode* ptemp;strcpy(BTree-name, root.name);BTree-sum root.sum;if (root.childrenList-next NULL) {BTree-offspring NULL;return 0;}BNode* pbnode (BNode*)malloc(sizeof(BNode));BTree-offspring pbnode;toBTree(Tree, pbnode, Tree[root.childrenList-next-index]);//处理左子树i 1;ptemp pbnode;Children* node root.childrenList-next-next;while (i root.childrenList-index node ! NULL) {BNode* pbnode (BNode*)malloc(sizeof(BNode));ptemp-sibling pbnode;ptemp pbnode;toBTree(Tree, pbnode, Tree[node-index]);//处理右子树i;node node-next;}ptemp-sibling NULL;return 0;}传入一棵二叉树的根和一个多叉树以及多叉树根通过递归将其转为二叉树多叉树的第一个孩子变成二叉树左子树第二个孩子作为第一个孩子的右子树以此类推兄弟变右孩子直到所有子树都变为二叉树为止。6二叉树遍历以前序遍历为例中后序遍历仅访问结点语句位置不同void preOrder(BNode* BTree) {//先序遍历if (BTree ! NULL) {printf(\t%-30s%d\n, BTree-name,BTree-sum);preOrder(BTree-offspring);preOrder(BTree-sibling);}else {return;}}7读取queries.txt的查询并给出回答void getAnswer(char* questionsFile,CTBox Tree[]) {//读取问题并获得答案char question[13][4][30];FILE* fp;char line[100];if ((fp fopen(questionsFile, r)) NULL) {printf(Error\n);return -1;}for (int i 0; i 13;i) {for (int j 0; j 4; j) {strcpy(question[i][j], );}}int index 0;while (!feof(fp) index 13) {//将文件内容读取到info数组里fgets(line, 100, fp);int t strlen(line);//逐行读取存入line里if (line[t - 1] \n) {//吃掉\nline[t - 1] 0;}char* str2 strtok(line, );//对line以 作为分隔符分割int j 0;while (j 4 str2 ! NULL) {strcpy(question[index][j], str2);str2 strtok(NULL, );j;}index;}fclose(fp);answer(question, Tree);}void answer(char question[][4][30], CTBox* Tree) {//获取答案int sum 0;for (int i 0; i 13; i) {if (strcmp(question[i][0], what) 0) {for (int j 0; j Max; j) {if (strcmp(question[i][2], Tree[j].name) 0) {printf(\n\t(%d)Part %s subparts are:\n,i 1,Tree[j].name);Children* node Tree[j].childrenList-next;while (node) {printf(\t\t%d %s\n, Tree[node-index].sum, Tree[node-index].name);node node-next;}}}}if (strcmp(question[i][0], how) 0) {for (int j 0; j Max; j) {if (strcmp(question[i][2], Tree[j].name) 0) {//孩子for (int k 0; k j; k) {if (strcmp(question[i][3], Tree[k].name) 0) {//父亲sum getSum(Tree[k], Tree[j], Tree);printf(\n\t(%d)%s has %d %s\n,i 1,Tree[k].name, sum, Tree[j].name);break;}}}}}}}运行结果实验四实验过程初始化图生成孤立结点Graph* initGraph(char cities[][15]) {//初始化邻接数组Graph* graph (Graph*)malloc(sizeof(Graph));graph-edgeNum 0;graph-vexNum MAX;for (int i 0; i MAX; i) {strcpy(graph-AdjList[i].name, cities[i]);graph-AdjList[i].firstEdge initEdgeList();}return graph;}cities为存储城市名称的数组将其依次赋值给结点的name域建立结点间的关系添加边void addVexAndEdge(Graph* graph,char info[][4][15],char cities[][15]) {for (int i 0; i 54; i) {int start -1;int end -1;for (int j 0; j MAX; j) {if (strcmp(graph-AdjList[j].name, info[i][0]) 0) {//起点start j;}if (strcmp(graph-AdjList[j].name, info[i][1]) 0) {//终点end j;}}int cost atoi(info[i][2]);int distance atoi(info[i][3]);addEdge(graph-AdjList[start].firstEdge, cost, distance, end);graph-edgeNum;}}info为存储结点名称、结点间关系和边的权值的数组cities为存储城市名称的数组深度优先遍历void DFS(Graph* graph,int* isvisted,int* index) {//深度遍历连通的19个城市if (isvisted[*index] ! 0) {return;}printf(\t\t%s\n, graph-AdjList[*index].name);isvisted[*index] 1;EBox* node graph-AdjList[*index].firstEdge-nextEdge;while (node) {*index node-toVex;DFS(graph, isvisted, index);node node-nextEdge;}}void DFSAll(Graph* graph,int* visited) {//深度遍历所有城市int order 0;DFS(graph, visited, order);EBox* node graph-AdjList[20].firstEdge-nextEdge;while (node) {//遍历孤立的两个城市printf(\n\t\t%s\n, graph-AdjList[20].name);visited[20] 1;printf(\t\t%s\n, graph-AdjList[node-toVex].name);visited[node-toVex] 1;node node-nextEdge;}}采用递归对每个城市深度优先遍历广度优先遍历void BFS(Graph* graph, int* visited,int index,Queue* Q) {//广度优先遍历一个点printf(\t\t%s\n, graph-AdjList[index].name);//访问节点visited[index] 1;inQueue(Q, graph-AdjList[index]);//节点入队EBox* p;while (!isEmpty(Q)) {p graph-AdjList[index].firstEdge-nextEdge;deQueue(Q);//节点出队while (p) {if (visited[p-toVex] 0) {printf(\t\t%s\n, graph-AdjList[p-toVex].name);visited[p-toVex] 1;inQueue(Q, graph-AdjList[p-toVex]);//入队相关结点}p p-nextEdge;}}}建立辅助数组visited记录结点是否被访问过假设对结点i进行广度优先遍历则先访问结点i将结点i入队再将visited[i]标记为true,然后弹出队首访问i能直接到达且还未被访问过的结点入队然后修改visited相应的元素。void BFSAll(Graph* graph,int* visited) {//广度优先遍历所有结点for (int i 0; i 22; i) {visited[i] 0;}Queue* Q initQueue();for (int i 0; i graph-vexNum; i) {if (visited[i] 0) {if (i 20) {printf(\n);}BFS(graph, visited, i, Q);}}}对所有违背访问过的结点进行广度优先遍历。获取最短路径采用迪杰斯特拉算法void DJ(Graph* graph, int dist[],int distance[], int path[], int v) {//迪杰斯特拉算法,v为起点索引int set[MAX];//1为已找到最短路径0为未找到int i, j, u, min;int cost;for ( i 0; i graph-vexNum; i) {set[i] 0;path[i] -1;dist[i] 9999;distance[i] 9999;}EBox* p graph-AdjList[v].firstEdge-nextEdge;while (p) {dist[p-toVex] p-cost;distance[p-toVex] p-distance;path[p-toVex] v;p p-nextEdge;}path[v] -1;set[v] 1;dist[v] 0;distance[v] 0;for (i 0; i graph-vexNum; i) {min 9999;for (j 0; j graph-vexNum; j) {if (set[j] 0 dist[j] min) {min dist[j];u j;}}set[u] 1;for (j 0; j graph-vexNum; j) {int cost getCost(graph, u, j);if (set[j] 0 dist[u] cost dist[j]) {dist[j] dist[u] cost;distance[j] getDistance(graph, u, j) distance[u];path[j] u;}}}}1.初始化。V为G中所有顶点集合path{v}。dist[x]表示从源点到x的已知路径的权值初始dist[v]为0其余为无穷大。2.从源点v开始运行一步广度优先算法即找其相邻点。3.计算可见点到源点v的路径长度更新dist[x]。然后对路径进行排序选择最短的一条作为确定找到的最短路径将其终点加入到path中.4.从path中选择新加入的点运行广度优先算法找其相邻点重复step3。直至所有点已加入S或者再搜索不到新的可见点图中存在不联通的点此时pathV终止算法。void printPath(Graph* graph,int path[], int v1) {//v1为终点索引,从终点往前打印路径if (path[v1] -1) {printf(%s, graph-AdjList[v1].name);}else {printPath(graph,path, path[v1]);//v1变为v1的前驱printf(---%s, graph-AdjList[v1].name);}}打印从起点v到终点v1的路径void shortestRoute(Graph* graph) {char start[30];char end[30];int dist[MAX], path[MAX], distance[MAX];//dist存储每条最短路径的花费总和path[i]存储索引为i的城市的的前驱结点索引distance存储每条最短路径的路程总和printf(\n请输入起点和终点用空格隔开:\n);scanf(%s %s, start,end);int v0 getLocation(graph, start);int v getLocation(graph, end);if (v0 ! -1 v ! -1) {DJ(graph, dist, distance, path, v0);if (dist[v] ! 9999) {printf(\n%s到%s费用最少的路线\n, start, end);printf(花费%d距离为%d公里\n, dist[v], distance[v]);printf(\n路线为\n);printPath(graph, path, v);printf(\n);}else {printf(\n%s到%s不连通所以无最短路径\n, start, end);}}else {printf(\n未找到此城市\n);}}输入起始点并输出其最短路径权值总和和最短路径。遍历运行结果测试用例编号输入预计输出实际输出实验结果评估1London Lisbon花费245距离为3000公里London--Paris--Bern--Madrid--Lisbon结果符合预期2LondonLondon花费0距离为0公里London符合预期3LisbonBucharest花费165距离4550公里Lisbon--Madrid--Bern--Sarajevo--Budapest--Bucharest符合预期4LisbonBelfast不连通无最短路径符合预期实验结果总结对每个实验分别进行测试总结实验一链表不要求在创建时就确定链表长度所以适合在不确定数据地数量时使用但是链表不能根据索引直接找到某个结点而要从头开始找因此链表的插入和删除效率比较低当数据量比较大而且要频繁地查找和删除数据时不推荐使用。实验二用栈来进行表达式求值的难点在于判断操作符的优先级在该实验中设置一个操作符数组用于获取运算符优先级。/* 存储运算符和界限符 */char OP[7] { , -, *, /, (, ), # };/* OP的优先级表 */char pre[][7] {{, , , , , , },{, , , , , , },{, , , , , , },{, , , , , , },{, , , , , , 0},{, , , , 0, , },{, , , , , 0, }};-*/#-*/#如下图所示a为当前读取的操作符b为当前操作符栈顶元素ab a的优先权高于,a不入栈操作数出栈与a后面的操作数作a运算结果入操作数栈ab a的优先权低于a入栈ab a的优先权等于加减乘除优先性都低于“”但是高于“”为了算法简洁在表达式的左边和右边虚设一个“#”这一对“#”表示一个表达式求值完成“”“”表示当一对括号相遇时表示括号内已运算完成。“”和“”、“#”和“(”、“(”和“#”无法相继出现如果出现则表达式出现语法错误。栈在表达式求值中有较为广泛的运用。实验三本实验需要从文件中读取数据来构建树还有从文件中读取问题并提取出关键字来在树中寻找相应的结果本实验让我对树的构建和基本操作以及文件读取字符串操作都得到了更深的理解。实验四本实验实现了图的创建遍历和求最短路径的操作其中最短路径问题为该实验的重难点在本实验中我使用了迪杰斯特拉算法本算法思路比较简单在不使用堆优化的情况下时间复杂度为O(E2),使用二叉堆后能优化到O((VE)logE),效率还是挺可观的。通过本实验我掌握了图的邻接表式创建和遍历以及常规迪杰斯特拉算法求最短路径。

相关新闻

114个Tracker服务器,凭什么让BT下载从“龟速“变“满速“?

114个Tracker服务器,凭什么让BT下载从“龟速“变“满速“?

114个Tracker服务器,凭什么让BT下载从"龟速"变"满速"? 【免费下载链接】trackerslist Updated list of public BitTorrent trackers 项目地址: https://gitcode.com/GitHub_Trending/tr/trackerslist 深夜两点,我…

2026/10/13 16:50:57 阅读更多 →
推荐几款chatGPT的浏览器插件供大家学习,教程如下

推荐几款chatGPT的浏览器插件供大家学习,教程如下

在前天的文章中,我们介绍了 ChatGPT 开放的全新模式 Web Browsing(网页浏览),启用后 ChatGPT 就可以开始上网,收集最新的互联网资料进行作答。今天我们讲讲 ChatGPT 另一个重要更新:插件集(Plug…

2026/10/12 23:31:46 阅读更多 →
Spark 本地调试怎么复现:缩小数据,不改变分区语义

Spark 本地调试怎么复现:缩小数据,不改变分区语义

Spark 本地调试怎么复现:缩小数据,不改变分区语义 Spark 任务本地能跑通,常常只是数据太小,没有触发真实问题。复现环境要缩小规模,但保留字段、分区、倾斜和空值这些关键特征。 准备最小数据集 从可公开或脱敏数据生成…

2026/10/11 6:10:10 阅读更多 →

最新新闻

AI工程化能力三支柱:数据智能、模型架构与系统交付

AI工程化能力三支柱:数据智能、模型架构与系统交付

1. 这不是“学AI”,而是构建一套可迁移、能落地的工程化能力体系很多人点开“AI培训学什么”这类标题,第一反应是找速成班、抄代码、背模型名字——结果学了三个月,连数据怎么清洗都卡在pandas报错上;或者花两万块报了“大模型实战…

2026/10/13 16:50:38 阅读更多 →
ASCII码与汉字编码:从乱码到UTF-8的完整解析

ASCII码与汉字编码:从乱码到UTF-8的完整解析

1. 从一段乱码说起:为什么你需要搞懂ASCII码你有没有遇到过这种情况:打开一个文本文件,里面全是“锟斤拷”或者“ ”这样的乱码,明明文件大小正常,内容却完全没法看。或者你在写程序的时候,把一个中文字符串…

2026/10/13 16:50:38 阅读更多 →
Spark on YARN GPU推理实战:资源调度、配置与性能调优

Spark on YARN GPU推理实战:资源调度、配置与性能调优

1. 为什么要在 Spark on YARN 上跑 GPU 推理把 AI 模型推理塞进 Spark on YARN 这套体系里,第一次听到的人多半会皱眉:推理不是应该用专门的在线服务框架吗,为什么要绕这么大一圈?我最初接手这个方向时也有同样的疑问,…

2026/10/13 16:50:38 阅读更多 →
MSP430G2553驱动RC522门禁系统实战:低功耗SPI时序与ISO14443-A协议精解

MSP430G2553驱动RC522门禁系统实战:低功耗SPI时序与ISO14443-A协议精解

简介:本资源是一套基于MSP430微控制器与MFRC522 RFID模块的嵌入式门禁系统完整工程,面向嵌入式初学者、电子设计竞赛备赛者及物联网硬件开发爱好者,解决低功耗门禁原型快速验证与软硬协同开发问题。压缩包共20个文件,含6个核心头文…

2026/10/13 16:50:38 阅读更多 →
IS95前向链路Rake接收机仿真:从物理层结构到多径合并的完整实现

IS95前向链路Rake接收机仿真:从物理层结构到多径合并的完整实现

简介:这份资源面向通信工程、无线通信课程学习者及CDMA仿真入门者,聚焦IS-95前向链路系统的建模与验证,帮助理解扩频调制、多径衰落与RAKE接收等核心机制。压缩包共13个文件,以10个m脚本、2个mat数据文件和1份doc说明文档为主&…

2026/10/13 16:50:38 阅读更多 →
SwiftUI中的Agent+Skill框架:摆脱if-else,构建可扩展的任务调度系统

SwiftUI中的Agent+Skill框架:摆脱if-else,构建可扩展的任务调度系统

项目名我起了个SwiftUI-Agent-Skill,翻译过来没啥歧义:一套跑在SwiftUI应用里的Agent技能框架。Agent在这里不是玄学,就是一个负责拆解用户意图、派发任务、汇总结果的调度核心;Skill则是挂在它下面的一个个独立能力模块&#xff…

2026/10/13 16:49:38 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →