【数据结构篇C++实现】- 特殊的线性表 - 串

news2024/11/15 21:45:06

友情链接:C/C++系列系统学习目录


文章目录

    • 🚀一、串的定义
    • 🚀二、串的存储结构
      • 🛴(一)串的顺序存储结构
        • 1、定长顺序存储表示
        • 2、堆分配存储表示
      • 🛴(二)串的链式存储结构
        • 3、块链存储表示
    • 🚀三、串的基本操作
    • 🚀四、串的模式匹配(重点)
      • 🛴(一)简单的模式匹配算法
      • 🛴(二)KMP算法
        • 1、字符串的前缀、后缀和最大公共前后缀长度
        • 2、求next数组
        • 3、next数组的优化
        • 4、KMP算法实现


🚀一、串的定义

串( string)是由零个或多个字符组成的有限序列,又名叫字符串。

  • 空串:零个字符的串称为空串。
  • 空格串:是只包含空格的串。注意它与空串的区别,空格串是有内容有长度的,而且可以不止一个空格。
  • 子串与主串:串中任意个数的连续字符组成的子序列称为该串的子串,相应地,包含子串的串称为主串。
  • 子串在主串中的位置就是子串的第一个字符在主串中的序号。

串的逻辑结构和线性表极为相似,区别仅在于串的数据对象限定为字符集。在基本操作上,串和线性表有很大差别。线性表的基本操作主要以单个元素作为操作对象,如查找、插入或删除某个元素等;而串的基本操作通常以子串作为操作对象,如查找、插入或删除一个子串等。

🚀二、串的存储结构

🛴(一)串的顺序存储结构

1、定长顺序存储表示

类似于线性表的顺序存储结构,用一组地址连续的存储单元存储串值的字符序列。在串的定长顺序存储结构中,为每个串变量分配一个固定长度的存储区,即定长数组。

#define MAXLEN 255	//预定义最大串长为255
typedef struct{
	char ch[MAXLEN];	//每个分量存储一个字符
	int length;	//串的实际长度
}SString;

串的实际长度只能小于等于MAXLEN,超过预定义长度的串值会被舍去,称为截断。串长有两种表示方法: 一是如上述定义描述的那样,用一个额外的变量len来存放串的长度;二是在串值后面加一一个不计入串长的结束标记字符“\0”,此时的串长为隐含值。需要遍历一下才能知道

在一些串的操作(如插入、联接等)中,若串值序列的长度超过上界MAXLEN,约定用“截断”法处理,要克服这种弊端,只能不限定串长的最大长度,即采用动态分配的方式。

2、堆分配存储表示

堆分配存储表示仍然以一组地址连续的存储单元存放串值的字符序列,但它们的存储空间是在程序执行过程中动态分配得到的。

typedef struct{
	char *ch;	//按串长分配存储区,ch指向串的基地址
	int length;	//串的长度
}HString;

在C语言中,存在一一个称之为“堆”的自由存储区,并用malloc()和free()函数来完成动则返回一个指向起始地址的指针,作为串的基地址,这个串由ch指针来指示;若分配失败,则返回NULL。已分配的空间可用free()释放掉。
上述两种存储表示通常为高级程序设计语言所采用。块链存储表示仅做简单介绍。

🛴(二)串的链式存储结构

3、块链存储表示

类似于线性表的链式存储结构,也可采用链表方式存储串值。由于串的特殊性(每个元素只有一个字符),在具体实现时,每个结点既可以存放一个字符, 也可以存放多个字符。每个结点称为块,整个链表称为块链结构。图(a)是结点大小为4 (即每个结点存放4个字符)的链表,最后一个结点占不满时通常用“#”补上;图(b)是结点大小为1的链表。

在这里插入图片描述

#define CHUNKSIZE 80	//块的大小可由用户定义
typedef struct Chunk{
    char ch[CHUNKSIZE];
    struct Chunk *next;
}Chunk;

一个结点存多少个字符才合适就变得很重要,这会直接影响着串处理的效率,需要根据实际情况做出选择。
但串的链式存储结构除了在连接串与串操作时有一定方便之外,总的来说不如顺序存储灵活,性能也不如顺序存储结构好。

