探索数据结构:顺序串与链式串的深入理解

embedded/2024/10/18 7:47:53/

✨✨ 欢迎大家来到贝蒂大讲堂✨✨

🎈🎈养成好习惯,先赞后看哦~🎈🎈

所属专栏:数据结构与算法
贝蒂的主页:Betty’s blog

1. 的定义

是一种特殊的顺序表,即每一个元素都是单独一个字符。在C语言中我们学习的字符便是的一种,它在我们的数据搜索与文本编译中起着不可或缺的作用。

img

特别注意:空格也是一个字符!!

下面是与相关概念:

  • 的长度:指中有效元素的个数(不包括字符\0)。
  • :不含任何元素的,即长度为0。
  • 子序列:抽取的一些字符,按照原字符的顺序进行放置的新
  • 中任意连续字符组成的子序列称为该的子,其中空是任意的子
  • :包含子称为该子的主

2. 的实现方式

是一种特殊的顺序表,所以实现方式也与顺序表类似,分别以顺序表和链表来实现。

  1. 顺序实现

img

  1. 链式实现

img

3. 的功能

  1. 的初始化
  2. 的生成。
  3. 的复制。
  4. 判断两个是否相等。
  5. 返回的长度。
  6. 链接两个
  7. 取子
  8. 1的指定位置插入2。
  9. 删除指定位置长度为n的某个子

4. 的声明

4.1. 顺序

顺序的存储自然是以顺序表的形式,但是在定义其长度有三种实现方式,如下:

  1. 初始化一个头结点作为长度的存储。

img

但是这种存储有一个明显的缺点就是char类型的最大表示范围为255,所以这种方式并不可取。

  1. 以字符\0作为结束标志。

img

C/C++中的字符就是以这种实现方式,但是这种实现方式每次求长度都需要遍历整个顺序表。所以在这里也不是特别好。

  1. 添加为结构体成员。

img

这种实现方式相较于前两种更加合理,后续我们也将以这种方式实现。

同时为了方便扩容,我们可以再增加一个结构体成员capacity

#define MAXSIZE 50
typedef struct string
{char *data;int length;int capacity;
}Sstring;

4.2. 链式

链式我们使用单链表来实现,为了方便操作我们可以添加一个头节点

typedef struct snode 
{char data;struct snode* next;
}LinkStrNode;

5. 的初始化

5.1. 顺序

void StrInit(Sstring* s)//初始化
{char *arr = (char*)malloc(sizeof(char) * MAXSIZE);if (arr == NULL){perror("malloc fail");return;}s->data = arr;s->length = 0;s->capacity = MAXSIZE;
}

5.2. 链式

链式并不需要单独初始化,可以在具体的实现中初始化。

5.3. 复杂度分析

  • 时间复杂度:顺序花费时间是一个常数,所以时间复杂度为O(1)。
  • 空间复杂度:初始化开辟了MAXSIZE的空间。可以视为O(N)的复杂度。

6. 的生成

6.1. 顺序

在对进行拷贝时,要检查是否需要扩容,放置越界。

void CheckCapacity(Sstring* s, int len)
{if (s->length + len > s->capacity){char* tmp = (char*)realloc(s->data, sizeof(char) * (s->length + len));if (tmp == NULL){perror("realloc fail");return;}s->data = tmp;s->capacity = MAXSIZE + len;}
}
void StrAssign(Sstring* s, char*str)//生成
{assert(s && str);int i = 0;int len = strlen(str);CheckCapacity(s, len);for (i = 0; str[i] != '\0'; i++){s->data[i] = str[i];}s->length = len;
}

6.2. 链式

链式每次插入都要生成一个节点,所以我们可以单独封装成一个函数。

LinkStrNode* BuyListNode()
{LinkStrNode*tmp= (LinkStrNode*)malloc(sizeof(LinkStrNode));if (tmp == NULL){perror("malloc fail");}return tmp;
}
void StrAssign(LinkStrNode** s, char*str)
{assert(str);LinkStrNode* r, * p;*s = BuyListNode();r = *s;for (int i = 0; str[i] != '\0'; ++i){p = BuyListNode();p->data = str[i];r->next = p;	r = p;}r->next = NULL;
}

