用c语言实现——一个动态顺序存储的串结构
一、思路概要
①动态顺序存储的串结构:
动态应该使用动态内存分配,也就是用指针来存储字符数组,同时记录长度和当前容量。
这样结构体应该包含三个成员:一个char*指针,一个int表示当前长度,另一个int表示总容量。这样可以方便扩展,当字符串变长时,可以重新分配更大的内存。
②初始化函数:
需要分配初始内存,比如默认大小可以设为一定值,比如20或者根据需要调整。
③赋值操作:
需要将一个字符串复制到结构体中,这时要注意检查容量是否足够,不够的话需要扩容。
④清空操作:
将长度设为0,但不释放内存。
⑤销毁操作:
完全释放内存,并将指针置空。
⑥求串长度:
直接返回长度,判空检查长度是否为0。
⑦显示操作:
直接打印当前字符串内容。
⑧串联接:
将另一个串连接到当前串后面,这时候需要考虑容量是否足够,不够的话需要扩容。
⑨子串提取:
需要用户给出起始位置和长度,然后提取出来形成新的串。这里要注意边界条件,比如起始位置是否合法,长度是否超过原串的范围。
⑩子串定位:
用的是朴素模式匹配算法,也就是逐个字符比较,主串和子串的指针移动,如果发现不匹配就回溯。需要注意索引的范围,避免越界。
子串定位的朴素算法实现需要注意循环的条件,主串从0到len - sublen的位置,每个位置检查子串是否匹配。例如,主串长度是len,子串长度是sublen,那么主串最多只能到 len - sublen的位置开始匹配,否则子串长度不够。
次数最多为n-m+1次。n为主串长,m为模式串长。
比较操作:
需要比较两个串的字典序,逐个字符比较直到不同或者结束。
户交互界面:
需要设计一个菜单,让用户可以选择不同的操作。比如用循环显示选项,然后根据输入调用对应的函数。
这里可能需要处理的错误:
①用户的输入错误,比如输入非数字选项,或者操作时输入无效的参数。
②提取子串时的位置和长度不正确。这时候程序应该给出提示,而不是崩溃。
③每个函数都应该检查参数的合法性,比如索引是否在有效范围内,指针是否为空等
2. 库函数
①perror 函数
是标准库函数,定义在<stdio.h>
头文件中。
作用 :输出系统错误信息到标准错误输出流(通常是屏幕)。它会将最近一次系统调用或库函数调用失败时产生的错误信息以字符串形式输出,帮助开发者快速定位问题。
语法 :void perror(const char *s)
。参数s
是一个字符串,通常用于指定错误发生的上下文描述。如果s
不是NULL
,函数会先输出这个字符串,接着输出一个冒号和空格,然后输出错误信息。
使用场景 :当系统调用或库函数返回失败时,可以使用perror输出具体的错误原因。例如,文件打开失败时,使用perror("File open failed");能帮助快速了解失败原因。I)里的部分是程序员自行输入的。
②exit函数
是标准库函数,定义在<stdlib.h>
头文件中。
作用 :终止程序的执行,并向宿主环境返回一个整数作为程序的退出状态。这可以用来告知调用者(例如操作系统或父进程)程序是否正常结束或因错误而终止。
语法 :void exit(int status)
。status
是退出状态码,通常EXIT_SUCCESS
(宏,表示成功)、EXIT_FAILURE
(宏,表示失败)或数字0表示成功,非0值表示失败。
执行过程 :当调用exit
时,会先调用所有通过atexit
注册的清理函数,完成程序中的一些收尾工作(如关闭文件、释放资源等),然后终止程序。
使用场景 :在程序关键步骤失败(如内存分配失败、文件打开失败等)时,使用exit
函数可以立即终止程序执行,避免程序继续运行导致更严重的后果。
二、代码阐释
1.动态字符串结构体定义
char* data
:一个字符指针,用于指向存储字符串的字符数组。这个指针允许字符串在内存中动态分配和扩展,以适应不同长度的字符串。
int length
:这个整数变量记录了当前字符串的实际长度,即字符串中有效字符的数量(不包括终止符'\0'
)。
int capacity
:这个整数变量表示当前分配给字符串存储的容量,也就是data
指针所指向的内存区域的大小。它通常大于或等于length
,以提供额外的空间供字符串扩展时使用。
2.初始化字符串
设置初始容量:
str->capacity = 20;
:将String
结构体的capacity
成员变量设置为20,表示最初为字符串分配的内存空间可以存储20个字符。
动态内存分配以及内存分配失败检查 :
str->data = (char*)malloc(str->capacity * sizeof(char));
:
使用malloc
函数为String
结构体的data
成员变量分配内存。malloc
函数根据str->capacity
的值(即20)乘以sizeof(char)
(通常为1字节)来确定要分配的内存大小。(char*)
是类型转换,确保分配的内存被正确地视为字符指针。
if (!str->data)
:检查malloc
函数是否成功分配内存。如果str->data
为NULL
,表示内存分配失败。
perror("Memory allocation failed");
:
输出错误信息,perror
函数会打印一条系统错误消息,说明内存分配失败的原因。
exit(EXIT_FAILURE);
:终止程序执行,并返回一个表示失败的退出状态码。这是一个宏,通常定义在头文件stdlib.h
中。
初始化字符串:
str->data[0] = '\0';
:将分配的内存空间的第一个字符设置为字符串结束符'\0'
,这样字符串的初始状态就是一个空字符串。
str->length = 0;
:将String
结构体的length
成员变量设置为0,表示当前字符串的长度为0。
3.销毁字符串
if (str->data)
:检查String
结构体的data
成员是否为非空指针。只有当data
指向有效的内存区域时,才需要进行释放操作。
free(str->data);
:调用free
函数释放data
所指向的动态分配的内存。free
函数是C语言标准库中的函数,用于释放用malloc
、calloc
或realloc
分配的内存。
str->data = NULL;
:将data
指针设置为NULL
。这一步是为了防止出现悬空指针(dangling pointer),即指向已经被释放的内存的指针。将指针设置为NULL
后,可以明确地表示该指针不再指向有效的内存区域。
str->length = 0;
:将String
结构体的length
成员设置为0,表示字符串的长度为0。这一步是为了将字符串重置为初始状态,即使得结构体中的各个成员变量都处于未分配或空状态。
str->capacity = 0;
:将String
结构体的capacity
成员设置为0,表示字符串的存储容量也为0。
4.清空字符串
if (str->data)
:检查String
结构体的data
成员是否指向有效的内存区域(即是否非空)。只有当data
非空时,才需要进行清空操作。
str->data[0] = '\0';
:将data
所指向的字符数组的第一个字符设置为字符串结束符'\0'
,这使得字符串在逻辑上变成空字符串,但原来的内存空间仍然被保留。
str->length = 0;
:将String
结构体的length
成员设置为0,表示字符串的长度变为0。
5.赋值操作
函数定义:
定义了一个名为 AssignString 的函数,该函数将一个普通字符串赋值给 String 结构体实例。函数的参数包括一个指向 String 结构体的指针 str 和一个指向普通字符串的指针 source,返回类型是 bool,表示赋值是否成功。
参数检查:
检查参数 str
和 source
是否为 NULL
。如果任何一个指针为 NULL
,则返回 false
,表示赋值失败。
获取字符串长度:
使用 strlen
函数获取 source
字符串的长度,并将其存储在变量 new_len
中。
检查存储容量:
判断 new_len
是否大于或等于 str->capacity
,以检查当前 String
结构体实例的存储容量是否足够容纳 source
字符串。
计算新容量:
计算新的存储容量 new_capacity
,即 new_len
加 1(额外 1 字节用于存储字符串结束符 '\0'
)。
重新分配内存:
使用 realloc
函数重新分配内存空间,尝试将 str->data
指向的内存区域的大小调整为 new_capacity
。realloc
函数返回一个新的指针,指向重新分配的内存区域。
内存重新分配失败检查:
检查 realloc
函数返回的指针是否为 NULL
。如果返回 NULL
,说明内存重新分配失败,函数返回 false
。
更新数据指针和容量:
将 str->data
更新为重新分配后的内存区域的指针,并更新 str->capacity
为新的存储容量 new_capacity
。
复制字符串:
使用 strcpy
函数将 source
字符串的内容复制到 str->data
指向的内存区域中。strcpy
函数会自动复制包括字符串结束符 '\0'
在内的所有字符。
更新字符串长度:
更新 str->length
为 new_len
,即当前字符串的长度。
最后返回成功信息。
6. 获取长度函数
定义了一个名为 GetLength
的函数,该函数接收一个指向 String
结构体的常量指针 str
,返回类型是 int
,表示字符串的长度。
使用三元运算符检查 str
是否为非空指针。
如果 str
不是空指针,则返回 str->length
,即 String
结构体的 length
成员变量的值。
如果 str
是空指针,则返回 0
,表示字符串长度为0。
7. 判空函数
使用三元运算符检查 str
是否为非空指针。
如果 str
不是空指针,则进一步检查 str->length
是否为0。如果 str->length
为0,返回 true
(表示字符串为空);否则返回 false
。
如果 str
是空指针,则直接返回 true
,表示字符串为空。这种处理方式是出于安全考虑,避免访问空指针。
8.显示函数
检查指针有效性:
检查 str
是否为非空指针,以及 str->data
是否为非空指针。
如果 str
或 str->data
为 NULL
,则不执行后续操作,避免访问无效内存。
打印字符串内容:
使用 printf
函数输出字符串的内容。
格式化字符串 "%s"
用于输出 str->data
指向的字符串内容。
打印字符串长度和容量:
使用 printf
函数输出字符串的长度和容量。
格式化字符串 "%d"
用于输出整数值 str->length
和 str->capacity
。
9.字符串的连接
检查指针是否为空:
检查 dest
、src
和 src->data
是否为非空指针。如果任何一个指针为 NULL
,函数返回 false
,表示连接失败。
计算新长度
计算连接后的长度:
计算连接后的字符串长度,即目标字符串 dest
的长度与源字符串 src
的长度之和。
检查存储容量
判断是否需要扩展容量:
判断连接后的字符串长度 new_len
是否大于或等于目标字符串 dest
的当前存储容量 capacity
。
扩展存储容量
计算新的存储容量:
计算新的存储容量,为连接后的字符串长度加1(用于存储字符串结束符 '\0'
)。
重新分配内存:
使用 realloc
函数尝试将目标字符串 dest
的存储容量扩展到 new_capacity
。
内存重新分配失败检查:
检查 realloc
是否成功。如果返回的指针为 NULL
,表示内存重新分配失败,函数返回 false
。
更新数据指针和容量:
更新目标字符串 dest
的数据指针和容量。
字符串连接
连接字符串:
使用 strcat
函数将源字符串 src
的内容连接到目标字符串 dest
的末尾。
更新字符串长度
更新目标字符串长度:
更新目标字符串 dest
的长度为连接后的长度。
最后返回成功
10.提取字符串
检查指针是否为空:
检查 sub
和 src
是否为非空指针,以及起始位置和长度是否合法。如果任何一个条件不满足,函数返回 false
,表示提取失败。
判断是否需要扩展容量:
判断提取的子串长度 length
是否大于或等于目标字符串 sub
的当前存储容量。
计算新的存储容量:
计算新的存储容量,为子串长度加1(用于存储字符串结束符 '\0'
)。
重新分配内存:
使用 realloc
函数尝试将目标字符串 sub
的存储容量扩展到 new_capacity
。
内存重新分配失败检查:
检查 realloc
是否成功。如果返回的指针为 NULL
,表示内存重新分配失败,函数返回 false
。
更新数据指针和容量:
更新目标字符串 sub
的数据指针和容量。
复制子串内容:
使用 strncpy
函数从源字符串 src
的指定起始位置 start
开始,复制 length
个字符到目标字符串 sub
的数据区域。
添加字符串结束符:
在目标字符串 sub
的数据区域的末尾添加字符串结束符 '\0'
。
更新字符串长度:
更新目标字符串 sub
的长度为提取的子串长度。
11.算法函数
检查指针是否为空:
检查主字符串 mainStr
和子字符串 subStr
是否为非空指针,以及子字符串长度是否为0或大于主字符串长度。如果任何一个条件满足,函数返回 0
,表示未找到子字符串。
遍历主字符串
外层循环:
遍历主字符串的每个可能的起始位置 i
,确保从位置 i
开始有足够的长度容纳子字符串。
遍历子字符串
内层循环:
遍历子字符串的每个字符,与主字符串从位置 i
开始的字符进行比较。
字符比较
字符不匹配处理:
如果主字符串和子字符串在位置 j
的字符不匹配,则跳出内层循环,移动到主字符串的下一个起始位置继续比较。
匹配成功处理
返回匹配位置:
如果内层循环完整执行(即子字符串所有字符都匹配),返回匹配的起始位置 i + 1
(因为返回值采用1-based索引)。
匹配失败处理
返回未找到:
如果遍历完所有可能的起始位置仍未找到匹配的子字符串,返回 0
。
12. 字符串比较函数
检查指针是否为空:
检查传入的两个字符串指针s1
和s2
是否为非空。如果任意一个指针为空,函数返回-1
,表示比较失败或参数无效。
计算最小长度
确定比较范围:
计算两个字符串长度中的较小值,确定字符比较的范围。这一步确保了不会因为超出较短字符串的长度而引发访问越界错误。
逐字符比较
循环比较对应字符:
在循环中依次比较两个字符串对应位置的字符:
如果发现不匹配的字符,立即返回这两个字符的ASCII值的差。这表示在第一个不匹配的位置上,哪个字符串的字符更大。
如果所有比较范围内的字符都相同,则继续执行后续操作。
比较长度
返回长度差:
如果两个字符串在较短长度范围内完全相同,则通过比较它们的长度来确定最终结果。较长的字符串被认为较大,返回两个字符串长度的差值。
13.清理缓冲区函数
-
定义变量:定义一个整型变量
c
,用于存储从标准输入读取的字符。 -
循环清理:使用
while
循环持续读取标准输入中的字符:-
getchar()
:读取一个字符。 -
条件判断:当读取的字符
c
不是换行符\n
且不是文件结束标志EOF
时,继续循环读取。 -
效果:该循环会一直读取并丢弃输入缓冲区中的字符,直到遇到换行符或文件结束标志,从而实现清理输入缓冲区的目的。
-
三、完整代码
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include<stdbool.h>typedef struct
{char* data; // 存储字符串的字符数组int length; // 当前字符串长度int capacity; // 当前分配的存储容量
} String;// 函数声明
void InitString(String* str);
void DestroyString(String* str);
void ClearString(String* str);
bool AssignString(String* str, const char* source);
int GetLength(const String* str);
bool IsEmpty(const String* str);
void DisplayString(const String* str);
bool ConcatString(String* dest, const String* src);
bool SubString(String* sub, const String* src, int start, int length);
int Index(const String* mainStr, const String* subStr);
int CompareString(const String* s1, const String* s2);// 初始化字符串
void InitString(String* str)
{str->capacity = 20;str->data = (char*)malloc(str->capacity * sizeof(char));if (!str->data){perror("Memory allocation failed");exit(EXIT_FAILURE);}str->data[0] = '\0';str->length = 0;
}// 销毁字符串
void DestroyString(String* str)
{if (str->data){free(str->data);str->data = NULL;}str->length = 0;str->capacity = 0;
}// 清空字符串
void ClearString(String* str)
{if (str->data){str->data[0] = '\0';str->length = 0;}
}// 赋值操作
bool AssignString(String* str, const char* source)
{if (!str || !source){return false;}int new_len = strlen(source);if (new_len >= str->capacity){int new_capacity = new_len + 1;char* new_data = (char*)realloc(str->data, new_capacity);if (!new_data){return false;}str->data = new_data;str->capacity = new_capacity;}strcpy(str->data, source);str->length = new_len;return true;
}// 获取长度
int GetLength(const String* str)
{return str ? str->length : 0;
}// 判断空串
bool IsEmpty(const String* str)
{return str ? (str->length == 0) : true;
}// 显示字符串
void DisplayString(const String* str)
{if (str && str->data){printf("String content: %s\n", str->data);printf("Length: %d, Capacity: %d\n", str->length, str->capacity);}
}// 字符串连接
bool ConcatString(String* dest, const String* src)
{if (!dest || !src || !src->data){return false;}int new_len = dest->length + src->length;if (new_len >= dest->capacity){int new_capacity = new_len + 1;char* new_data = (char*)realloc(dest->data, new_capacity);if (!new_data){return false;}dest->data = new_data;dest->capacity = new_capacity;}strcat(dest->data, src->data);dest->length = new_len;return true;
}// 提取子串
bool SubString(String* sub, const String* src, int start, int length)
{if (!sub || !src || start < 1 || start > src->length || length < 0 || (start + length - 1) > src->length){return false;}if (length >= sub->capacity) {int new_capacity = length + 1;char* new_data = (char*)realloc(sub->data, new_capacity);if (!new_data){return false;}sub->data = new_data;sub->capacity = new_capacity;}strncpy(sub->data, src->data + start - 1, length);sub->data[length] = '\0';sub->length = length;return true;
}// 朴素模式匹配
int Index(const String* mainStr, const String* subStr)
{if (!mainStr || !subStr || subStr->length == 0 || mainStr->length < subStr->length){return 0;}for (int i = 0; i <= mainStr->length - subStr->length; i++){int j;for (j = 0; j < subStr->length; j++){if (mainStr->data[i + j] != subStr->data[j]){break;}}if (j == subStr->length){return i + 1; // 返回1-based位置}}return 0;
}// 字符串比较
int CompareString(const String* s1, const String* s2)
{if (!s1 || !s2) return -1;int min_len = s1->length < s2->length ? s1->length : s2->length;for (int i = 0; i < min_len; i++) {if (s1->data[i] != s2->data[i]){return s1->data[i] - s2->data[i];}}return s1->length - s2->length;
}// 清理输入缓冲区
void CleanInputBuffer()
{int c;while ((c = getchar()) != '\n' && c != EOF);
}int main()
{String str, temp;InitString(&str);InitString(&temp);int choice;char buffer[1024];while (1) {printf("\n===== 字符串操作菜单 =====\n");printf("1. 字符串赋值\n");printf("2. 清空字符串\n");printf("3. 判空操作\n");printf("4. 获取长度\n");printf("5. 显示字符串\n");printf("6. 连接字符串\n");printf("7. 提取子串\n");printf("8. 查找子串位置\n");printf("9. 比较字符串\n");printf("10. 退出程序\n");printf("请输入选项:");if (scanf("%d", &choice) != 1){while (getchar() != '\n');printf("输入错误!请重新输入数字\n");continue;}switch (choice){case 1: {printf("请输入新字符串:");CleanInputBuffer();// 清除输入缓冲区fgets(buffer, sizeof(buffer), stdin);buffer[strcspn(buffer, "\n")] = '\0';if (AssignString(&str, buffer))printf("赋值成功\n");elseprintf("赋值失败!\n");break;}case 2:ClearString(&str);printf("字符串已清空\n");break;case 3:printf("字符串状态:%s\n", IsEmpty(&str) ? "空" : "非空");break;case 4:printf("字符串长度:%d\n", GetLength(&str));break;case 5:DisplayString(&str);break;case 6:{printf("请输入要连接的字符串:");CleanInputBuffer();fgets(buffer, sizeof(buffer), stdin);buffer[strcspn(buffer, "\n")] = '\0';if (AssignString(&temp, buffer) && ConcatString(&str, &temp))printf("连接成功\n");elseprintf("连接失败!\n");ClearString(&temp);break;}case 7: {int start, length;printf("请输入起始位置和长度:");if (scanf("%d %d", &start, &length) != 2){printf("参数无效!\n");while (getchar() != '\n');break;}String sub;InitString(&sub);if (SubString(&sub, &str, start, length)){printf("提取的子串:");DisplayString(&sub);}else{printf("参数错误!\n");}DestroyString(&sub);break;}case 8: {printf("请输入要查找的子串:");CleanInputBuffer();fgets(buffer, sizeof(buffer), stdin);buffer[strcspn(buffer, "\n")] = '\0';if (AssignString(&temp, buffer)) {int pos = Index(&str, &temp);if (pos > 0)printf("找到子串,位置:%d\n", pos);elseprintf("未找到子串!\n");}ClearString(&temp);break;}case 9:{printf("请输入比较字符串:");CleanInputBuffer();fgets(buffer, sizeof(buffer), stdin);buffer[strcspn(buffer, "\n")] = '\0';if (AssignString(&temp, buffer)) {int result = CompareString(&str, &temp);if (result < 0)printf("当前字符串小于输入字符串\n");else if (result > 0)printf("当前字符串大于输入字符串\n");elseprintf("字符串相同\n");}ClearString(&temp);break;}case 10:DestroyString(&str);DestroyString(&temp);printf("正在退出程序...\n");exit(0);default:printf("无效选项!请重新选择\n");}}return 0;
}
编译器环境为VS2022!!!
用c语言实现一个动态顺序存储的串结构,支持用户输入交互界面、初始化、赋值、清空、销毁、求串长、判空、显示串表等基本操作、同时也要包含更高级的操作,比如串联接、子串提取、子串定位、比较等。子串定位采用朴素模式匹配算法,注意代码的健壮性
数据结构学习者参考。
相关文章:
用c语言实现——一个动态顺序存储的串结构
一、思路概要 ①动态顺序存储的串结构: 动态应该使用动态内存分配,也就是用指针来存储字符数组,同时记录长度和当前容量。 这样结构体应该包含三个成员:一个char*指针,一个int表示当前长度,另一个int表示…...
小程序Npm package entry file not found?
修改依赖包的入口文件 看是不是cjs,小程序不支持cjs...
vue3学习之防抖和节流
在前端开发中,我们经常会遇到这样的情况:某些事件(如滚动、输入、点击等)会频繁触发,如果不加以控制,可能会导致性能问题。Vue3 中的防抖(Debounce)和节流(Throttle&a…...
当高级辅助驾驶遇上“安全驾校”:NVIDIA如何用技术给无人驾驶赋能?
高级辅助驾驶技术的商业化落地,核心在于能否通过严苛的安全验证。国内的汽车企业其实也在做高级辅助驾驶,但是吧,基本都在L2级别。换句话说就是在应急时刻内,还是需要人来辅助驾驶,AI驾驶只是决策层,并不能…...
Linux | Mfgtools 修改单独只烧写 Uboot,内核,文件系统
01 1. 打开 mfgtools_for_6ULL 文件夹,找到 cfg.ini 文件,如果您的板子是 EMMC 的修改如下图: 如果您的板子是 NAND 的,修改如下图: 02 2. 打开“Pro...
【Agent python实战】ReAct 与 Plan-and-Execute 的融合之道_基于DeepSeek api
写在前面 大型语言模型(LLM)驱动的 Agent 正在从简单的任务执行者向更复杂的问题解决者演进。在 Agent 的设计模式中,ReAct (Reason + Act) 以其步步为营、动态适应的特性见长,擅长处理需要与环境实时交互、快速响应的任务。而 Plan-and-Execute 则强调前瞻性规划,先制定…...
Native层Trace监控性能
一、基础实现方法 1.1 头文件引用 #include <utils/Trace.h> // 基础版本 #include <cutils/trace.h> // 兼容旧版本1.2 核心宏定义 // 区间追踪(推荐) ATRACE_BEGIN("TraceTag"); ...被监控代码... ATRACE_END();// 函数级自…...
【C++】15. 模板进阶
1. 非类型模板参数 模板参数分类类型形参与非类型形参。 类型形参即:出现在模板参数列表中,跟在class或者typename之类的参数类型名称。 非类型形参:就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当…...
C#进阶学习(十四)反射的概念以及关键类Type
目录 本文末尾有相关类中的总结,如有需要直接跳到最后即可 前置知识: 1、程序集(Assembly) 2、元数据(Metadata) 3、中间语言(IL, Intermediate Language) 中间语言(…...
B. And It‘s Non-Zero
题目链接:https://codeforces.com/problemset/problem/1615/B 位运算之前没怎么写过,所以不会写。留一份题解,作为复习使用。 题解:按位与的结果不为0,则至少有一列全为1.要求删除的数最少,即要求该列原本…...
深入解析NuttX:为何它是嵌入式RTOS领域的标杆?
文章目录 引言一、NuttX简介:轻量级与高兼容性的结合二、架构特点:为何NuttX更灵活?三、横向对比:NuttX vs 主流嵌入式RTOS四、NuttX的核心优势五、何时选择NuttX?结语 引言 在资源受限的嵌入式系统中,实时…...
html初识
html 盖楼第一步:HTML1. HTML是啥玩意儿?2. 动手!搭个你的"网络小窝" (第一个HTML页面)3. 添砖加瓦:常用HTML"建材"详解3.1 标题家族3.2 段落哥俩好3.3 传送门:链接3.4 挂画:图片 盖楼…...
leetcode66.加一
从后向前遍历,直到碰到非9的数(也就是数组中中最后一个非9的数) ,该值+1,然后其后的数字全部0 class Solution {public int[] plusOne(int[] digits) {for (int i digits.length-1; i >0; i--) {if (d…...
【Vue】Vue3项目创建
执行npm run dev,如果报错检查nodejs版本...
缓存替换算法之 FIFO(先进先出)
FIFO(First In, First Out,先进先出)是一种常见的缓存替换算法,其基本思想是最早进入缓存的数据项将最先被移除。以下是FIFO的详细讲解: 一、FIFO的数据结构 队列(Queue) 队列是一种典型的线性…...
Linux下的I/O复用技术之epoll
I/O多路复用 指在单个线程或进程中,同时处理多个I/O操作的技术。 旨在提高程序处理多个并发I/O操作的能力,避免程序因等待某个I/O操作而被阻塞。在传统的I/O模型中当程序进行I/O操作时(如读取文件、接受网路数据等),如果数据还未准备好&…...
数据分析管理软件 Minitab 22.2.2 中文版安装包 免费下载
Minitab22.2.2 安装包下载链接: https://pan.baidu.com/s/1cWuDbvcWhYrub01C6QR81Q?pwd6666 提取码: 6666 Minitab软件是现代质量管理统计软件,全球六西格玛实施的共同语言。Minitab 已经在全球120多个国家,5000多所高校被广泛使用。...
chrony服务器(1)
简介 NTP NTP(Network Time Protocol,网络时间协议)是一种用于同步计算机系统时间的协议是TCP/IP协议族中的一个应用层协议,主要用于在分布式时间服务器和客户端之间进行时钟同步,提供高精准度的时间校正通过分层的时…...
2025.04.26-淘天春招笔试题-第三题
📌 点击直达笔试专栏 👉《大厂笔试突围》 💻 春秋招笔试突围在线OJ 👉 笔试突围OJ 03. 二进制信号转换器 问题描述 卢小姐是一位通信工程师,她设计了一种特殊的二进制信号处理装置。该装置可以对由 0 0 0...
腾讯二面:TCC分布式事务 | 图解TCC|用Go语言实现一个TCC
写在前面 前段时间,有同学反馈的一个面试问题,觉得分布式事务有点偏了,但其实也不算偏了,在java领域就有很火很成熟的seata分布式事务框架(阿里和蚂蚁的同学主导,目前在apache孵化)。 之前我们讲过了两阶段提交、三阶…...
如何在 Conda 环境中降级 Python 版本:详细指南
如何在 Conda 环境中降级 Python 版本:详细指南 Python 版本的管理在开发过程中至关重要,特别是在处理不同项目需求时。对于使用 Conda 环境的 Python 程序员来说,版本管理不仅仅是安装不同的 Python 版本,还涉及到依赖关系的兼容…...
MCP 协议解读:STDIO 高效通信与 JSON-RPC 实战
本文深度解析 MCP 协议的传输机制与消息格式,涵盖 stdio、SSE 及自定义传输方式,剖析 JSON-RPC 2.0 的请求、响应与通知设计。 结合 RooCode 开源实现与天气查询案例,揭秘如何通过 MCP 实现跨进程通信与高效服务集成,为开发者提供…...
AI心理健康服务平台项目面试实战
AI心理健康服务平台项目面试实战 第一轮提问: 面试官: 请简要介绍一下AI心理健康服务平台的核心技术架构。在AI领域,心理健康服务的机遇主要体现在哪些方面?如何利用NLP技术提升用户与AI的心理健康对话体验? 马架构…...
路由器重分发(OSPF+RIP),RIP充当翻译官,OSPF充当翻译官
路由器重分发(OSPFRIP) 版本 1 RIP充当翻译官 OSPF路由器只会OSPF语言;RIP路由器充当翻译官就要会OSPF语言和RIP语言;则在RIP中还需要将OSPF翻译成RIPOSPF 把RIP路由器当成翻译官,OSPF路由器就只需要宣告自己的ip&am…...
29-算法打卡-字符串-KMP算法理论2-第二十九天
1、KMP算法前缀表计算逻辑 可以查看上一章节的前缀表概念以及逻辑,KMP算法基础理论[基础概念、前缀、后缀、最长公共前后缀、前缀表] 2、KMP算法前缀表使用 当模式串和文本串匹配失败的时候,前缀表会告诉我们下一次的匹配中,模式串应该跳到…...
解锁生成式AI潜力的金钥匙
一、引言:生成式AI的浪潮与“提示词”的崛起 在短短几年内,生成式人工智能(Generative AI)以前所未有的速度席卷全球,从文字创作到图像生成,从代码辅助到科学研究,以ChatGPT、Midjourney、DALL…...
统计定界子数组的数组
前言:看到这个题目的时候,只想着怎么暴力枚举右端点,结合线段树还是会超时,没找到很好的处理方法 超时代码 class Tree1:def __init__(self,n):self.t [0]*(4*n)def update(self,o,l,r,index,va):if lr:self.t[o] vareturnmid …...
JAVA---字符串
ctrlN 搜索界面(idea) API和API帮助文档 API : 应用程序编程接口(换句话说,就是别人已经写好了,我们不需要再编写,直接使用即可) Java API :就是JDK中提供的各种功能…...
import tree # pip install dm_tree ModuleNotFoundError: No module named ‘tree‘
在导入tree包时,在python库里找了很久,一直以为是tree这个包没下载好,有的推荐执行 pip install dm_tree这是deepmind开发一个处理处理嵌套数据结构的库。它在某种程度上tree 概括了仅支持扁平序列的内置map函数,并允许将函数应用…...
Java ThreadLocal与内存泄漏
当我们利用 ThreadLocal 来管理数据时,我们不可避免地会面临内存泄漏的风险。 原因在于 ThreadLocal 的工作方式。当我们在当前线程的 ThreadLocalMap 中存储一个值时,一旦这个值不再需要,释放它就变得至关重要。如果不这样做,那么…...
Rule.resource作用说明
1. 说明 作用 Rule.resource 用于定义哪些文件需要被当前规则处理。它是对传统 test、include、exclude 的更底层封装,支持更灵活的匹配方式。 与 test/include/exclude 的关系 test: /.js$/ 等价于resource: { test: /.js$/ } include: path.resolve(__dirname, ‘…...
【Docker项目实战】使用Docker部署Caddy+vaultwarden密码管理工具(详细教程)
【Docker项目实战】使用Docker部署vaultwarden密码管理工具 前言一、vaultwarden介绍1.1 vaultwarden简介1.2 主要特点二、本次实践规划2.1 本地环境规划2.2 本次实践介绍三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本四、拉取镜像五、…...
代码随想录算法训练营第五十九天 | 1.ford算法精讲 卡码网94.城市间货物运输
1.Bellman_ford 算法精讲 题目链接:94. 城市间货物运输 I 文章讲解:代码随想录 思路: 使用dijkstra,要求图中边的权值都为正数。 带负权值的单源最短路问题,轮到Bellman_ford 算法。Bellman_ford算法的核心思想是对…...
shell(1)
1.shell变量介绍 i.Linux Shell中的变量分为,系统变量和用户自定义变量. ii.系统变量:$HOME,$PWD, $SHELL,$USER 例echo $HOME iii.显示当前shell中的所有变量--set 2.shell变量的定义 基本语法 1.定义变量:变量名值 注意 号左右也不能有空格 2.撤销变量:unset 变量 3.声…...
KEPServerEX 6与西门子1500PLC进行OPC通讯
仿真效果与真实环境效果一至; 环境: 西门子软件:博图V20、S7-PLCSIM Advanced V5.0 OPC软件:KEPServerEX 6 创建S7-PLCSIM Advanced V5.0仿真环境 西门子1500plc组态 添加一个1500cpu,注意点击项目文件࿰…...
【概念】什么是 JWT Token?
—什么是 JWT Token? JWT Token(JSON Web Token) 就是一张后端发给前端的小票,里面包含用户身份信息,用于做无状态认证(Stateless Authentication)。 每次前端访问后端接口,都拿着…...
【Castle-X机器人】一、模块安装与调试:机器人底盘
持续更新。。。。。。。。。。。。。。。 【ROS机器人】模块安装 一、Castle-X机器人底盘1.1 结构概述1.2 驱动执行结构1.3 环境传感器1.4 电气系统1.5 Castle-x机器人底盘测试激光雷达传感器测试及数据可视化超声波传感器实时数据获取防跌落传感器测试陀螺仪测试键盘控制测试…...
NSIS打包
以下是一篇详细的 NSIS 打包 EXE 的入门教程: NSIS 打包 EXE 入门教程 NSIS(Nullsoft Scriptable Install System)是一款开源的 Windows 安装包制作工具,支持脚本化定制安装流程。本教程将带你从零开始,创建一个简单的 EXE 安装程序。 1. 环境准备 1.1 下载 NSIS 访问官…...
62.不同路径
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。 问总共有多少条不同的路径? 示例 …...
前端开发中shell的使用场景
Shell语言基础概念 Shell是用户与操作系统内核之间的接口,它接收用户输入的命令并解释执行。在Linux/Unix系统中,Shell是最常用的命令行界面。 基本语法和常用命令 变量定义和使用 # 定义变量 name"张三" age25# 使用变量 echo $name echo…...
基于javaweb的SSM投票管理系统设计与实现(源码+文档+部署讲解)
技术范围:SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论文…...
uml类关系(实现、继承,聚合、组合,依赖、关联)
drawio和EA是架构设计时经常使用的画图工具。 drawio学习门槛低,使用灵活,但是功能仅仅限于画图。 EA学习门槛高,但是功能更加的丰富: ①在画图方面,EA严格满足UML标准,EA中的图和类是关联的,…...
力扣热题100题解(c++)—链表
160.相交链表 给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。 图示两个链表在节点 c1 开始相交: 题目数据 保证 整个链式结构中不存在环。 注意,函数…...
MQ消息的不可靠性发生情况与解决方案
文章目录 问题:可能出现的情况: 解决流程与兜底方案第一个方面:确保生产者一定把消息发送到MQ1.生产者重试机制2.生产者确认机制 第二个方面:确保MQ不会将消息丢失数据持久化交换机持久化2.队列持久化3.消息持久化 LazyQueue控制台…...
线程池(五):线程池使用场景问题
线程池(五):线程池使用场景问题 线程池(五):线程池使用场景问题1 线程池使用场景CountDownLatch、Future1.1 CountDownLatch原理示例代码 1.2 案例一(es数据批量导入)需求分析实现步…...
第十六届蓝桥杯网安初赛wp
解题列表 根据提示一步一步走,经过猜测,测试出app.py 经过仔细研读代码,找到密钥 编写python代码拿到flag key secret_key9828 flagd9d1c4d9e0d6c29e9aad71696565d99bc8d892a8979ec7a69b9a6868a095c8d89dac91d19ba9716f63b5 newbytearray(…...
8.学习笔记-Maven进阶(P82-P89)
(一)Maven-08-配置文件加载属性 通过maven可以做版本的集中管理,所以能不能通过maven进行配置文件(jdbc.properties)的集中管理。 (1)resource-》jdbc.properties 可以识别$符号 因为只能…...
基于 IPMI + Kickstart + Jenkins 的 OS 自动化安装
Author:Arsen Date:2025/04/26 目录 环境要求实现步骤自定义 ISO安装 ipmitool安装 NFS定义 ks.cfg安装 HTTP编写 Pipeline 功能验证 环境要求 目标服务器支持 IPMI / Redfish 远程管理(如 DELL iDRAC、HPE iLO、华为 iBMC)&…...
Ubuntu20.04部署Ragflow(Docker方式)
Ubuntu20.04部署Ragflow(Docker方式) Ubuntu20.04 RagflowRunning RagflowRunning Ollama 由于写这篇博客的时候电脑还没装输入法,所以先用半吊子英文顶着了…关于最后运行ollama的部分可以无视,因为我修改了端口所以才需要这么运…...
【C++语法】类和对象(2)
4.类和对象(2) 文章目录 4.类和对象(2)类的六个默认成员函数(1)构造函数:构造函数特点含有缺省参数的构造函数构造函数特点(续)注意事项构造函数补充 前面总结了有关对象概念,对比 C…...