🚀三、串的基本操作

  • StrAssign(&T, chars): 赋值操作。把串T赋值为 chars

  • Strcopy(&T, S): 复制操作。由串S复制得到串T。

  • StrEmpty(S): 判空操作。若S为空串,则返回TRUE,否则返回 FALSE

  • StrCompare(S,T): 比较操作。若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0。

    事实上,串的比较是通过组成串的字符之间的编码来进行的,而字符的编码指的是字符在对应字符集中的序号。

  • StrEngth(S): 求串长。返回串S的元素个数

  • Substring(&Sub,S,pos,1en):求子串。用Sub返回串S的第pos个字符起长度为len的子串。

  • Concat(&T,S1,S2): 串联接。用T返回由S1和S2联接而成的新串。

  • Index(S,T): 定位操作。若主串S中存在与串T值相同的子串,则返回它在主串S中第一次出现的位置;否则函数值为0

  • Clearstring(&S): 清空操作。将S清为空串

  • Destroystring(&S): 销毁串。将串S销毁

不同的高级语言对串的基本操作集可以有不同的定义方法。在上述定义的操作中,串赋值StrAssign、串比较 StrCompare、求串长 Strength、串联接 Concat及求子串 Substring五种操作构成串类型的最小操作子集,即这些操作不可能利用其他串操作来实现;反之,其他串操作(除串清除 Clearstring和串销毁 Destroystring外)均可在该最小操作子集上实现。

例如,可利用判等、求串长和求子串等操作实现定位函数 Index(S,T)。

int Index(Sring S, String T){
	int i = 1, n = StrLength(S), m = StrLength(T);
	String sub;
	while(i <= n-m+1){
		SubString(sub, S, i, m);	//取主串第i个位置,长度为m的串给sub
		if(StrCompare(sub, T) != 0){
			++i;
		}else{
			return i;	//返回子串在主串中的位置
		}
	}
	return 0;	//S中不存在与T相等的子串
}

🚀四、串的模式匹配(重点)

🛴(一)简单的模式匹配算法

子串的定位操作通常称为串的模式匹配,它求的是子串(常称模式串)在主串中的位置。这里采用定长顺序存储结构,给出一种不依赖于其他串操作的暴力匹配算法。

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){
		return i - T.length;
	}else{
		return 0;
	}
}

下图展示了模式串T = ′ a b c a c ′ 和主串S的匹配过程

在这里插入图片描述

简单的模式匹配算法的最坏时间复杂度为O(nm),其中n和m分别为主串和模式串的长度。

🛴(二)KMP算法

在上面的简单匹配中,每趟匹配失败都是模式后移一位再从头开始比较。而某趟已匹配相等的字符序列是模式的某个前缀,这种频繁的重复比较相当于模式串在不断地进行自我比较,这就是其低效率的根源。对于要匹配的子串T来说,“abcac”首字母“a”与后面的串“bc”中任意一个字符都不相等。那么既然要全部和主串相等,意味着子串T的首字符“a”不可能与S串的第2、3位字符相等,所以对这两位的判断是多余的

因此,可以从分析模式本身的结构着手,如果已匹配相等的前缀序列中有某个后缀正好是模式的前缀,那么就可以将模式向后滑动到与这些相等字符对齐的位置,主串i指针无须回溯,并继续从该位置开始进行比较。而模式向后滑动位数的计算仅与模式本身的结构有关,与主串无关。

KMP算法的特点就是:仅仅后移模式串,比较指针不回溯。很是牛掰。

1、字符串的前缀、后缀和最大公共前后缀长度

要了解子串的结构,首先要弄清楚几个概念:前缀后缀部分匹配值。前缀指除最后一个字符以外,字符串的所有头部子串;后缀指除第一个字符外,字符串的所有尾部子串;部分匹配值则为字符串的前缀和后缀的最大公共前后缀长度。下面以′ a b a b a ′ ’ ababa’′ababa′为例进行说明

  • ′ a ′ 的前缀和后缀都为空集,最大公共前后缀长度为0。
  • ′ a b ′ 的前缀为{ a } ,后缀为{ b } , ${ { a } } ∩ { { b } }= N U L L $,最大公共前后缀长度长度为0。
  • ′ a b a ′ 的前缀为{ a , ab } , 后缀为{ a , ba } , ${ { a,ab } } ∩ { { a,ba } }= {{a}} $, 最大公共前后缀长度为1
  • ′ a b a b ′ ,前缀∩后缀,{ a , a b , a b a } ∩ { b , a b , b a b } = {ab},最大公共前后缀长度为2。
  • ′ a b a b a ′ ,前缀∩后缀, { a , a b , a b a , a b a b } ∩ { a , b a , a b a , b a b a } = {a,aba}, 公共元素有两个,最大公共前后缀长度长度为3。