6.3. 复杂度分析

  • 时间复杂度:无论是顺序还是链式都需要遍历一遍目标,间复杂度可以视为O(N))。
  • 空间复杂度:顺序可能会扩容,链式需要开辟等量节点,所以空间复杂度可以视为O(N)。

7. 的复制

7.1. 顺序

的复制也需要检查是否需要扩容,然后再依次拷贝。

void StrCopy(Sstring* s, Sstring* t)//复制
{assert(s && t);if (s->capacity < t->capacity){char* tmp = (char*)realloc(s->data, sizeof(char) * t->capacity);if (tmp == NULL){perror("realloc fail");return;}s->data = tmp;s->capacity = t->capacity;}for (int i = 0; i < t->length; i++){s->data[i] = t->data[i];}s->length = t->length;
}

7.2. 链式

链式的拷贝我们采用一种方法:即先将原销毁,然后再拷贝。

void StrCopy(LinkStrNode** s, LinkStrNode* t)//复杂
{assert(t);DestroyStr(*s);//销毁LinkStrNode* r, * q;LinkStrNode* p = t->next;*s = BuyListNode();r = *s;while (p != NULL){q = BuyListNode();q->data = p->data;		r->next = q;r = q;			p = p->next;}r->next = NULL;
}

7.3. 复杂度分析

  • 时间复杂度:需要遍历一遍被复制,所以时间复杂度可以视为O(N)。
  • 空间复杂度:顺序可能扩容,链式需要复制等量节点,所以空间复杂度可以视为O(N)。

8. 的比较

的比较与C语言中strcmp函数功能类似,都是依次比较中的字符,直至结束或者出现不同的字符为至。

若大于则返回>0,等于返回0,小于则返回<0。

列如:

  • 长度不同时:“aabc”>“abbca”,“aaa”<“aaab”。
  • 长度相同时:“acbc”>“bcbc”,“acac”=“acac”。

8.1. 顺序

int StrCmp(Sstring* s, Sstring* t)//比较两个
{assert(s && t);char* p1 = s->data;char* p2 = t->data;int i = 0;while (i < s->length && i < t->length && p1[i] == p2[i]){i++;}if (i == s->length&&i==t->length){return 0;}if (i == s->length && i != t->length){return -1;}if (i != s->length && i == t->length){return 1;}return p1[i] - p2[i];
}

8.2. 链式

int StrCmp(LinkStrNode* s, LinkStrNode* t)//比较两个
{assert(s&&t);LinkStrNode* p = s->next, * q = t->next;while (p != NULL && q != NULL && p->data == q->data){p = p->next;q = q->next;}if (p == NULL&&q == NULL)		return 0;if (p == NULL && q != NULL){return -1;}if (p != NULL && q == NULL){return 1;}return p->data - q->data;
}

8.3. 复杂度分析

  • 时间复杂度:无论是链式还是顺序都可能遍历整个,所以时间复杂度可以视为O(N)
  • 空间复杂度:无论是顺序还是链式花费空间是一个常数,所以空间复杂度为O(1)。

9. 返回的长度

9.1. 顺序

int StrLength(Sstring* s)//返回的长度
{assert(s);return s->length;
}

9.2. 链式

int StrLength(LinkStrNode* s)//返回的长度
{assert(s);int count = 0;LinkStrNode* p = s->next;while (p != NULL){count++;p = p->next;}return count;
}

9.3. 复杂度分析

  • 时间复杂度:顺序是一个常数,所以时间复杂度为O(1)。但是链式需要遍历整个,所以为O(N)。
  • 空间复杂度:无论是顺序还是链式花费空间是一个常数,所以空间复杂度为O(1)。

10. 链接两个

链接两个十分简单,首先找个一个的末尾,然后再链接即可。

10.1. 顺序

