考研408笔记之数据结构(三)——串
数据结构(三)——串
1. 串的定义和基本操作
本节内容很少,重点是串的模式匹配,所以对于串的定义和基本操作,我就简单提一些易错点。另外,串也是一种特殊的线性表,只不过线性表是可以存储任何东西,而串只能存储字符。除此以外,我们进行串的查找时,很少查找单个字符,一般情况下是进行子串查取。
1.1 串的定义

上面是串的定义,以及一些有关串的术语的定义。
但是有几个易错点需要指出:
- 串的长度是不包含两侧引号的,例如S="hello world!"的长度是12,而非14。
- 在串里,空格也要占1位长度。例如S=“n h”的长度是3。另外,由空格组成的串叫空格串。
- 确定子串在主串中的位置,其实就是确定子串的第一个字符在主串中的位置。
- 查找串里某个字符的位置,从第一字符开始查找时,要从1开始查起,而不是从0开始查。
1.2 串的基本操作

串的基本操作全在上图,这里说下几个需要注意的点:
- 区分清空操作和销毁串:清空操作是将串中字符情况,但是串本身的存储位置还在。而销毁操作,是将整个串都给销毁,无法在原地址上找到该串,要想使用串需重新分配存储空间。
- 串连接操作,是将两个串拼凑在一起,这个时候可能需要开辟存储空间,所以如果程序里多次使用串连接操作,要使用易扩展的存储结构。
- 定位操作,要在主串里找到子串,涉及到了匹配算法,也是我们这一章的重点,后面会细讲。
- 比较操作,注意比较两个字符串,并不是谁长谁就大,而是从第一个字符开始一位一位进行比较,当出现两个字符不同的时候,哪个字符大,哪个字符串就大。例如S=“abcd”,M=“acb”,两个字符串第一位全是a,所以比较第二位,而b<c,所以M>S。若两个字符串相等,则两个字符串一定相同。注意,这里b<c,并不是按英语里的排序,而是在计算机对字母的编码大小,一般情况下,计算机对字母使用ASCLL码进行编码,而在ASCLL码表里b的二进制表示小于c的二进制表示,所以c>b。如果有不理解的地方可以去看看视频串的定义和基本操作
2. 串的存储结构
2.1 串的顺序存储
同线性表,串的顺序存储也有两种创建方式,一使用静态数组进行顺序存储。二使用动态数据进行顺序存储。
//静态数组创建存储空间
#define MaxSize 255 //定义串的最大长度
typedef struct {char ch[MaxSize]; //每个分量存储一个字符int length; //串当前长度
}SString;
//动态数组创建存储空间
typedef struct {char* ch; //定义ch指针,指向串首地址int length; //串的长度
}HString;

在不同教材里顺序存储方式有所差别,以下给出4种方案,第一种方案在末尾使用int(不一定int,也可是其他数据类型)记录存储长度,这样更容易获得长度,且范围足够。第二种让ch[0]充当length,这样可以使字符的位序和数组下标相同,但是ch[0]仅有一个字节,表示最大长度为255,存储的长度有限。方案三在结尾以‘\0’结尾,没有length变量,这样每次获得长度就需要我们去遍历。第四种综合了第1种和第2种方案,所以也综合了1,2两种的优点,不出意外,我们接下来对于串的基本操作的实现,都基于第4种方案进行设计。

2.2 串的链式存储
这里可以看到,1个字符占1个存储空间,但是在一个32位系统里,一个指针占4个bit的存储空间。如果我们每个结点只存放一个字符,那就会有大量空间被浪费。所以我们可以采用一个存储结点放4个字符,这样可以平衡存储空间的利用。
//链式存储
typedef struct StringNode {//char ch; //每个结点存放一个字符char ch[4]; //每个结点存放4个字符struct String* next; //指向下一个结点
}StringNode, *String;

2.3 串的基本操作实现
串的基本操作在1.2已展示,由于串就是一种特殊的线性表,而前面的线性表、栈、队列等,我们已对增删改查、初始化、判空等基本操作进行反复书写,这里为了节省时间便展示几个重要的操作的程序设计。
2.3.1 求子串

求子串,就是将字符串里第i个位置起,将长度为len的子串给取出来。注意,我们上图里采用的是2.1里几种存储方法的第4种,所以数组下标为0的位置没有进行数据存储。
//求子串
bool SubString(SString& Sub, SString S, int pos, int len) {if (pos + len - 1 > S.length) //判断字符串长度return false;for (int i = pos; i < pos + len; i++) //从pos位置将len长度子串取出Sub.ch[i - pos + 1] = S.ch[i];Sub.length = len;return true;
}
2.3.2 字符串比较

