一、顺序表和链表习题 

1. 顺序表就地逆置

#include <stdio.h>
// 定义顺序表结构
#define MAXSIZE 100
typedef struct {int data[MAXSIZE];int length;
} SqList;
// 就地逆置顺序表
void reverseList(SqList *L) {int i, temp;for (i = 0; i < L->length / 2; i++) {// 交换对称位置的元素temp = L->data[i];L->data[i] = L->data[L->length - 1 - i];L->data[L->length - 1 - i] = temp;}
}

2. 删除顺序表中值为 e 的所有元素

#include <stdio.h>
#define MAXSIZE 100
typedef struct {int data[MAXSIZE];int length;
} SqList;
// 删除值为 e 的所有元素
void deleteElem(SqList *L, int e) {int k = 0, i;// 统计值不为 e 的元素个数for (i = 0; i < L->length; i++) {if (L->data[i] != e) {L->data[k++] = L->data[i];}}L->length = k;
}

3. 有序顺序表中插入元素 e 保持有序

#include <stdio.h>
#define MAXSIZE 100
typedef struct {int data[MAXSIZE];int length;
} SqList;
// 有序插入元素 e
void insertElem(SqList *L, int e) {int i;// 找到插入位置for (i = L->length - 1; i >= 0 && L->data[i] > e; i--) {L->data[i + 1] = L->data[i];}L->data[i + 1] = e;L->length++;
}

4. 计算单链表中数据域值为 x 的结点个数

#include <stdio.h>
#include <stdlib.h>
// 定义单链表结点结构
typedef struct LNode {int data;struct LNode *next;
} LNode, *LinkList;
// 计算值为x的结点个数
int countNodes(LinkList L, int x) {int count = 0;LNode *p = L->next;while (p != NULL) {if (p->data == x) {count++;}p = p->next;}return count;
}

5. 判断单链表是否递增有序

#include <stdio.h>
#include <stdlib.h>
typedef struct LNode {int data;struct LNode *next;
} LNode, *LinkList;
// 判断链表是否递增有序
int isIncreasing(LinkList L) {LNode *p = L->next;if (p == NULL) {return 1; // 空链表视为有序}while (p->next != NULL) {if (p->data > p->next->data) {return 0; // 不是递增有序}p = p->next;}return 1; // 是递增有序
}

6. 单链表就地逆置

#include <stdio.h>
#include <stdlib.h>
typedef struct LNode {int data;struct LNode *next;
} LNode, *LinkList;
// 单链表就地逆置
void reverseList(LinkList L) {LNode *p = L->next;L->next = NULL;LNode *q;while (p != NULL) {q = p->next;p->next = L->next;L->next = p;p = q;}
}

第六题这个 LNode *p = L->next; L->next = NULL; LNode *q;没看懂

这段代码是单链表就地逆置算法的核心部分,我们可以逐步拆解来理解其原理:

LNode *p = L->next;  // 步骤1:初始化指针p,指向第一个实际节点(跳过头节点)
L->next = NULL;      // 步骤2:将头节点的next置空,作为逆置后链表的尾节点
LNode *q;            // 步骤3:声明临时指针q,用于保存后续节点

为什么这样做?

单链表的就地逆置采用头插法思想,核心是将原链表的节点逐个 "摘下",再反向插入到头节点后面:

  1. 指针 p 的作用p初始指向原链表的第一个节点(L->next),它负责遍历原链表的所有节点。

  2. L->next = NULL: 头节点Lnext置空后,原链表的头节点变成了逆置后链表的尾节点(尾节点的next必须为NULL)。

  3. 临时指针 q: 在每次移动p之前,用q保存p的下一个节点(q = p->next),防止原链表断裂后无法继续遍历。

完整逆置过程示例

假设原链表为:L(头节点) -> 1 -> 2 -> 3 -> NULL

  • 初始状态:p=1L->next=NULL

  • 第一次循环: q = p->nextq=2p->next = L->next1->next=NULLL->next = pL->next=1p = qp=2) 此时链表:L -> 1 -> NULL,剩余节点:2 -> 3 -> NULL

  • 第二次循环: q = p->nextq=3p->next = L->next2->next=1L->next = pL->next=2p = qp=3) 此时链表:L -> 2 -> 1 -> NULL,剩余节点:3 -> NULL

  • 第三次循环: q = p->nextq=NULLp->next = L->next3->next=2L->next = pL->next=3p = qp=NULL) 最终链表:L -> 3 -> 2 -> 1 -> NULL(完成逆置)