链接两个也需要判断该是否需要扩容。

Sstring Strcat(Sstring* s, Sstring* t)//链接两个
{assert(s && t);int len = t->length;CheckCapacity(s, len);for (int i = s->length; i < s->length + t->length; i++){s->data[i] = t->data[i - s->length];}s->length = s->length + t->length;return *s;
}

10.2. 链式

LinkStrNode*Strcat(LinkStrNode* s, LinkStrNode* t)//链接两个
{assert(s && t);LinkStrNode* p = s->next, * q = t->next;while (p->next != NULL){p = p->next;}LinkStrNode* str1 = p,*str2;while (q != NULL){str2 = BuyListNode();str2->data =q->data;str1->next = str2;str1 = str2;q = q->next;}str1->next = NULL;return s;
}

10.3. 复杂度分析

  • 时间复杂度:无论是顺序还是链式都需要遍历两个,所以时间复杂度为O(N)。
  • 空间复杂度:顺序可能会扩容,链式需要开辟等量节点,所以空间复杂度为O(N)

11. 取子

我们通过传入的目标位置与长度来截取一段子返回,如果长度过大则截取后续所有字符。

11.1. 顺序

Sstring SubStr(Sstring* s, int i, int len)//取子
{assert(i < s->length);assert(s);Sstring str;str.data = (char*)malloc(sizeof(char) * s->capacity);if (str.data == NULL){perror("malloc fail");return *s;}str.capacity = s->capacity;if (i + len >= s->length){for (int pos = i; pos < s->length; pos++){str.data[pos-i] = s->data[pos];}str.length = s->length - i;}else{for (int pos = i; pos < i+len; pos++){str.data[pos - i] = s->data[pos];}str.length = len;}return str;
}

11.2. 链式

LinkStrNode*SubStr(LinkStrNode* s, int i, int len)//取子
{assert(s);assert(i <= StrLength(s));int count = 0;LinkStrNode* r, * p;p = s->next;//跳过头节点r = BuyListNode();while (p != NULL)//找到第i个位置{count++;if (count == i){break;}p = p->next;}LinkStrNode* str1=r,*str2;while (len--&&p!=NULL){str2 = BuyListNode();str2->data = p->data;str1->next = str2;str1 = str2;p = p->next;}str1->next = NULL;//末尾置空return r;
}

11.3. 复杂度分析

  • 时间复杂度:都可能遍历整个,所以时间复杂度为O(N)。
  • 空间复杂度:都需要开辟len个大小的空间,所以空间复杂度可以视为O(N)。

12. 指定位置插入

12.1. 顺序

指定位置插入也许检查是否扩容,然后指定位置后续字符移动len个单位。

img

img

Sstring InsStr(Sstring* s1, int i, Sstring* s2)//指定位置插入
{assert(s1 && s2);assert(i < s1->length);int len = s2->length;CheckCapacity(s1, len);for (int pos = s1->length - 1; pos >= i; pos--){s1->data[pos + len] = s1->data[pos];}for (int pos = i; pos < i + len; pos++){s1->data[pos] = s2->data[pos - i];}s1->length += len;return *s1;
}

12.2. 链式

LinkStrNode*InsStr(LinkStrNode* s1, int i, LinkStrNode* s2)//指定位置插入
{assert(s1&&s2);assert(i <= StrLength(s1));int count = 0;LinkStrNode* r, * p,*q;q=p = s1->next;//q为i之前的位置while (p != NULL)//找到第i个位置{count++;if (count == i){break;}q = p;//记录前一个位置p = p->next;}r = q;LinkStrNode* str;LinkStrNode* ptr=s2->next;//跳过头节点while (ptr != NULL){str = BuyListNode();str->data = ptr->data;r->next = str;r = str;ptr = ptr->next;}r->next= p;//链接return s1;
}

12.3. 复杂度分析

  • 时间复杂度:顺序需要移动覆盖,链式需要寻找目标位置,时间复杂度都可以视为O(N)。
  • 空间复杂度:顺序可能扩容,链式需要开辟等量空间,空间复杂度都可以视为O(N)。