故字符串′ a b a b a ′ 的最大公共前后缀长度为00123。这个值有什么作用呢?回到最初的问题,主串为 ′ a b a c a b c a c b a b ′,子串为 ′ a b c a c ′ 。利用上述方法容易写出子串′ a b c a c ′ 的最大公共前后缀长度为00010,将最大公共前后缀长度值写成数组形式,就得到了最大公共前后缀长度(Partial match,PM)的表。

在这里插入图片描述

下面用PM表来进行字符串匹配:

在这里插入图片描述

  • 第一趟匹配过程:

    发现c 与a 不匹配,前面的2个字符′ a b ′是匹配的,查表可知,最后一个匹配字符b对应的部分匹配值为0,因此按照下面的公式算出子串需要向后移动的位数:
    移动位数 = 已匹配的字符数 − 失配字符上一位字符对应最大公共前后缀长度 移动位数 = 已匹配的字符数 − 失配字符上一位字符对 应 最 大 公 共 前 后 缀 长 度 移动位数=已匹配的字符数失配字符上一位字符对应最大公共前后缀长度

    因为2 − 0 = 2,所以将子串向后移动2位,如下进行第二趟匹配:

    在这里插入图片描述

  • 第二趟匹配过程:

    发现c 与b 不匹配,前面4个字符′ a b c a ′是匹配的,最后一个匹配字符a对应的部分匹配值为1,4 − 1 = 3 ,将子串向后移动3位,如下进行第三趟匹配:

    在这里插入图片描述

  • 第三趟匹配过程:

    子串全部比较完成,匹配成功。整个匹配过程中,主串始终没有回退,故KMP算法可以在O ( n + m ) 的时间数量级上完成串的模式匹配操作,大大提高了匹配效率。

2、求next数组

使用部分匹配值时,每当匹配失败,就去找它前一个元素的部分匹配值,这样使用起来有些不方便,所以将PM表右移一位,这样哪个元素匹配失败,直接看它自己的部分匹配值即可。将上例中字符串′ a b a c ′的PM表右移一位,就得到了next数组:

在这里插入图片描述
移动位数 = 失配字符所在位置 − 失配字符对应的 n e x t 值。(涉及到数组,记得位置是从 0 开始的) 移动位数 = 失配字符所在位置 - 失配字符对应的next值。(涉及到数组,记得位置是从0开始的) 移动位数=失配字符所在位置失配字符对应的next值。(涉及到数组,记得位置是从0开始的)
通过代码递推计算next 数组:

对于next的数组的计算,可以采用递推来算。根据上面的分析,我们知道如果模式串当前位置j之前有k个相同的前缀后缀,那么可以表示为next[j] = k,所以如果当模式串的p[j]跟文本串失配后,我们可以用next[j]处的字符继续和文本串匹配,相当于模式串向右移动了j - next[j]位。那么问题就来了,如何求出next[j+1]的值呢,我们还是来看例子吧:

模式串:    A  B  C  D  A  B  C  E
next值:   -1  0  0  0  0  1  2  ?  
索引:             k           j

如上所示,模式串为"ABCDABCE",且j=6, k = 2,我们有next[j] = k,这表示j位置上的字符C之前的最大前后缀长度为2,即AB。现在我们要求next[j+1]的值,

  • 因为 p [ k ] = = p [ j ] p[k] == p[j] p[k]==p[j],所以 n e x t [ j + 1 ] = n e x t [ j ] + 1 = k + 1 = 3 next[j+1] = next[j] + 1 = k + 1 = 3 next[j+1]=next[j]+1=k+1=3。即字母E之前的最大前后缀长度为3,即ABC。

  • 那么我们再来看 p [ k ] ! = p [ j ] p[k] != p[j] p[k]!=p[j]的情况下怎么处理,还是来看例子:

模式串:    A  B  C  D  A  B  D  E
next值:   -1  0  0  0  0  1  2  ?  
索引:             k           j

这个例子把上面例子中的第二个’C’换成了’D’,所以字符’E’前面的相同后缀就不再是3了,所以我们希望在k前面找出个k’位置,使得p[k’]为D,这样 n e x t [ j + 1 ] = k ′ + 1 next[j+1] = k' +1 next[j+1]=k+1,但是这个例子中不存在这样的’D’,所以next[j+1] = 0。

  • 我们再看一个能在前缀中找到’D’的例子:
模式串:    D  A  B  C  D  A  B  D  E
next值:   -1  0  0  0  0  1  2  3  ?  
索引:                k           j

这个例子上面例子的最前面加上了个’D’,此时j = 7, k = 3了,我们有next[j] = k,这表示j位置上的字符D之前的最大前后缀长度为3,即DAB。要求next[j+1]的值,我们发现此时 p [ k ] ! = p [ j ] p[k] != p[j] p[k]!=p[j],然后我们寻找k’或者直接让 k = n e x t [ k ] = 0 k = next[k] = 0 k=next[k]=0,此时p[0]是D,那么 n e x t [ j + 1 ] = k + 1 = 1 next[j+1] = k + 1 = 1 next[j+1]=k+1=1了,这说明字母E之前的最大前后缀长度为1,即D。综上所述,我们可以写出next的生成函数如下:

vector<int> getNext(string p) {
    int n = p.size(), k = -1, j = 0;
    vector<int> next(n, -1);
    while (j < n - 1) {
        if (k == -1 || p[j] == p[k]) {  //P[J]表示后缀的单个字符,P[K]表示前缀的单个字符,匹配成功
            ++k; ++j;
            next[j] = k;    //第一步就是next[1] = 0,每匹配成功一个就加一
        } else {
            k = next[k];   //如果匹配失败
        }
    }
    return next;
}

3、next数组的优化

上面这种计算next数组的方式可以进一步的优化,可以优化的原因是因为上面的方法存在一个小小的问题,如果用这种方法求模式串ABAB,会得到next数组为[-1 0 0 1],我们用这个模式串去匹配ABACABABC:

ABACABABC
ABAB

我们会发现C和B失配,那么根据上面的规则,我们要向右移动j - next[j] = 3 - 1 = 2位,于是有:

ABACABABC
  ABAB

右移2位后,b又跟c失配。事实上,因为在上一步的匹配中,已经得知p[3] = b,与s[3] = c失配,而右移两位之后,让p[ next[3] ] = p[1] = b 再跟s[3]匹配时,必然失配。问题出在哪呢?原因是当p[j] != s[i]时,下一步要用 p [ n e x t [ j ] ] 和 s [ i ] p[next[j]]和s[i] p[next[j]]s[i]去匹配,而如果 p [ j ] = = p [ n e x t [ j ] ] p[j] == p[next[j]] p[j]==p[next[j]]了,再用 p [ n e x t [ j ] ] 和 s [ i ] p[next[j]]和s[i] p[next[j]]s[i]去匹配必然会失配。所以我们要避免出现 p [ j ] = = p [ n e x t [ j ] ] p[j] == p[next[j]] p[j]==p[next[j]]的情况,一旦出现了这种情况,我们可以再次递归, n e x t [ j ] = n e x t [ n e x t [ j ] ] next[j] = next[next[j]] next[j]=next[next[j]],修改后的代码如下:

vector<int> getNext(string p) {
    int n = p.size(), k = -1, j = 0;
    vector<int> next(n, -1);
    while (j < n - 1) {
        if (k == -1 || p[j] == p[k]) {  //P[J]表示后缀的单个字符,P[K]表示前缀的单个字符
            ++k; ++j;
            next[j] = (p[j] != p[k]) ? k : next[k];
        } else {
            k = next[k];
        }
    }
    return next;
}

4、KMP算法实现

当想要在C++中实现KMP算法进行字符串匹配时,可以按照以下步骤进行:

  1. 构建next数组:计算模式串的前缀表,用于在不匹配时快速移动模式串。
  2. 使用KMP算法进行字符串匹配。
#include <iostream>
#include <vector>
#include <string>

// 构建next数组
vector<int> getNext(string p) {
    int n = p.size(), k = -1, j = 0;
    vector<int> next(n, -1);
    while (j < n - 1) {
        if (k == -1 || p[j] == p[k]) {  //P[J]表示后缀的单个字符,P[K]表示前缀的单个字符
            ++k; ++j;
            next[j] = (p[j] != p[k]) ? k : next[k];
        } else {
            k = next[k];
        }
    }
    return next;
}