简单说,这段代码的作用是初始化逆置所需的指针,为后续的节点 "头插" 操作做准备,通过逐步移动指针实现链表方向的反转。

二、栈和队列的基本操作 

1. 顺序栈的基本操作

#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
// 顺序栈结构定义
typedef struct {int data[MAXSIZE];int top;
} SqStack;
// 初始化栈
void InitStack(SqStack *S) {S->top = -1;
}
// 判断栈空
int StackEmpty(SqStack S) {return S.top == -1;
}
// 入栈
int Push(SqStack *S, int e) {if (S->top == MAXSIZE - 1) {return 0;}S->top++;S->data[S->top] = e;return 1;
}
// 出栈
int Pop(SqStack *S, int *e) {if (StackEmpty(*S)) {return 0;}*e = S->data[S->top];S->top--;return 1;
}
// 获取栈顶元素
int GetTop(SqStack S, int *e) {if (StackEmpty(S)) {return 0;}*e = S.data[S.top];return 1;
}

2. 链栈的基本操作

#include <stdio.h>
#include <stdlib.h>
// 链栈结点结构定义
typedef struct StackNode {int data;struct StackNode *next;
} StackNode, *LinkStack;
// 初始化链栈
void InitStack(LinkStack *S) {*S = NULL;
}
// 判断链栈空
int StackEmpty(LinkStack S) {return S == NULL;
}
// 入栈
int Push(LinkStack *S, int e) {StackNode *p = (StackNode *)malloc(sizeof(StackNode));if (!p) {return 0;}p->data = e;p->next = *S;*S = p;return 1;
}
// 出栈
int Pop(LinkStack *S, int *e) {if (StackEmpty(*S)) {return 0;}StackNode *p = *S;*e = p->data;*S = p->next;free(p);return 1;
}
// 获取栈顶元素
int GetTop(LinkStack S, int *e) {if (StackEmpty(S)) {return 0;}*e = S->data;return 1;
}

3. 循环队列的基本操作

#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
// 循环队列结构定义
typedef struct {int data[MAXSIZE];int front, rear;
} SqQueue;
// 初始化循环队列
void InitQueue(SqQueue *Q) {Q->front = Q->rear = 0;
}
// 判断循环队列空
int QueueEmpty(SqQueue Q) {return Q.front == Q.rear;
}
// 入队
int EnQueue(SqQueue *Q, int e) {if ((Q->rear + 1) % MAXSIZE == Q->front) {return 0;}Q->data[Q->rear] = e;Q->rear = (Q->rear + 1) % MAXSIZE;return 1;
}
// 出队
int DeQueue(SqQueue *Q, int *e) {if (QueueEmpty(*Q)) {return 0;}*e = Q->data[Q->front];Q->front = (Q->front + 1) % MAXSIZE;return 1;
}
// 获取队头元素
int GetHead(SqQueue Q, int *e) {if (QueueEmpty(Q)) {return 0;}*e = Q.data[Q.front];return 1;
}

4. 链队列的基本操作

#include <stdio.h>
#include <stdlib.h>
// 链队列结点结构定义
typedef struct QNode {int data;struct QNode *next;
} QNode, *QueuePtr;
// 链队列结构定义
typedef struct {QueuePtr front, rear;
} LinkQueue;
// 初始化链队列
void InitQueue(LinkQueue *Q) {Q->front = Q->rear = (QueuePtr)malloc(sizeof(QNode));if (!Q->front) {exit(1);}Q->front->next = NULL;
}
// 判断链队列空
int QueueEmpty(LinkQueue Q) {return Q.front == Q.rear;
}
// 入队
int EnQueue(LinkQueue *Q, int e) {QueuePtr p = (QueuePtr)malloc(sizeof(QNode));if (!p) {return 0;}p->data = e;p->next = NULL;Q->rear->next = p;Q->rear = p;return 1;
}
// 出队
int DeQueue(LinkQueue *Q, int *e) {if (QueueEmpty(*Q)) {return 0;}QueuePtr p = Q->front->next;*e = p->data;Q->front->next = p->next;if (Q->rear == p) {Q->rear = Q->front;}free(p);return 1;
}
// 获取队头元素
int GetHead(LinkQueue Q, int *e) {if (QueueEmpty(Q)) {return 0;}*e = Q.front->next->data;return 1;
}