13. 指定删除子

13.1. 顺序

如果删除的长度过长,只需要修改length。否则需要从前往后覆盖。

Sstring DelStr(Sstring* s, int i, int len)//指定删除子
{assert(i < s->length);assert(s);if (i + len >=s->length){s->length = i ;}else{for (int pos = i+len; pos <s->length; pos++){s->data[pos-len] = s->data[pos];}s->length -= len;}return *s;
}

13.2. 链式

LinkStrNode* DelStr(LinkStrNode* s, int i, int len)//指定删除子
{assert(s);assert(i < StrLength(s));int count = 0;LinkStrNode* r, * p;p = s->next;r = p;//r为前一个节点while (p != NULL){count++;if (count == i){break;}r = p;p = p->next;}while (len-- && p != NULL){LinkStrNode* str = p->next;free(p);p = str;}r->next = p;return s;
}

13.3. 复杂度分析

  • 时间复杂度:顺序可能需要移动覆盖,链式需要寻找目标位置,时间复杂度都可以视为O(N)。
  • 空间复杂度:顺序与链式都不需要开辟格外空间,空间复杂度都可以视为O(1)。

14. 的打印

14.1. 顺序

void PrintStr(Sstring* s)
{assert(s);char* p = s->data;for (int i = 0; i < s->length; i++){printf("%c", p[i]);}printf("\n");
}

14.2. 链式

void PrintStr(LinkStrNode* s)//打印
{assert(s);LinkStrNode* p = s->next;while (p != NULL){printf("%c", p->data);p = p->next;}printf("\n");
}

14.3. 复杂度分析

  • 时间复杂度:无论是顺序还是链式都需要遍历整个,所以时间复杂度为O(N)。
  • 空间复杂度:顺序与链式都不需要开辟格外空间,空间复杂度都可以视为O(1)。

15. 的销毁

15.1. 顺序

void StrDestroy(Sstring* s)//销毁
{free(s->data);s->data = NULL;s->length = s->capacity = 0;
}

15.2. 链式

void DestroyStr(LinkStrNode* s)//销毁
{LinkStrNode* pre = s, * p = s->next;while (p != NULL){free(pre);pre = p;p = p->next;}free(pre);
}

15.3. 复杂度分析

  • 时间复杂度:顺序消耗时间固定,时间复杂度为O(1)。链式需要遍历这个,时间复杂度为O(N)
  • 空间复杂度:顺序与链式都不需要开辟格外空间,空间复杂度都可以视为O(1)。

16. 对比与应用

16.1. 对比

因为也是一种顺序表,所以无论是顺序表还是链式的优劣都与顺序表与链表差不多。这里就不在赘述。

16.2. 应用

在计算机领域有着广泛的应用:

  1. **文本处理:**文本编辑器或处理器中,文本被表示为一个字符,可以进行查找、替换、插入、删除等操作
  2. 加密和安全:加密算法中经常使用字符表示数据,例如对称加密和非对称加密中的密钥和明文。

17. 完整代码

17.1. 顺序