// 使用KMP算法进行字符串匹配
int kmpSearch(const std::string& text, const std::string& pattern) {
    int n = text.size();
    int m = pattern.size();
    std::vector<int> next = getNext(pattern);
    int i = 0;
    int j = 0;

    while (i < n) {
        if (j == -1 || text[i] == pattern[j]) {
            ++i;
            ++j;
            if (j == m) {
                return i - j;  // 匹配成功,返回匹配的起始位置
            }
        } else {
            j = next[j];
        }
    }

    return -1;  // 未找到匹配的子串
}

int main() {
    std::string text = "ABABDABACDABABCABAB";
    std::string pattern = "ABABCABAB";

    int index = kmpSearch(text, pattern);

    if (index != -1) {
        std::cout << "在位置 " << index << " 处找到匹配的子串" << std::endl;
    } else {
        std::cout << "未找到匹配的子串" << std::endl;
    }

    return 0;
}

行文至此,落笔为终。文末搁笔,思绪驳杂。只道谢不道别。早晚复相逢,且祝诸君平安喜乐,万事顺意。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ES6 - Iterator迭代器和for...of 循环

文章目录 前言一、Iterator介绍二、Iterator原理三、实现Iterator接口的原生对象有五、默认调用 Iterator 接口的场合六&#xff0c;for... of 循环七&#xff0c;总结 前言 JavaScript 原有的表示“集合”的数据结构&#xff0c;主要是数组&#xff08;Array&#xff09;和对…

【每天40分钟,我们一起用50天刷完 (剑指Offer)】第四十二天 42/50【unordered_set】【双指针处理连续】【翻转字符串】

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&#xff09;   文章字体风格&#xff1a; 红色文字表示&#…

优思学院|企业遇到瓶颈期怎么办?六西格玛管用吗?

企业遇到瓶颈期应该分析一下原因&#xff0c;企业内部应该和各级一起思考如何解决、如何舒缓&#xff0c;即使找管理咨询公司同样也是这样做的&#xff0c;关键是企业是否连一个领导者也没有呢&#xff1f; 企业每天都会遇到新的问题&#xff0c;是否每次都要找管理咨询公司&a…

第七篇:k8s集群使用helm3安装Prometheus Operator

安装Prometheus Operator 目前网上主要有两种安装方式&#xff0c;分别为&#xff1a;1. 使用kubectl基于manifest进行安装 2. 基于helm3进行安装。第一种方式比较繁琐&#xff0c;需要手动配置yaml文件&#xff0c;特别是需要配置pvc相关内容时&#xff0c;涉及到的yaml文件太…

iOS--frame和bounds

坐标系 首先&#xff0c;我们来看一下iOS特有的坐标系&#xff0c;在iOS坐标系中以左上角为坐标原点&#xff0c;往右为X正方向&#xff0c;往下是Y正方向如下图&#xff1a; bounds和frame都是属于CGRect类型的结构体&#xff0c;系统的定义如下&#xff0c;包含一个CGPoint…

卡片布局 可左右上删除,可向下拉出上一个 支持复用

效果 支持左右上 三个方向删除内容&#xff0c;支持下拉显示上一个。支持adapter 支持复用。 使用 myLayout.setAdapter(new StackAdapter() {final int[] bgColorsnew int[]{Color.RED,Color.GREEN,Color.BLUE};Overridepublic View getView(int position, LayoutInflater …

Docker Hub和镜像仓库

目录 前言 创建存储库 推送镜像&#xff08;可选&#xff09; 搜索镜像 拉取镜像 前言 Docker Hub 是 Docker 公司提供的官方公共 Docker 镜像注册表&#xff0c;允许用户存储、分享和获取 Docker 镜像。在 Docker Hub 上&#xff0c;你可以找到许多官方和社区维护的 D…

三、前端高德地图、测量两个点之前的距离

点击测距工具可以开启测量&#xff0c;再次点击关闭测量&#xff0c;清除地图上的点、连线、文字 再次点击测量工具的时候清除。 首先 上面的功能条河下面的地图我搞成了两个组件&#xff0c;他们作为兄弟组件存在&#xff0c;所以简单用js写了个事件监听触发的对象&#xff…

JavaScript三元运算符

条件运算符&#xff08;三元运算符&#xff09;的基本结构 条件 &#xff1f; true:false例如&#xff1a; const age 20; age > 18 ? console.log("你已经成年了"):console.log("你还是一个孩子&#xff01;");我们这里把条件运算符和IF来做个区分…

高等数学中如何求间断点