三、顺序表、单链表基本操作

1. 顺序表的基本操作

#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
// 顺序表结构定义
typedef struct {int data[MAXSIZE];int length;
} SqList;
// 初始化顺序表
void InitList(SqList *L) {L->length = 0;
}
// 插入元素
int ListInsert(SqList *L, int i, int e) {if (i < 1 || i > L->length + 1 || L->length >= MAXSIZE) {return 0;}for (int j = L->length; j >= i; j--) {L->data[j] = L->data[j - 1];}L->data[i - 1] = e;L->length++;return 1;
}
// 删除元素
int ListDelete(SqList *L, int i, int *e) {if (i < 1 || i > L->length) {return 0;}*e = L->data[i - 1];for (int j = i; j < L->length; j++) {L->data[j - 1] = L->data[j];}L->length--;return 1;
}
// 查找元素
int LocateElem(SqList L, int e) {for (int i = 0; i < L.length; i++) {if (L.data[i] == e) {return i + 1;}}return 0;
}

2. 单链表的基本操作

#include <stdio.h>
#include <stdlib.h>
// 单链表结点结构定义
typedef struct LNode {int data;struct LNode *next;
} LNode, *LinkList;
// 初始化单链表
void InitList(LinkList *L) {*L = (LNode *)malloc(sizeof(LNode));if (!*L) {exit(1);}(*L)->next = NULL;
}
// 头插法创建单链表
void CreateListHead(LinkList *L, int n) {LinkList p;*L = (LNode *)malloc(sizeof(LNode));(*L)->next = NULL;for (int i = 0; i < n; i++) {p = (LNode *)malloc(sizeof(LNode));scanf("%d", &p->data);p->next = (*L)->next;(*L)->next = p;}
}
// 插入元素
int ListInsert(LinkList *L, int i, int e) {LinkList p = *L, s;int j = 0;while (p && j < i - 1) {p = p->next;j++;}if (!p || j > i - 1) {return 0;}s = (LNode *)malloc(sizeof(LNode));s->data = e;s->next = p->next;p->next = s;return 1;
}
// 删除元素
int ListDelete(LinkList *L, int i, int *e) {LinkList p = *L, q;int j = 0;while (p->next && j < i - 1) {p = p->next;j++;}if (!p->next || j > i - 1) {return 0;}q = p->next;*e = q->data;p->next = q->next;free(q);return 1;
}
// 查找元素
LNode *LocateElem(LinkList L, int e) {LNode *p = L->next;while (p && p->data != e) {p = p->next;}return p;
}

四、问答题 

问题 1:循环队列的优点,判断循环队列的空和满

  • 优点:循环队列解决了普通顺序队列 “假溢出” 的问题,能充分利用队列的存储空间。
  • 判空:当队头指针front等于队尾指针rear时,循环队列为空。
  • 判满:通常采用 “牺牲一个单元” 的方法,即当 (rear + 1) % 队列长度 == front 时,循环队列为满。

问题 2:栈和队列的区别

  • 栈的特点:是一种 “先进后出”(FILO)的线性数据结构,元素只能从栈顶进行插入和删除操作。
  • 队列的特点:是一种 “先进先出”(FIFO)的线性数据结构,元素从队尾插入,从队头删除。
  • 使用场景
    • 栈:常用于函数调用、递归实现、表达式求值(如中缀转后缀)、括号匹配等场景,比如在递归函数执行时,调用栈保存函数的调用信息。
    • 队列:常用于任务调度(如操作系统中的进程调度)、消息队列、广度优先搜索(BFS)等场景,比如打印任务队列,按提交顺序依次打印。

问题 3:递归

  • 递归:是指在函数的定义中直接或间接调用自身的一种方法。
  • 优点:代码简洁,能清晰地表达问题的求解思路,尤其是对于具有递归性质的问题(如斐波那契数列、树的遍历等),递归实现更直观。
  • 缺点:可能会存在栈溢出的风险(当递归深度过大时);并且由于递归过程中需要保存大量的调用栈帧,在时间和空间效率上可能不如非递归实现。