17.1.1. Sstring.h
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
#include<string.h>
#define MAXSIZE 50
typedef struct string
{char *data;int length;int capacity;
}Sstring;
void StrInit(Sstring* s);//初始化
void StrAssign(Sstring* s, char str[]);//生成
void StrCopy(Sstring* s, Sstring*t);//复制
int StrCmp(Sstring*s, Sstring*t);//比较两个
int StrLength(Sstring*s);//返回的长度
Sstring Strcat(Sstring*s, Sstring*t);//链接两个
Sstring SubStr(Sstring* s, int i, int len);//取子
Sstring InsStr(Sstring* s1, int i, Sstring* s2);//指定位置插入
Sstring DelStr(Sstring* s, int i, int len);//指定删除子
void PrintStr(Sstring* s);//打印
void StrDestroy(Sstring* s);//销毁
17.1.2. Sstring.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"Sstring.h"
void CheckCapacity(Sstring* s, int len)
{if (s->length + len > s->capacity){char* tmp = (char*)realloc(s->data, sizeof(char) * (s->length + len));if (tmp == NULL){perror("realloc fail");return;}s->data = tmp;s->capacity = MAXSIZE + len;}
}
void StrInit(Sstring* s)//初始化
{char *arr = (char*)malloc(sizeof(char) * MAXSIZE);if (arr == NULL){perror("malloc fail");return;}s->data = arr;s->length = 0;s->capacity = MAXSIZE;
}
void StrAssign(Sstring* s, char*str)//生成
{assert(s && str);int i = 0;int len = strlen(str);CheckCapacity(s, len);for (i = 0; str[i] != '\0'; i++){s->data[i] = str[i];}s->length = len;
}
void StrCopy(Sstring* s, Sstring* t)//复制
{assert(s && t);if (s->capacity < t->capacity){char* tmp = (char*)realloc(s->data, sizeof(char) * t->capacity);if (tmp == NULL){perror("realloc fail");return;}s->data = tmp;s->capacity = t->capacity;}for (int i = 0; i < t->length; i++){s->data[i] = t->data[i];}s->length = s->length > t->length ? s->length : t->length;
}
int StrCmp(Sstring* s, Sstring* t)//比较两个
{assert(s && t);char* p1 = s->data;char* p2 = t->data;int i = 0;while (i < s->length && i < t->length && p1[i] == p2[i]){i++;}if (i == s->length&&i==t->length){return 0;}if (i == s->length && i != t->length){return -1;}if (i != s->length && i == t->length){return 1;}return p1[i] - p2[i];
}
int StrLength(Sstring* s)//返回的长度
{assert(s);return s->length;
}
Sstring Strcat(Sstring* s, Sstring* t)//链接两个
{assert(s && t);int len = t->length;CheckCapacity(s, len);for (int i = s->length; i < s->length + t->length; i++){s->data[i] = t->data[i - s->length];}s->length = s->length + t->length;return *s;
}
Sstring SubStr(Sstring* s, int i, int len)//取子
{assert(i < s->length);assert(s);Sstring str;str.data = (char*)malloc(sizeof(char) * s->capacity);if (str.data == NULL){perror("malloc fail");return *s;}str.capacity = s->capacity;if (i + len >= s->length){for (int pos = i; pos < s->length; pos++){str.data[pos-i] = s->data[pos];}str.length = s->length - i;}else{for (int pos = i; pos < i+len; pos++){str.data[pos - i] = s->data[pos];}str.length = len;}return str;
}
Sstring InsStr(Sstring* s1, int i, Sstring* s2)//指定位置插入
{assert(s1 && s2);assert(i < s1->length);int len = s2->length;CheckCapacity(s1, len);for (int pos = s1->length - 1; pos >= i; pos--){s1->data[pos + len] = s1->data[pos];}for (int pos = i; pos < i + len; pos++){s1->data[pos] = s2->data[pos - i];}s1->length += len;return *s1;
}
Sstring DelStr(Sstring* s, int i, int len)//指定删除子
{assert(i < s->length);assert(s);if (i + len >=s->length){s->length = i ;}else{for (int pos = i+len; pos <s->length; pos++){s->data[pos-len] = s->data[pos];}s->length -= len;}return *s;
}
void PrintStr(Sstring* s)
{assert(s);char* p = s->data;for (int i = 0; i < s->length; i++){printf("%c", p[i]);}printf("\n");
}
void StrDestroy(Sstring* s)//销毁
{free(s->data);s->data = NULL;s->length = s->capacity = 0;
}

17.2. 链式