高等数学中求间断点是一项重要的技巧&#xff0c;特别适用于分析函数的性质和图像的特征。在本文中&#xff0c;我们将深入探讨如何在给定函数中找到间断点&#xff0c;并解释其数学原理和实际应用。 什么是间断点&#xff1f; 在高等数学中&#xff0c;间断点是指函数在某个点…

Trello的功能、优缺点、国内使用体验,及4大类似的项目工具

1、Trello是什么软件&#xff0c;有哪些功能&#xff1b; 2、Trello的价格及国内用户的使用体验&#xff1b; 3、盘点国内同类型的项目管理软件&#xff1b; 4、对比国内工具Worktile、Teambition等工具如何。 一、Trello是什么软件&#xff0c;有哪些功能&#xff1f; 【官网…

Pytorch 最全入门介绍,Pytorch入门看这一篇就够了

本文通过详细且实践性的方式介绍了 PyTorch 的使用&#xff0c;包括环境安装、基础知识、张量操作、自动求导机制、神经网络创建、数据处理、模型训练、测试以及模型的保存和加载。 1. Pytorch简介 在这一部分&#xff0c;我们将会对Pytorch做一个简单的介绍&#xff0c;包括它…

uniapp打包本地资源使用原生安卓打包

Android安装打包 1. 安装sdk 2.安装解压openjdk到D盘 3.安装编辑器 在D盘新建文件 Androidstudio 将编辑器安装到这个Androidstudio 文件内 配置sdk路径 打包步骤&#xff1a; 1. 打开项目&#xff0c;如图&#xff1a; 2. uniapp的本地打包资源可以在 这里替换apps包下 再修…

java+springboot+mysql疫情物资管理系统

项目介绍&#xff1a; 使用javaspringbootmysql开发的疫情物资管理系统&#xff0c;系统包含超级管理员&#xff0c;系统管理员、员工角色&#xff0c;功能如下&#xff1a; 超级管理员&#xff1a;管理员管理&#xff1b;部门管理&#xff1b;职位管理&#xff1b;员工管理&…

港联证券:股市降印花税是什么意思?股市降印花税利好还是利空?

在股票买卖过程中&#xff0c;需求交纳必定的印花税、佣钱费用和过户费用&#xff0c;那么&#xff0c;股市降印花税是什么意思&#xff1f;股市降印花税利好仍是利空&#xff1f;下面港联证券为我们预备了相关内容&#xff0c;以供参阅。 股票降印花税是指下调投资者买卖股票的…

计算机毕设 深度学习实现行人重识别 - python opencv yolo Reid

文章目录 0 前言1 课题背景2 效果展示3 行人检测4 行人重识别5 其他工具6 最后 0 前言 &#x1f525; 这两年开始毕业设计和毕业答辩的要求和难度不断提升&#xff0c;传统的毕设题目缺少创新和亮点&#xff0c;往往达不到毕业答辩的要求&#xff0c;这两年不断有学弟学妹告诉…

Vue3使用vxetable进行表格的编辑、删除与新增

效果图如下: vxetable4传送门 一、引入插件 package.json中加入"vxe-table": "4.0.23",终端中执行npm i导入import {VXETable, VxeTableInstance

YouIcons-矢量图标、LOGO和插图素材下载 48000000+

YouIcons是一个免费下载矢量图标、LOGO和插图素材下的网站&#xff0c;图标量高达千万级别&#xff0c;目前共收录48109736个&#xff0c;是世界领先的创意徽标logo社区&#xff0c;供创意人员下载、分享、成长和使用&#xff0c;是设计师获取灵感、发现并与全球设计师联系的社…

大模型中的注意力机制——MHA、GQA、MQA

注意力机制是Transformer模型的核心组件。考虑到注意力机制的计算效率问题&#xff0c;研究人员也进行了许多研究。代表的就是以下三种模式&#xff1a; MHA&#xff08;Multi-head Attention&#xff09;是标准的多头注意力机制&#xff0c;包含h个Query、Key 和 Value 矩阵。…

DM数据库Linux安装

创建用户账号密码 groupadd dinstalluseradd -g dinstall -m -d /home/dmdba -s /bin/bash dmdbapasswd dmdba安装前必须创建 dmdba 用户&#xff0c;禁止使用 root 用户安装数据库。 dmdba ncayu123456修改文件打开最大数 vi /etc/security/limits.conf在最后添加四条语句dm…