问题 4:递归借助什么数据结构执行,入口语句和出口语句一般用什么语句实现

  • 数据结构:递归程序在执行时,借助栈(系统栈或自定义栈)来实现,系统会自动为递归函数的每次调用创建栈帧,保存局部变量、返回地址等信息。
  • 入口与出口语句
    • 入口语句:一般通过函数自身的调用来实现,即递归调用语句。
    • 出口语句:通常用条件判断语句(如if语句)来实现递归的终止条件,当满足该条件时,不再进行递归调用,开始返回。

五、题5 

问题①

问题② (解决方法:画试管图)

(1)判断 435612 是否能得到

不能。

  • 分析:出栈序列中,当 4、3、5、6 依次出栈后,栈中剩余元素为 1、2(1 在栈底,2 在 1 之上)。此时下一个要出栈的是 1,但根据栈 “先进后出” 的特性,2 在 1 上面,必须 2 先出栈,1 才能出栈,所以无法得到 435612 这个出栈序列。

(2)判断 325641 是否能得到

能。

  • 进栈出栈序列:
    • 进栈 1、进栈 2、进栈 3;出栈 3、出栈 2;
    • 进栈 4、进栈 5;出栈 5;
    • 进栈 6;出栈 6;
    • 出栈 4、出栈 1。

(3)判断 154623 是否能得到

不能。

  • 分析:出栈序列中,1 先出栈后,进栈 2、3、4、5;然后 5、4 出栈,此时栈中元素为 2、3(2 在栈底,3 在 2 之上)。接下来要出栈的是 6,进栈 6 后出栈 6,之后要出栈的是 2,但 3 在 2 上面,必须 3 先出栈,2 才能出栈,所以无法得到 154623 这个出栈序列。

(4)判断 135426 是否能得到

能。

  • 进栈出栈序列:
    • 进栈 1;出栈 1;
    • 进栈 2、进栈 3;出栈 3;
    • 进栈 4、进栈 5;出栈 5;
    • 出栈 4、出栈 2;
    • 进栈 6;出栈 6。

六、题6 

画试管分层图可得3

七、题7 

八、题8 

循环队列结构定义

#include <stdio.h>
#include <stdlib.h>typedef struct {int *data;     // 存储数据的数组int front;     // 队头指针int rear;      // 队尾指针int capacity;  // 数组容量int size;      // 队列中元素个数
} DynamicCircularQueue;

初始化队列

void initQueue(DynamicCircularQueue *queue, int initCapacity) {queue->data = (int *)malloc(initCapacity * sizeof(int));if (!queue->data) {printf("内存分配失败\n");exit(1);}queue->front = 0;queue->rear = 0;queue->capacity = initCapacity;queue->size = 0;
}

入队操作(支持扩容)

int enQueue(DynamicCircularQueue *queue, int value) {// 队列满,扩容if (queue->size == queue->capacity) {int newCapacity = queue->capacity * 2;int *newData = (int *)malloc(newCapacity * sizeof(int));if (!newData) {printf("内存分配失败\n");return 0;}// 复制原队列元素到新数组int j = 0;for (int i = queue->front; i != queue->rear; i = (i + 1) % queue->capacity) {newData[j++] = queue->data[i];}free(queue->data);queue->data = newData;queue->front = 0;queue->rear = j;queue->capacity = newCapacity;}// 入队queue->data[queue->rear] = value;queue->rear = (queue->rear + 1) % queue->capacity;queue->size++;return 1;
}

出队操作(支持缩容)

int deQueue(DynamicCircularQueue *queue, int *value) {if (queue->size == 0) {printf("队列为空\n");return 0;}*value = queue->data[queue->front];queue->front = (queue->front + 1) % queue->capacity;queue->size--;// 元素数量少于容量的1/4且容量大于初始容量,缩容if (queue->size < queue->capacity / 4 && queue->capacity > 10) {int newCapacity = queue->capacity / 2;int *newData = (int *)malloc(newCapacity * sizeof(int));if (!newData) {printf("内存分配失败\n");return 0;}// 复制原队列元素到新数组int j = 0;for (int i = queue->front; i != queue->rear; i = (i + 1) % queue->capacity) {newData[j++] = queue->data[i];}free(queue->data);queue->data = newData;queue->front = 0;queue->rear = j;queue->capacity = newCapacity;}return 1;
}

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

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