17.2.1. Sstring.h
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
#include<string.h>
typedef struct snode 
{char data;struct snode* next;
}LinkStrNode;
void StrInit(LinkStrNode* s);//初始化
void StrAssign(LinkStrNode**s, char str[]);//生成
void StrCopy(LinkStrNode**s, LinkStrNode*t);//复制
int StrCmp(LinkStrNode*s, LinkStrNode*t);//比较两个
int StrLength(LinkStrNode*s);//返回的长度
LinkStrNode*Strcat(LinkStrNode*s, LinkStrNode*t);//链接两个
LinkStrNode*SubStr(LinkStrNode* s, int i, int len);//取子
LinkStrNode*InsStr(LinkStrNode* s1, int i, LinkStrNode* s2);//指定位置插入
LinkStrNode*DelStr(LinkStrNode* s, int i, int len);//指定删除子
void PrintStr(LinkStrNode* s);//打印
void DestroyStr(LinkStrNode* s);//销毁
17.2.2. Sstring.c
#include"Sstring.h"
LinkStrNode* BuyListNode()
{LinkStrNode*tmp= (LinkStrNode*)malloc(sizeof(LinkStrNode));if (tmp == NULL){perror("malloc fail");}return tmp;
}
void StrAssign(LinkStrNode** s, char*str)
{assert(str);LinkStrNode* r, * p;*s = BuyListNode();r = *s;for (int i = 0; str[i] != '\0'; ++i){p = BuyListNode();p->data = str[i];r->next = p;	r = p;}r->next = NULL;
}void StrCopy(LinkStrNode** s, LinkStrNode* t)
{assert(t);DestroyStr(*s);LinkStrNode* r, * q;LinkStrNode* p = t->next;*s = BuyListNode();r = *s;while (p != NULL){q = BuyListNode();q->data = p->data;		r->next = q;r = q;			p = p->next;}r->next = NULL;
}int StrCmp(LinkStrNode* s, LinkStrNode* t)//比较两个
{assert(s&&t);LinkStrNode* p = s->next, * q = t->next;while (p != NULL && q != NULL && p->data == q->data){p = p->next;q = q->next;}if (p == NULL&&q == NULL)		return 0;if (p == NULL && q != NULL){return -1;}if (p != NULL && q == NULL){return 1;}return p->data - q->data;
}
int StrLength(LinkStrNode* s)//返回的长度
{assert(s);int count = 0;LinkStrNode* p = s->next;while (p != NULL){count++;p = p->next;}return count;
}
LinkStrNode*Strcat(LinkStrNode* s, LinkStrNode* t)//链接两个
{assert(s && t);LinkStrNode* p = s->next, * q = t->next;while (p->next != NULL){p = p->next;}LinkStrNode* str1 = p,*str2;while (q != NULL){str2 = BuyListNode();str2->data =q->data;str1->next = str2;str1 = str2;q = q->next;}str1->next = NULL;return s;
}
LinkStrNode*SubStr(LinkStrNode* s, int i, int len)//取子
{assert(s);assert(i <= StrLength(s));int count = 0;LinkStrNode* r, * p;p = s->next;//跳过头节点r = BuyListNode();while (p != NULL)//找到第i个位置{count++;if (count == i){break;}p = p->next;}LinkStrNode* str1=r,*str2;while (len--&&p!=NULL){str2 = BuyListNode();str2->data = p->data;str1->next = str2;str1 = str2;p = p->next;}str1->next = NULL;//末尾置空return r;
}
LinkStrNode*InsStr(LinkStrNode* s1, int i, LinkStrNode* s2)//指定位置插入
{assert(s1&&s2);assert(i <= StrLength(s1));int count = 0;LinkStrNode* r, * p,*q;q=p = s1->next;//q为i之前的位置while (p != NULL)//找到第i个位置{count++;if (count == i){break;}q = p;//记录前一个位置p = p->next;}r = q;LinkStrNode* str;LinkStrNode* ptr=s2->next;//跳过头节点while (ptr != NULL){str = BuyListNode();str->data = ptr->data;r->next = str;r = str;ptr = ptr->next;}r->next= p;//链接return s1;
}
LinkStrNode* DelStr(LinkStrNode* s, int i, int len)//指定删除子
{assert(s);assert(i < StrLength(s));int count = 0;LinkStrNode* r, * p;p = s->next;r = p;//r为前一个节点while (p != NULL){count++;if (count == i){break;}r = p;p = p->next;}while (len-- && p != NULL){LinkStrNode* str = p->next;free(p);p = str;}r->next = p;return s;
}
void PrintStr(LinkStrNode* s)//打印
{assert(s);LinkStrNode* p = s->next;while (p != NULL){printf("%c", p->data);p = p->next;}printf("\n");
}
void DestroyStr(LinkStrNode* s)//销毁
{LinkStrNode* pre = s, * p = s->next;while (p != NULL){free(pre);pre = p;p = p->next;}free(pre);
}