字符串比较,从首位开始一位一位比较,如果出现两个字符串同一位置字符不同,则哪个字符大,哪个字符串就大;若相同,接着往下比较。若两个字符串被扫描的地方都一样,则谁长谁大。若完全一样,则相等。
//字符串比较,若S>T,则返回值>0;若S<T,则返回值<0;
int StrCompare(SString S, SString T) {for (int i = 0; i < S.length && i <= T.length; i++) {if (S.ch[i] != T.ch[i]) //判相等return S.ch[i] - T.ch[i]; //不相等返还S.ch[i] - T.ch[i]的值}return S.length - T.length; //若数据匹配完,谁长谁大
}
2.3.3 求子串位置

这里我们可以使用这样一种思路,结合前面两种操作,从第1位每次从主串里取要求子串长度,然后与要求子串进行比较,相同则返回首位下标,不同则让主串里所取的位置往后移一位再进行取串比较的操作。通过这种思想,我们可以结合2.3.1和2.3.2,使用2.3.1取串,然后通过2.3.2比较。如果取到最后发现没有与要求子串相等的串,则说明该主串里不存在要求子串。
//求子串位置操作
int Index(SString S, SString T) {int i = 1, n = StrLength(S), m = StrLength(T); //获取子串和主串长度SString sub; //暂存子串while (i <= n - m + 1){SubString(sub, S, i, m); //取子串if (StrCompare(sub, T) != 0) //判相等++i; //不等进入下轮取串判等操作else //相等返回串头下标return i;}return 0;
}
3. 朴素模式匹配算法
首先介绍两个概念——主串和模式串
主串:一组数据较长的字符串。
模式串:一组数据较少的字符串。
这里要区分子串和模式串,子串一定可以在主串里找到,而模式串不一定能在主串里找到。
字符串的模式匹配:在主串中找到与模式串相同的子串,并返回其所在位置。
字符串匹配有两种算法,一种朴素匹配,一种KMP。
这里我们先介绍朴素模式匹配。

朴素模式匹配算法的具体过程如下,假设主串长度为n,模式串长度为m,m<n。则从主串第1个位置开始,取长度为m的子串,与模式串进行匹配,不相等,则将所取子串的首位向后移动一位,再进行取串,判相等操作。最多匹配n-m+1个子串。到这里,我们就会发现,所谓朴素模式匹配算法和我们前面2.3.3里所说的求子串方法一样,只不过这里出现了可能找不到的情况。
所以,联系前面的求子串算法,我们很容易写出如下的朴素模式匹配算法:
//朴素模式匹配算法
int Index(SString S,SString T){int i=1,j=1; //定义主串与模式串的起始匹配位置while(i<=S.length && j<=T,length){if(S.ch[i] == T.ch[j]){ //如果两个串当前匹配位置相等,继续后移匹配++i; ++j;}else{i=i-j+2; //匹配失败,进行下一轮初始化待匹配状态j=1}}if(j>T.length) //匹配结束以后,如果j大于模式串长,说明匹配成功return i>T.length;elsereturn 0; //j小于模式串长,匹配失败
}
为了更方便我们理解这个算法,这里以一个实例的匹配过程,作为演示,来进行算法详解。

首先,用i指向主串S的下标1的地方,j指向模式串T的下标为1的地方。从主串S里取出第一组与模式串T等长的子串,同时令i,j后移进行每一位判相等操作。从上图可以看到,当i=j=6时,两个串不相同,于是令j回到模式串T的数组下标为1的地方,但是i回到的应该是1的下一位,即数组下标为2的地方。这里,我们可以发现i每次回去的值等于i-j+2,即令当前S串中被匹配的长度i减去模式串S中被匹配的长度j,此时i会回到第一个匹配位的前一位,这时候加2即可令i指向第一个匹配位的下一位,也即下一个匹配子串的第一个位置。

接下来是第二个子串与模式串比较过程,可以发现两个串的第一位就不相同,于是i应指向3,即第三个子串的首位,而j仍然在模式串1的位置。

第三轮匹配,发现主串中第三个子串与模式串T相等,这个时候两者就相同,由于是判断一位相同,然后再移动到下一位,所以当我们的模式串最后一位也被判断相同时,此时j还会再加1,这时j的数值大于模式串T的数值,所以,我们可以用i-T.length>0来判断相等。
说完了算法以及算法的运行过程,就要谈论评价一个算法必不可少的东西——时间复杂度。

在朴素模式匹配算法里,假设模式串长m(即每次都要匹配m个字符),主串长n(要匹配n-m+1个串):
最优的时间复杂度:第一次匹配m个字符就匹配成功,所以最快时间复杂度=O(m)。
最坏时间复杂度:最后一个串匹配,才匹配成功,则要匹配n-m+1次m个字符,即O(mn-m2+m)=O(mn)。
最后进行一个简短的思维图总结:

4. KMP算法
写在开头:这一部分我写的有点简陋,主要是因为这部分内容是串这一章的核心,讲清比较繁琐,我只能在我的基础上进行一些重点指出,这样不会浪费时间,也能帮助我复习,有问题的可以跳转看视频:KMP
4.1 KMP基础
在前面,我们学习的朴素匹配算法里,如果匹配失败,主串前进了m步,就要退回m-1步,模式串要将数据指针指向头部。这样有大量时间消耗在回溯的过程上,所以为了减少这种时间消耗,提出了KMP匹配算法。
KMP算法就是在主串回溯位置上做了手脚,我们可以通过特殊的方法,使主串不进行回溯,同时对模式串每次回溯的位置进行确定,从而减少过多回溯产生的时间消耗。比如在bababaccd里找babac,我们第一次匹配时,会发现babab和babac最后一位不相同,按照朴素匹配算法,我们会将两者指针都回溯到最初位置。但我们可以发现,不将主串回溯,将模式串回溯到babac里第二个b的位置,也可以实现匹配成功,所以这就是我们优化后的KMP算法,而KMP算法的核心就是要找到我们在模式串里匹配失败时,对应该位应回溯的位置。
接下来以一个匹配过程作为演示,来进行KMP的介绍:

模式串匹配在最后一位(第6位)没有匹配成功,此时j回溯到1位。

当j=5时发生了不匹配,此时将j回溯到2。
综上,当j=4,3,2,1时匹配失败都要回溯对应位置,我们将其总结如下。

这里我们可以采用一个数组将每个不匹配位置的j要回溯的数位统计下来。然后在匹配失败时,从数组里提取要回溯的位置。
注意:
(1)在第1位匹配失败,理论上应保持不变,但却让其回溯到0,这是为了更方便代码的实施,可以联系接下来的算法代码理解。
(2)在回溯时出现可能会出现多个回溯位都可以的情况,例如从主串ababababababc里匹配模式串abababac,第一次匹配时,在c的位置出现匹配出错,此时可回溯到ababab,也可以回溯到abab,还可以回溯到ab,出现这种情况,要选择最大前缀(前缀和后缀的知识在下面补充,但大家应该都有基础,这里应该可以理解什么是前缀什么是后缀)回溯,即选择最长的那个进行回溯。
(3)如果从主串abccabca里匹配模式串abca,会发现在第4个位置匹配失败,这个时候要回溯到模式串头再次匹配,实际上,第4位的a匹配失败,我们就已经可以知道开头a的匹配肯定失败,但计算机依然会进行一次运算,这就是KMP所存在的缺点,从这里就可以发现KMP也存在非最优解。
接下来就着重说一下KMP的核心,next数组(模式串回溯数组)怎么求。
4.2 next数组求解

在next数组求解前,先补充一下概念——串的前缀和串的后缀。
串的前缀:包含第一个字符,且不包含最后一个字符的子串。
串的后缀:包含最后一个字符,且不包含第一个字符的子串。
求next数组的公式:假设第j个字符匹配失败,由前1~j-1个字符组成的串记为S,则:next[j]=S的最长相等前后缀长度+1
接下来以一道练习题加深印象。

这里我仅以j=5举例,其余的大家可以自己算。
j=5,则S=4,在aaaa里的最长前后相等缀为aaa=aaa,所以next[5]=3+1=4。
另外,j=1和2时,不论模式串有多长,他们的最长相等前后缀都为0,而为了匹配算法,所以1特定为0。在手算时,为了节省时间,我们可以直接写next[1]=0,next[2]=1。

上面是书上给出的next[j]求解公式,方法并不唯一,大家也可以根据自己的理解写自己的推导公式。
4.3 KMP算法
说了半天,我们已经可以理解KMP算法的大致流程以及实现过程。接下来我们就可以对KMP算法进行代码书写以及性能分析。
//next数组求解
void get_next(SString T, int next[]) {int i = 1, j = 0;next[1] = 0;while (i<T.length){if (j == 0 || T.ch[i] == T.ch[j]) {++i; ++j;next[i] = j;}elsej = next[j];}
}
这里next数组的算法求解可能有点难以理解(我就没理解),所以我找了一个视频讲解,大家没看懂想弄懂的可以看一下:KMP算法next数组代码讲解
//KMP匹配
int Index_KMP(SString S, SString T) {int i = 1, j = 0;int next[T.length+1]; //这里加1,是因为我们使用2.1里的第四种存储方法,数组首位空出get_next(T, next); //求模式串T的next数组while (i<=S.length&&j<=T.length){if (j == 0 || T.ch[i] == T.ch[j]) {++i; ++j; //逐级匹配}elsej = next[j]; //匹配失败}if (j > T.length)return i - T.length; //匹配成功elsereturn 0; //匹配失败
}

在这里,求next数组,假设模式串长m,get_next的时间复杂度可以简单认为是O(m)。
假设主串的长度为n,则匹配过程的时间复杂度可以简单认为是O(n)。
KMP算法的时间复杂度就可以认为是O(m+n)。
这里的理解是比较粗糙的,实际上的计算过程可能要考虑很多且很复杂。不过大家记住这个结论就好。

上面是对KMP算法与朴素模式匹配算法的一个简短总结与比较。大家可以看一下。
4.4 KMP算法优化
在4.1的注意事项里的第三条,我们说过,如果出现匹配失败的位置上的字符与模式串回溯位置的字符相同,则会出现多匹配的情况,这里,我们就说一下如何解决这种情况。

如上图,我们在i=j=3的位置出现匹配失败,如果根据常规的next数组,此时next[3]=1,我们回溯到j=1的位置,显然j=1与i=3的位置仍会匹配失败,这次失败,我们就会将j=1处根据next数组再进行回溯。既然如此,我们为什么不在一开始就令next[3]=next[1]=0呢?
提到这里,很多人就可以想到KMP的优化思路,就是优化next数组,获得一个新的nextval数组。
这里说下我对nextval数组的理解,希望能帮助大家更好的理解。我对nextval数组的理解其实就是一个带前继的链表,这个表的前继里指向着串里字符的回溯数据位置,数据域里存放该位置字符。如果一个结点数据域里的字符与前继结点里的字符相等,则他的前继里所指向的最终位置应该是前一个结点的前继所指向的位置,如果前一个结点的前继所指向的位置里的数据域与前一个结点数据域里的值一样,则应该继续向前指向,直到前面数据里的值与后一个结点里的数据域值不一样,才算指到最终位置,而这个最终的位置,就是我们要回溯到的位置,也就是nextval数组里对应字符应回溯的位置。
根据上面所说,我们可以得到nextval数组的优化思路,先写出next数组,然后判断匹配失败j处的字符是否等于其next[j]里所指向回溯位置的字符,如果不相等,则其回溯位置,就是其求出的next数组所要回溯的位置,即nextval[j]=next[j];如果相等,则其回溯位置,应与其next数组里所指的回溯位置的字符的最终回溯位置相同。
这里我们可以写出nextval求解算法:
nextval[1]=0;
for (int j=2 ; j<=T.length ; j++){if(T.ch[next[j]] == T.ch[j]) //当前位置字符与回溯位置字符相等nextval[j] = nextval[next[j]]; //nextval应等于回溯位置字符的nextvalelse //不等nextval[j] = next[j]; //nextval就是next
}

这里给出一道练习题,大家可以做一做加深理解,毕竟看的再多,不消化相当于没看。
写在最后:该系列笔记是本人在25考研备考408过程中根据王道课程所整理的复习笔记,原本放在个人网站方便自己复习所用。现考完以后,为了给个人网站减负,故将其全部移植到CSDN上。笔记中会存在一些错别字和输入法错误,不过考完以后,实在不想再去纠错,所以欢迎大家在评论区中指出,博主看到以后会进行纠正。
相关文章:
考研408笔记之数据结构(三)——串
数据结构(三)——串 1. 串的定义和基本操作 本节内容很少,重点是串的模式匹配,所以对于串的定义和基本操作,我就简单提一些易错点。另外,串也是一种特殊的线性表,只不过线性表是可以存储任何东…...
Java 和 JavaScript 的区别
尽管名字相似,JavaScript 的名字中带有 “Java”,确实让很多人误以为它与 Java 有紧密联系。但实际上,它们是完全不同的语言,只是在 JavaScript 的发展历史中与 Java 有一定的关联。 1. JavaScript 的诞生背景 时间点࿱…...
Web3与传统互联网的对比:去中心化的未来路径
随着互联网技术的不断发展,Web3作为去中心化的新兴架构,正在逐步改变我们的网络体验。从传统的Web2到Web3,互联网的演进不仅是技术的革新,更是理念的变革。那么,Web3与传统互联网相比,到底有何不同…...
C++之初识模版
目录 1.关于模版的介绍 2.函数模版 2.1函数模板概念 2.2函数模板格式 2.3 函数模板的原理 2.4 函数模板的实例化 2.5模板参数的匹配原则 3.类模版 3.1类模板的定义格式 3.2 类模板的实例化 1.关于模版的介绍 C中的模板是一种通用编程工具,它允许程序员编…...
如何给自己的域名配置免费的HTTPS How to configure free HTTPS for your domain name
今天有小伙伴给我发私信,你的 https 到期啦 并且随手丢给我一个截图。 还真到期了。 javapub.net.cn 这个网站作为一个用爱发电的编程学习网站,用来存编程知识和面试题等,平时我都用业余时间来维护,并且还自费买了服务器和阿里云…...
什么是Memecoin?它如何在加密货币世界崭露头角
在加密货币的世界里,Memecoin已经成为一个越来越受欢迎的词汇。作为一种新兴的加密货币,Memecoin凭借其独特的性质和文化背景吸引了大量投资者和加密爱好者。本文将详细探讨Memecoin是什么、它的起源、以及为什么它在市场中越来越受到关注。 什么是Meme…...
[unity 高阶]使用ASE制作一个cubed的skybox的shader,跟做版本
第一步,导入ASE 此步骤不在此讲解,有时间再补充 第二步,创建shader 需要选择shader的类型,此处选择legacy/Unlit第三步,创建变量 根据默认shader中的变量 _Tint (“Tint Color”, Color) = (.5, .5, .5, .5)[Gamma] _Exposure (“Exposure”, Range(0, 8)) = 1.0_Rotat…...
Java复习第四天
一、代码题 1.相同的树 (1)题目 给你两棵二叉树的根节点p和q,编写一个函数来检验这两棵树是否相同。 如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。 示例 1: 输入:p[1,2,3],q[1,2,3] 输出:true示例 2: 输…...
mysql数据库启动出现Plugin ‘FEEDBACK‘ is disabled.问题解决记录
本人出现该问题的环境是xampp,异常关机,再次在xampp控制面板启动mysql出现该问题。出现问题折腾数据库之前,先备份数据,将mysql目录下的data拷贝到其他地方,这很重要。 然后开始折腾。 查资料,会发现很多…...
Spring 是如何解决循环依赖问题
Spring 框架通过 三级缓存 机制来解决循环依赖问题。循环依赖是指两个或多个 Bean 相互依赖,形成一个闭环,例如 Bean A 依赖 Bean B,而 Bean B 又依赖 Bean A。Spring 通过提前暴露未完全初始化的 Bean 来解决这个问题。 以下是 Spring 解决…...
【论文笔记】TranSplat:深度refine的camera-required可泛化稀疏方法
深度信息在场景重建中是非常重要的先验,有一个精确的深度估计,重建质量起码提升一半,这一篇就是围绕着transformer优化深度来展开工作,进而提升GS的效果,感谢作者大佬们的work! 1 Abstract 与之前的3D重建方…...
营销2.0时代的挑战与开源AI智能名片2+1链动模式S2B2C商城小程序源码的解决方案
摘要:本文旨在探讨营销2.0时代企业在客户管理方面的挑战,并提出开源AI智能名片21链动模式S2B2C商城小程序源码作为解决方案。营销2.0虽然强调客户导向,但在实际操作中,企业往往无差别地对待所有客户,导致客户忠诚度下降…...
PHP教育系统小程序
🌐 教育系统:全方位学习新体验,引领未来教育风尚 🚀 教育系统:创新平台,智慧启航 📱 教育系统,一款深度融合科技与教育的创新平台,匠心独运地采用先进的ThinkPHP框架与U…...
开篇:吴恩达《机器学习》课程及免费旁听方法
课程地址: Machine Learning | Coursera 共包含三个子课程 Supervised Machine Learning: Regression and Classification | Coursera Advanced Learning Algorithms | Coursera Unsupervised Learning, Recommenders, Reinforcement Learning | Coursera 免费…...
zookeeper的介绍和简单使用
1 zookerper介绍 zookeeper是一个开源的分布式协调服务,由Apache软件基金会提供,主要用于解决分布式应用中的数据管理、状态同步和集群协调等问题。通过提供一个高性能、高可用的协调服务,帮助构建可靠的分布式系统。 Zookeeper的特点和功能…...
python学opencv|读取图像(三十八 )阈值自适应处理
【1】引言 前序学习了5种阈值处理方法,包括(反)阈值处理、(反)零值处理和截断处理,相关文章链接为: python学opencv|读取图像(三十三)阈值处理-灰度图像-CSDN博客 python学opencv|读取图像(三十四&#…...
C++ 条件变量-生产消费者模型
条件变量是一种线程同步机制,当条件不满足时,相关线程被一直阻塞,直到某种条件出现,这些线程才会被唤醒. C11的条件变量提供了两个类: condition_variable:只支持与普通mutex搭配,效率更高。 condition_…...
Vue - ref( ) 和 reactive( ) 响应式数据的使用
一、ref( ) 在 Vue 3 中,ref() 是一个用于创建响应式引用的函数。它是 Vue 3 Composition API(组合式API) 的一部分,允许在组件中创建响应式数据。 使用对象:基本数据类型(String 、Number 、Boolean 、Null 等)、对…...
C语言初阶牛客网刷题——HJ73 计算日期到天数转换【难度:简单】
1. 题目描述——HJ73 计算日期到天数转换 牛客网OJ题链接 描述 每一年中都有 12 个月份。其中,1,3,5,7,8,10,12 月每个月有 31 天; 4,6,9,11 月每个月有 30 天;而对于 2 月,闰年时有29 天,平年时有 28 天。 现在&am…...
学到一些小知识关于Maven 与 logback 与 jpa 日志
1.jpa想要输出参数 logging:level:org.hibernate.orm.jdbc.bind: trace #打印SQL参数web: debug #web框架的日志级别就可以了, 2.Slf4j 其实 Slf4j 是一个日志接口规范,没有具体的实现 而 logback 是 Slf4j的一个实现 ,也是springboot3 的…...
Springboot3 自动装配流程与核心文件:imports文件
注:本文以spring-boot v3.4.1源码为基础,梳理spring-boot应用启动流程、分析自动装配的原理 如果对spring-boot2自动装配有兴趣,可以看看我另一篇文章: Springboot2 自动装配之spring-autoconfigure-metadata.properties和spring…...
1905电影网中国地区电影数据分析(一) - 数据采集、清洗与存储
文章目录 前言一、数据采集步骤及python库使用版本1. python库使用版本2. 数据采集步骤 二、数据采集网页分析1. 分析采集的字段和URL1.1 分析要爬取的数据字段1.2 分析每部电影的URL1.2 分析每页的URL 2. 字段元素标签定位 三、数据采集代码实现1. 爬取1905电影网分类信息2. 爬…...
postgresql15的启动
PostgreSQL是一个功能非常强大的、源代码开放的客户/服务器关系型数据库管理系统,且因为许可证的灵活,任何人都可以以任何目的免费使用、修改和分发PostgreSQL。现在国产数据库大力发展阶段,学习和熟悉postgresql的功能是非常有必要的&#x…...
基于SpringBoot的高校教师科研的设计与实现(源码+SQL脚本+LW+部署讲解等)
专注于大学生项目实战开发,讲解,毕业答疑辅导,欢迎高校老师/同行前辈交流合作✌。 技术范围:SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:…...
位运算的基本概念+通过 Brian Kernighan算法计算 lowbit 实现的奇技淫巧 python
目录 引入判断奇偶位运算概念 进入正题Brian Kernighan 算法lowbit 介绍判断幂举一反三牛刀小试汉明重量总结 引入 判断奇偶 假设你不知道位运算为何物:你怎么判断奇偶呢? n int(input()) if n % 2 0:print(f"{n}是偶数") else:print(f&q…...
vscode环境中用仓颉语言开发时调出覆盖率的方法
在vscode中仓颉语言想得到在idea中利用junit和jacoco的覆盖率,需要如下几个步骤: 1.在vscode中搭建仓颉语言开发环境; 2.在源代码中右键运行[cangjie]coverage. 思路1:编写了测试代码的情况(包管理工具) …...
【测试】UI自动化测试
长期更新,建议关注收藏点赞! 目录 概论WEB环境搭建Selenium APPAppium 概论 使用工具和代码执行用例。 什么样的项目需要自动化? 需要回归测试、自动化的功能模块需求变更不频繁、项目周期长(功能测试时长:UI自动化测…...
ThinkPHP 8的多对多关联
【图书介绍】《ThinkPHP 8高效构建Web应用》-CSDN博客 《2025新书 ThinkPHP 8高效构建Web应用 编程与应用开发丛书 夏磊 清华大学出版社教材书籍 9787302678236 ThinkPHP 8高效构建Web应用》【摘要 书评 试读】- 京东图书 使用VS Code开发ThinkPHP项目-CSDN博客 编程与应用开…...
利用 SoybeanAdmin 实现前后端分离的企业级管理系统
引言 随着前后端分离架构的普及,越来越多的企业级应用开始采用这种方式来开发。前后端分离不仅提升了开发效率,还让前端和后端开发可以并行进行,减少了相互之间的耦合度。SoybeanAdmin 是一款基于 Spring Boot 和 MyBatis-Plus 的后台管理系…...
【Uniapp-Vue3】request各种不同类型的参数详解
一、参数携带 我们调用该接口的时候需要传入type参数。 第一种 路径名称?参数名1参数值1&参数名2参数值2 第二种 uni.request({ url:"请求路径", data:{ 参数名:参数值 } }) 二、请求方式 常用的有get,post和put 三种,默认是get请求。…...
【安当产品应用案例100集】034-安当KSP支持密评中存储数据的机密性和完整性
安当KSP是一套获得国密证书的专业的密钥管理系统。KSP的系统功能扩展图示如下: 我们知道商用密码应用安全性评估中,需要确保存储的数据不被篡改、删除或者破坏,必须采用合适的安全方案来确保存储数据的机密性和完整性。KSP能否满足这个需求呢…...
如何实现网页不用刷新也能更新
要实现用户在网页上不用刷新也能到下一题,可以使用 前端和后端交互的技术,比如 AJAX(Asynchronous JavaScript and XML)、Fetch API 或 WebSocket 来实现局部页面更新。以下是一个实现思路: 1. 使用前端 AJAX 或 Fetch…...
【真机调试】前端开发:移动端特殊手机型号有问题,如何在电脑上进行调试?
目录 前言一、怎么设置成开发者模式?二、真机调试基本步骤? 🚀写在最后 前言 edge浏览器 edge://inspect/#devices 谷歌浏览器(开tizi) chrome://inspect 一、怎么设置成开发者模式? Android 设备 打开设…...
ASP.NET Core 6.0 如何处理丢失的 Startup.cs 文件
介绍 .NET 6.0 已经发布,ASP.NET Core 6.0 也已发布。其中有不少变化让很多人感到困惑。例如,“谁动了我的奶酪”,它在哪里Startup.cs?在这篇文章中,我将深入研究这个问题,看看它移动到了哪里以及其他变化。…...
利用Java爬虫获取eBay商品详情:代码示例与教程
在当今的电商时代,获取商品详情数据对于市场分析、价格监控和竞品研究至关重要。eBay作为全球最大的电商平台之一,拥有海量的商品信息。通过Java爬虫技术,我们可以高效地获取这些数据,为商业决策提供支持。本文将详细介绍如何使用…...
graylog~认识一下-日志管理平台
1、介绍 Graylog 是一个开源的日志管理和分析平台,旨在帮助企业集中收集、存储、搜索和分析来自各种来源的日志数据。它提供了强大的实时日志处理能力,适用于大规模分布式系统和复杂的生产环境。 主要功能 集中化日志管理: 收集来自不同来源…...
Vue 拦截监听原理
Vue 渐进式JavaScript 框架 学习笔记 - Vue 拦截监听原理 目录 拦截监听原理 如何跟踪变化 拦截监听示例 观察者 注意:vue3的变化 总结 拦截监听原理 如何跟踪变化 当你把一个普通的Javascript 对象传入 Vue 实例作为data选项,Vue 将遍历此对象所有的proper…...
C# 解析 HTML 实战指南
在网页开发和数据处理的场景中,经常需要从 HTML 文档里提取有用的信息。C# 作为一门强大的编程语言,提供了丰富的工具和库来实现 HTML 的解析。这篇博客就带你深入了解如何使用 C# 高效地解析 HTML。 一、为什么要在 C# 中解析 HTML 在实际项目中&…...
idea新增java快捷键代码片段
最近在写一些算法题,有很多的List<List这种编写,想着能否自定义一下快捷键 直接在写代码输入:lli,即可看见提示...
网络与信息安全:企业如何正确实施电子邮件监控,防止内忧外患?
什么是电子邮件监控? 电子邮件监控对于保护公司免受因员工的恶意活动或外部攻击(如网络钓鱼、垃圾邮件等)而导致的不良事件的影响非常重要。实施员工电子邮件监控措施可能包括以下原因: 密切关注员工的官方电子邮件可确保员工有…...
blender 安装笔记 linux 2025
目录 linux安装blender: 运行后台渲染: 安装库: linux安装blender: # 进入下载目录 cd /shared_disk/users/lbg/soft/ # 下载 Blender 4.3.2 安装包 wget https://download.blender.org/release/Blender4.3/blender-4.3.2-l…...
99.11 金融难点通俗解释:净资产收益率(ROE)VS投资资本回报率(ROIC)VS总资产收益率(ROA)
目录 0. 承前1. 简述:三大收益率指标对比2. 比喻:三大指标对比2.1 简单对比2.2 生动比喻2.3 区别要点 3. 实际应用3.1 选择建议 4. 总结5. 实现代码 0. 承前 如果想更加全面清晰地了解金融资产组合模型进化论的体系架构,可参考: …...
【深度学习入门】深度学习知识点总结
一、卷积 (1)什么是卷积 定义:特征图的局部与卷积核做内积的操作。 作用:① 广泛应用于图像处理领域。卷积操作可以提取图片中的特征,低层的卷积层提取局部特征,如:边缘、线条、角。 ② 高层…...
最小距离和与带权最小距离和
1. 等权中位数 背景: 给定一系列整数,求一个整数x使得x在数轴上与所有整数在数轴上的距离和最小。 结论: 这一系列的整数按顺序排好后的中位数(偶数个整数的中位数取 n 2 或 n 2 1 \frac{n}{2}或\frac{n}{2}1 2n或2n1都可)一定是所求点…...
有哪些常见的 Vue 错误?
在使用 Vue.js 开发应用时,开发者可能会遇到各种错误。以下是一些常见的 Vue 错误以及如何避免它们:为了更详细地解释常见的 Vue.js 错误,我们可以深入探讨每个类别,并提供更多的背景信息和解决方案。以下是针对常见错误的扩展说明…...
查看电脑或笔记本CPU的核心数方法及CPU详细信息
一、通过任务管理器查看 1.打开任务管理器 可以按下“Ctrl Shift Esc”组合键,或者按下“Ctrl Alt Delete”组合键后选择“任务管理器”来打开。 2.查看CPU信息 在任务管理器界面中,点击“性能”标签页,找到CPU使用记录区域,…...
Python 轻松扫描,快速检测:高效IP网段扫描工具全解析
Python 轻松扫描,快速检测:高效IP网段扫描工具全解析 相关资源文件已经打包成EXE文件,可双击直接运行程序,且文章末尾已附上相关源码,以供大家学习交流,博主主页还有更多Python相关程序案例,秉着…...
AI Agent:AutoGPT的使用方法
AutoGPT的使用方法 准备工作: 安装Python:确保你的电脑上安装了Python 3.8或更高版本。获取OpenAI API密钥:访问https://platform.openai.com/account/api-keys获取API密钥,并保存备用。获取Google API及Google Search Engine ID(可选):若要使用谷歌搜索功能,需访问htt…...
RabbitMQ 在实际应用时要注意的问题
1. 幂等性保障 1.1 幂等性介绍 幂等性是数学和计算机科学中某些运算的性质,它们可以被多次应⽤,⽽不会改变初始应⽤的结果. 应⽤程序的幂等性介绍 在应⽤程序中,幂等性就是指对⼀个系统进⾏重复调⽤(相同参数),不论请求多少次,这些请求对系统的影响都是相同的效果. ⽐如数据库…...
ASP .NET Core 学习(.NET9)部署(一)windows
在windows部署 ASP .NET Core 的时候IIS是不二选择 一、IIS安装 不论是在window7 、w10还是Windows Server,都是十分简单的,下面以Windows10为例 打开控制面版—程序—启用或关闭Windows功能 勾选图中的两项,其中的子项看需求自行勾选&am…...