相关文章

【Java实战㉞】从0到1:Spring Boot Web开发与接口设计实战

目录一、Spring Boot Web 基础配置1.1 Web 起步依赖&#xff08;spring-boot-starter-web 导入与核心组件&#xff09;1.2 内置服务器配置&#xff08;Tomcat 端口、线程池、连接超时设置&#xff09;1.3 静态资源访问&#xff08;静态资源存放路径、自定义资源映射&#xff09…

房屋安全鉴定机构评价

房屋安全鉴定机构评价&#xff1a;如何选择专业可靠的检测服务在建筑行业快速发展的今天&#xff0c;房屋安全鉴定已成为保障建筑安全、预防事故的重要环节。面对市场上众多的房屋安全鉴定机构&#xff0c;如何科学评价并选择一家专业可靠的服务提供方&#xff0c;是许多业主、…

【算法专题训练】19、哈希表

1、哈希表基础知识 以键值对的方式进行数据存储优点&#xff1a;哈希表数据结构在插入、删除或查找一个元素时&#xff0c;都只需要O(1)的时间 哈希表设计三要点&#xff1a; 为了快速确定一个元素在哈希表中的位置&#xff0c;可以使用一个数组&#xff0c;元素的位置为他的…

某光伏电力监控系统网络安全监测项目:智能组网技术优化方案实践

背景与挑战随着光伏电力行业的快速发展&#xff0c;光伏电站的规模和分布范围日益扩大。电力监控系统作为光伏电站的核心平台&#xff0c;其网络安全直接关系到电力生产的稳定性与可靠性。然而&#xff0c;光伏场站通常分布在偏远地区&#xff0c;网络环境复杂&#xff0c;传统…

GEE训练教程:基于Landsat 8卫星影像识别并提取指定区域内无云覆盖的区域多边形,最终导出为矢量文件

简介 本文使用Google Earth Engine平台,通过Landsat 8卫星影像识别并提取指定区域内无云覆盖的区域多边形,最终导出为矢量文件。主要步骤包括:定义研究区域、创建云检测算法、筛选高质量影像、将无云区域转换为矢量多边形,并进行可视化检查和数据导出。 使用Google Earth…

UniApp 页面通讯方案全解析:从 API 到状态管理的最佳实践

在 UniApp 跨端开发中&#xff0c;组件与页面间的通讯是核心需求。无论是父子组件交互、跨页面数据传递&#xff0c;还是全局状态共享&#xff0c;选择合适的通讯方案直接影响代码的可维护性和性能。本文将系统对比 uni.$emit 系列 API、状态管理库&#xff08;Vuex/Pinia&…

【c++进阶系列】:万字详解AVL树(附源码实现)

&#x1f525; 本文专栏&#xff1a;c &#x1f338;作者主页&#xff1a;努力努力再努力wz &#x1f4aa; 今日博客励志语录&#xff1a; 路在脚下延伸时&#xff0c;不必追问终点何在。你迈出的每一步&#xff0c;都在重新定义世界的边界 ★★★ 本文前置知识&#xff1a; …

前端日志回捞系统的性能优化实践|得物技术

一、前言在现代前端应用中&#xff0c;日志回捞系统是排查线上问题的重要工具。然而&#xff0c;传统的日志系统往往面临着包体积过大、存储无限膨胀、性能影响用户体验等问题。本文将深入分析我们在dw/log和dw/log-upload两个库中实施的关键性能优化&#xff0c;以及改造过程中…

【QT随笔】结合应用案例一文完美概括QT中的队列(Queue)

【QT随笔】结合应用案例一文完美概括QT中的队列&#xff08;Queue&#xff09; 队列&#xff08;Queue&#xff09;是一种线性数据结构&#xff0c;其核心规则为先进先出&#xff08;FIFO, First-In-First-Out&#xff09;&#xff1a; 新元素在队尾插入&#xff08;enqueue&a…

At least one <template> or <script> is required in a single file component

环境rspack vue3原因rule 中配置了两个vue-loader删掉一个即可。

LangChain实战(十八):构建ReAct模式的网页内容摘要与分析Agent