http://www.ppmy.cn/embedded/6948.html

相关文章

MongoDB的CURD(增删改查操作)

读者大大们好呀&#xff01;&#xff01;!☀️☀️☀️ &#x1f525; 欢迎来到我的博客 &#x1f440;期待大大的关注哦❗️❗️❗️ &#x1f680;欢迎收看我的主页文章➡️寻至善的主页 ✈️如果喜欢这篇文章的话 &#x1f64f;大大们可以动动发财的小手&#x1f449;&#…

MVCC(多版本并发控制)

MVCC&#xff08;多版本并发控制&#xff0c;Multi-Version Concurrency Control&#xff09;是一种并发控制方法&#xff0c;用于解决数据库中多个事务同时执行时可能产生的数据一致性问题。MVCC 在数据库中通过维护多个数据版本&#xff08;记录历史版本&#xff09;来提供高…

Eclipse+Java+Swing实现学生信息管理系统-TXT存储信息

一、系统介绍 1.开发环境 操作系统&#xff1a;Win10 开发工具 &#xff1a;Eclipse2021 JDK版本&#xff1a;jdk1.8 存储方式&#xff1a;Txt文件存储 2.技术选型 JavaSwingTxt 3.功能模块 4.工程结构 5.系统功能 1.系统登录 管理员可以登录系统。 2.教师-查看学生…

C# Monitor锁

一、Lock和Monitor的关系 二、Monitor多于Lock的功能 三、Monitor常用属性和方法 一、Lock和Monitor的关系 Lock在IL代码中会被翻译成Monitor。lock(obj){} 等同于 Monitor.Enter(obj)和Monitor.Exit(obj) lock 是语法糖&#xff0c;是通过 Monitor 来实现的。 lock能做的…

手写一个民用Tomcat (04)

我们继续来 写 Tomcat 这次我们做优化&#xff0c;先看一下一个标准的http 协议 GET /servlet/com.yixin.HelloWorldServlet HTTP/1.1 Host: localhost:8080 Connection: keep-alive sec-ch-ua: "Microsoft Edge";v"123", "Not:A-Brand";v&quo…

Linux基本命令之正则表达式(转义字符)

一&#xff1a;查看二进制文件 strings 命令&#xff1a;strings 文件名 生成链接文件 ln 命令&#xff1a;ln 选项 源文件(f1) 链接文件&#xff08;f2&#xff09; 软连接&#xff1a;eg:ln -s f1 f2 软链接不能跨分区链接&#xff0c;但可以在同一分区的不同目录下链接…

OWASP发布大语言模型网络安全与治理清单

当前人工智能技术面临的最大风险是大语言模型&#xff08;LLM&#xff09;和生成式人工智能技术的发展和应用速度已经远远超过了安全和治理的速度。 OpenAI、Anthropic、谷歌和微软等公司的生成式人工智能和大语言模型产品的使用正呈指数级增长。与此同时&#xff0c;开源大语…

CCleaner怎么清理软件缓存 CCleaner清理要勾选哪些 ccleanerfree下载

CCleaner软件是一款优秀的数据清理软件&#xff0c;其中没有硬盘和内存的设置&#xff0c;也不含任何广告软件&#xff0c;其出色的注册表清洁功能能够保证您的电脑更稳定运行。本文将围绕CCleaner怎么清理软件缓存&#xff0c;CCleaner清理要勾选哪些的相关内容进行介绍。 一、…