本文是《LangChain实战课》系列的第十八篇,将深入讲解如何构建一个基于ReAct模式的智能网页内容摘要与分析Agent。这个Agent能够自主浏览网页、提取关键信息、生成智能摘要,并进行深入的内容分析,让信息获取和理解变得更加高效。 前言 在信息爆炸的时代,我们每天都需要处理…

debian11 ubuntu24 armbian24 apt install pure-ftpd被动模式的正确配置方法

debian11 ubuntu24 armbian24 apt install pure-ftpd被动模式的正确配置方法 安装方法请看&#xff1a;https://www.itbulu.com/pure-ftpd.html 疑难问题解决 原本以为配置很简单的&#xff0c;无非是修改 ForcePassiveIP MinUID PassivePortRange PureDB这几个配置项就行了…

量化金融|基于算法和模型的预测研究综述

一、研究背景与发展历程​​1.​​量化投资理论演进​​•奠基阶段&#xff08;1950s-1960s&#xff09;​​&#xff1a;Markowitz均值方差理论&#xff08;1952&#xff09;、CAPM模型&#xff08;1964&#xff09;奠定现代量化投资基础•衍生品定价&#xff08;1970s-1980s&…

从零开始的云计算生活——第六十天,志在千里,使用Jenkins部署K8S

一.安装kubectl1、配置yum源cat <<EOF | tee /etc/yum.repos.d/kubernetes.repo [kubernetes] nameKubernetes baseurlhttps://mirrors.aliyun.com/kubernetes-new/core/stable/v1.28/rpm/ enabled1 gpgcheck1 gpgkeyhttps://mirrors.aliyun.com/kubernetes-new/core/sta…

无人机电压模块技术剖析

无人机电源模块的基本运行方式无人机电压模块的核心任务是对动力电源&#xff08;通常是锂电池&#xff09;进行转换、调节和分配&#xff0c;为飞控、图传、摄像头、舵机等各个子系统提供稳定可靠的电能。其运行方式可以概括为&#xff1a;电压转换与调控&#xff1a;无人机动…

MATLAB基于GM(灰色模型)与LSTM(长短期记忆网络)的组合预测方法

一、GM与LSTM的基本原理及互补性 1. GM模型的核心特点基本原理&#xff1a;通过累加生成&#xff08;AGO&#xff09;将原始无序序列转化为具有指数规律的光滑序列&#xff0c;建立一阶微分方程&#xff08;如GM(1,1)&#xff09;进行预测。其数学形式为&#xff1a; dx(1)dtax…

【菜狗每日记录】启发式算法、傅里叶变换、AC-DTC、Xmeans—20250909

&#x1f431;1、启发式算法 ① 定义 ② 特点 ③ 案例 &#x1f431;2、快速傅里叶变换FFT ① DFT离散傅里叶变换 ② FFT快速傅里叶变换 &#x1f431;3、AC-DTC聚类 &#x1f431;4、Xmeans &#x1f431;1、启发式算法 启发式算法是和最优化算法相对的。 一般而言&am…

Axure移动端选择器案例:多类型选择器设计与动态效果实现

在移动端交互设计中&#xff0c;选择器是用户输入的核心组件。Axure移动端高保真元件库提供了四种关键选择器解决方案&#xff0c;通过动态效果提升操作真实感&#xff1a; 预览地址&#xff1a;Axure 1. 基础选择器 采用底部弹窗设计&#xff0c;支持单选项快速选择。点击触发…

Spring Boot图片验证码功能实现详解 - 从零开始到完美运行

Spring Boot图片验证码功能实现详解 - 从零开始到完美运行 &#x1f4d6; 前言 大家好&#xff01;今天我要和大家分享一个非常实用的功能&#xff1a;Spring Boot图片验证码。这个功能可以防止恶意攻击&#xff0c;比如暴力破解、刷票等。我们实现的是一个带有加减法运算的图片…

HarmonyOS实现快递APP自动识别地址

​ 大家好&#xff0c;我是潘Sir&#xff0c;持续分享IT技术&#xff0c;帮你少走弯路。《鸿蒙应用开发从入门到项目实战》系列文章持续更新中&#xff0c;欢迎关注&#xff01; 随着鸿蒙&#xff08;HarmonyOS&#xff09;生态发展&#xff0c;越来越多的APP需要进行鸿蒙适…