当前位置: 首页 > news >正文

STL—容器—string类【对其结构和使用的了解】【对oj相关练习的训练】

STL—容器—string类

其实string类准确来说并不是容器,因为他出现的时间比STL要早,但是也可以说是容器吧。

1.为什么要学习string类?

1.1C语言当中的字符串

C语言中,字符串是以’\0’结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。

1.2面试题

415. 字符串相加 - 力扣(LeetCode)

在OJ中,有关字符串的题目基本以string类的形式出现,而且在常规工作中,为了简单、方便、快捷,基本

都使用string类,很少有人去使用C库中的字符串操作函数。

2.标准库中的string类

2.1string类的了解

string类的文档介绍

  1. 字符串是表示字符序列的类

  2. 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作单字节字符字符串的设计特性。

  3. string类是使用char(即作为它的字符类型,使用它的默认char_traits和分配器类型(关于模板的更多信息,请参阅basic_string)。

  4. string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits和allocator作为basic_string的默认参数(根于更多的模板信息请参考basic_string)。

  5. 注意,这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个类的所有成员(如长度或大小)以及它的迭代器,将仍然按照字节(而不是实际编码的字符)来操作。

总结:

  1. string是表示字符串的字符串类

  2. 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。

  3. string在底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator> string;

  4. 不能操作多字节或者变长字符的序列。

使用string类时,必须包含#include头文件以及using namespace std;

我们在包含头文件的时候经常会遇到两个比较容易混淆的头文件引用#include<string.h> 和 #include ,两者的主要区别如下:

#include<string.h>是C语言的标准库,主要是对字符串进行操作的库函数,是基于char*进行操作的,例如常见的字符串操作函数stpcpy、strcat都是在该头文件里面声明的。

#include是C++语言的标准库,该库里面定义了string类,你可以包含这个头文件,然后定义一个字符串对象,对于字符串的操作就基于该对象进行,例如:string str;

一般来说,c++的头文件不会有.h的出现,比如

————————————————

文档方面,个人觉得这个比较好用

- C++ Reference

作为一个程序员,查文档是一个必须具备的基本素质,当遇到一个不熟悉的接口需要使用的时候,查文档就是最好的解决方法,因此我们需要学会怎么查文档。

2.2string类的常用接口说明

2.2.1.string类的常见构造

image-20240617000544460

c++98版本中全部的构造

image-20240617002205885

实例:

// 初识string类 
// string类 有很多的接口和成员函数,我们主要得熟悉的使用其中的2成,剩下的8成需要我们去通过网络查询来解决
# include<string>
# include<iostream>using namespace std;
int main()
{// 关于string类的构造string s1; // 构造string s2("string"); // 直接构造string s3(s2); // 拷贝构造// 上面这三个最常用string s4(10, 's'); // string类中的的不常用的特殊构造string s5("hello", 1, 3); // string类中的不常用的特殊构造 [这里如果给的不是3 是过大的值,那么就是npos,意思就是将字符串后面有多少给多少] 这些知识都可以查文档查到// 能使用 << 来输出是因为 库中 已经对<< 进行了重载cout << s1 << endl; // [这里默认是空串]cout << s2 << endl; // stringcout << s3 << endl; // stringcout << s4 << endl; // sssssssssscout << s5 << endl; // ell [取"hello"中的 第 1~3号元素来构造的, 正好就是ell]string s6 = s4; // 这里还是拷贝构造string s7 = "string"; // 这里正常来说就是发生隐式类型转化 意味着,先直接构造,在拷贝构造// 但是这里的直接构造 + 拷贝构造发生在了同一表达式,因此编译器直接优化成直接构造cout << s6 << endl; // sssssssssscout << s7 << endl; // stringreturn 0;
}
2.2.2string类对象的容量操作

常见的与容量相关的接口:

image-20240617005128425

接口的代码使用:

1.size(重点)

size可以统计字符串的有效字符长度并返回。一般来说会用作遍历。

// string类对象有关容量的常见接口
// 1.size()
# include<string>
# include<iostream>
using namespace std;int main()
{	string s("hello");cout << "s: ";// 遍历for (size_t i = 0; i < s.size(); i++){s[i] += 1; // 写 [这个相当于对取出来的字符+1,就相当于给其ASCII码值+1]}for (size_t i = 0; i < s.size(); i++){cout << s[i]; // 读}cout << endl; //s8: ifmmp [hello每个字符的ASCII码值分别+1]return 0;
}
2.length

length也会统计字符串的有效长度并返回。其实和size是非常像的,甚至其底层的实现原理都是一样的、

其实在早期的时候用的都是length,但是后面数据结构都用size了,就统一用size了,length和size可以说就是一样的,这里推荐使用size

// 2.length# include<string>
# include<iostream>
using namespace std;void test_string()
{string s1("hello, world");cout << s1.size() << endl; // 12cout << s1.length() << endl; // 12}int main()
{test_string();return 0;
}
3.capacity

capacity可以返回当前空间的总大小

// 3.capacity
# include<string>
# include<iostream>
using namespace std;int main()
{string s("hello, world");cout << s.capacity() << endl; // 15// 目前s有12个空间存放数据,如果超出空间,会增容多少呢?s += "ddddd";cout << s.capacity() << endl; // 31// 可以发现,直接将其增容到了2倍的容量。return 0;
}
4.clear(重点)

清空字符串内容 【注意,空间不会被销毁,只是内容被清空了】

// 4.clear# include<string>
# include<iostream>
using namespace std;int main()
{string s("hello, world");cout << s << endl; // hello, worlds.clear();cout << s << endl; // 空串// 我们清除了字符串内容,不代表空间被销毁了、cout << s.capacity() << endl; // 15return 0;
}
5.empyt(重点)

empty可以检测字符串是否为空串,是就返回true,不是就返回false

//5.empty# include<string>
# include<iostream>
using namespace std;int main()
{string s("hello, world");if (s.empty())cout << "该string类对象为空" << endl;elsecout << "该string类对象不为空" << endl;s.clear();if (s.empty())cout << "该string类对象为空" << endl;elsecout << "该string类对象不为空" << endl;return 0;
}
6.reserve/resize(重点)

在学习这两个接口之前,我们先来看一个代码:

这个代码可以观察到每次增容时容量的变化大小

# include<string>
# include<iostream>
using namespace std;int main()
{string s;size_t sz = s.capacity();cout << "s_capacity grow\n";for (int i = 0; i < 100; i++){s.push_back('c'); // 也可以s += 'c'if (sz != s.capacity()) // != 的时候就说明s进行了增容{sz = s.capacity(); // 将新容量给到szcout << "new capacity: " << sz << endl; // 将此时的容量打印出来}}return 0;
}

image-20240617164339500

我们发现是接近1.5倍增容的。但是我们之前知道15容量在增容的时候是按两倍增容增到31的、

规律是:空间基数越大,增容的倍数越小

因为增容是有代价的。增容越多的空间,执行越多次增容,代价就越大。

知道了这个小知识,我们就可以来看resize和reserve了。

reserve给字符串预留空间。

其实就是给字符串开辟空间

// 6.resize/reserve
# include<string>
# include<iostream>
using namespace std;int main()
{string s;s.reserve(100); // 我们知道s需要100个空间,提前开好空间size_t sz = s.capacity();cout << "s_capacity grow\n";for (int i = 0; i < 100; i++){s.push_back('c'); // 也可以s += 'c'if (sz != s.capacity()) // != 的时候就说明s进行了增容{sz = s.capacity(); // 将新容量给到szcout << "new capacity: " << sz << endl; // 将此时的容量打印出来}}return 0;
}

image-20240617165039849

由于我们提前开辟好了100个空间【实际上不一定会开100个,因为要考虑内存对齐,最后还要放个\0】,s没有再执行增容操作。

这样我们只增容了一次,比起自动增容的次数就减少了许多。

image-20240617165453007

直接开辟了111个空间,并不是我们输入的100。【了解一下】

resize:在reserve的基础上,将有效字符的个数修改,并填充字符

int main()
{string s;//s.reserve(100); // 我们知道s需要100个空间,提前开好空间s.resize(100); // 将有效字符个数修改到100,并填充\0size_t sz = s.capacity();cout << "s_capacity grow\n";for (int i = 0; i < 100; i++){s.push_back('c'); // 也可以s += 'c'if (sz != s.capacity()) // != 的时候就说明s进行了增容{sz = s.capacity(); // 将新容量给到szcout << "new capacity: " << sz << endl; // 将此时的容量打印出来}}return 0;
}

image-20240617165704803

可以看到它相当于reserve(100)并且将有效字符个数修改到了100,并且填充了\0、

image-20240617171034866

由于前100个空间被resize填充了\0,因此后面还是会执行增容操作

因此如果想后面不执行增容操作,这里要用reserve

我们还可以指定填充的字符

int main()
{string s;//s.reserve(100); // 我们知道s需要100个空间,提前开好空间//s.resize(100); // 将有效字符个数修改到100,并填充\0s.resize(100,'6'); // 将有效字符修改到100,并填充6// 因此如果想后面不执行增容操作,这里要用reservesize_t sz = s.capacity();cout << "s_capacity grow\n";for (int i = 0; i < 100; i++){s.push_back('c'); // 也可以s += 'c'if (sz != s.capacity()) // != 的时候就说明s进行了增容{sz = s.capacity(); // 将新容量给到szcout << "new capacity: " << sz << endl; // 将此时的容量打印出来}}return 0;
}

image-20240617165942993

可以看到不再填充\0而是填充我们指定的字符6

image-20240617170946266

并且由于前100个空间都被resize填入了元素,因此后面插入100个c的时候还是会增容的

因此如果想后面不执行增容操作,这里要用reserve

总结(重要):

string容量相关方法使用代码演示

  1. size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()。
  2. clear()只是将string中有效字符清空,不改变底层空间大小
  3. resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变
string s1("hello, world");
s1.resize(5); // 会将原来的size减小到 5。
cout << s1 << endl; // hellos1.resize(20, 'x'); // 将size改到20,由于前5个已经有元素了,后15个填入x【空间不够会自动扩容】
cout << s1 << endl; // helloxxxxxxxxxxxxxxx
  1. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserver不会改变容量大小
注意:
  1. 上面我们讲的有关容量的接口都是常用的,并不是全部。全部的接口可以去文档中查看
  2. 在查看接口的时候,目前来说只需要查看接口如何使用,不用查看接口的底层实现,因为以目前的水平,是完全看不懂的。
  3. 常用的接口需要熟悉使用、

2.2.3string类对象的访问及遍历操作

image-20240617183351615

string中元素访问及遍历代码演示

下面我们对于遍历一共有3种方法【[] + 下标】【迭代器】【范围for】

拓展:迭代器

我们来了解一下迭代器

image-20240617120225600

如图所示,迭代器一共四种,这里我们就是了解一下,具体的我们后面会详细学习。

遍历的代码:

void test_string3()
{// 迭代器一共有4种迭代器,这里在介绍一种string s("hello world");// 倒着遍历string::reverse_iterator rit = s.rbegin(); //要用rbegin,指向字符串的最后一个有效元素// auto rit = s.rbegin();while (rit != s.rend()) // rend,指向字符串的首元素{cout << *rit;rit++; // 其实是倒着走的}cout << endl;// dlrow olleh
}int main()
{	// [] + 下标  【平常推荐使用这个】string s("hello");cout << "s: ";// 遍历for (size_t i = 0; i < s.size(); i++){s[i] += 1; // 写 [这个相当于对取出来的字符+1,就相当于给其ASCII码值+1]}for (size_t i = 0; i < s.size(); i++){cout << s[i]; // 读}cout << endl; //s8: ifmmp [hello每个字符的ASCII码值分别+1]// 迭代器【每个容器都会有自己的迭代器】【迭代器一共有四种】(这里了解一下迭代器)string::iterator it = s.begin(); // string::iterator 实际是一个类型//auto it = s1.begin(); // 也可以这样写 [自动推演]// 遍历while (it != s.end()){*it -= 1; // 写++it; // 迭代}it = s.begin(); // 重置while (it != s.end()){cout << *it; // 读++it; // 迭代}cout << endl;// hellotest_string3(); // 另外一种迭代器的使用// 上述是迭代器的使用方法,熟悉一下就行,后面会详细学习。// 范围for(c++11)  [原理其实就是迭代器]for (auto ch : s) // 自动把s8从左到右依次给到ch auto会自动推断类型{cout << ch;}cout << endl; //helloreturn 0;
}

再来看一个场景:

  • 将字符串转化为整数
// 将传进来的字符串转化成整数 【使用迭代器】
int string2int(const string& str)// 用引用提高效率,并且不改变str,const修饰
{int val = 0;string::const_iterator cit = str.begin(); // 此时的str是const对象,返回的是const类型的迭代器类型while (cit != str.end()){val *= 10;val += (*cit - '0');}cout << val << endl;
}int main()
{// 将字符串转化成整数string s("12345");int val = 0; for (int i = 0; i < s.size(); i++) // 遍历{// 让val + 上取出来的数字,然后再*10, 循环,直至全部取出、val *= 10; val += (s[i] - '0'); // -'0'是因为 取出来的是字符 而不是整形, - 去'0'的ASCII值才是对应整形}cout << val << endl; // 12345string s1("12345");int ret = string2int(s1);cout << ret << endl; // 12345return 0;
}

通过上面两个例子,我们了解到了遍历有不同的方式去遍历。

在这里面当中,迭代器似乎是一个比较麻烦的使用方式。

从方向上分:正向和反向迭代器

从权限上分:普通迭代器,const迭代器。

因此使用的时候似乎不吃香,从短期来看确实是如此,因为经过了c语言的学习,我们已经习惯于用数组的方式去遍历。但是数组这个方式只能用于vector 和 string。等到后面更多的数据结构,也就是容器出现,迭代器就会频繁使用,因为+所有容器的迭代器使用方法都是类似的。

因此迭代器的学习是c++中一个重要的部分。迭代器可以用于所有STL库中的容器的遍历

2.2.4string类对象的修改操作

常见的几个与修改操作相关的接口

image-20240617194843211

1.push_back/append/+=(重要)

push_back:在字符串后边尾插字符

append:在字符串后边追加字符串

+=:在字符串后边追加字符串

这三个我们推荐**+=**

有关尾插的三个接口的使用的代码:

// 1.+= / push_back / append 【有关尾插的三个接口】
# include<string>
# include<iostream>
using namespace std;int main()
{string s1;s1.push_back('p');s1 += 'p'; // 推荐使用+=cout << s1 << endl; //pp  可以看到 += 和 调用尾插接口的结果是一样的s1 += "hello"; // 这里调用的是另外一个 += 的重载函数cout << s1 << endl; // pphellos1.append(" world"); // 在s1后尾插" world"字符串cout << s1 << endl; // pphello world// 在上述三个尾插的操作接口中,我们推荐使用+=return 0;
}

如果想在具体位置插入的话可以使用insert接口,想删除具体位置的话用erase接口

可以上文档查具体使用方法,这里不做详解

2.c_str

image-20240618130116327

c_str: 会将string类对象以const char 的格式返回*

他会在string类对象中找到\0 ,把\0之前的字符串内容当做一个 const char 类型返回*

代码操作:

//2.c_str
# include<string>
# include<iostream>
using namespace std;int main()
{string s("hello");const char* str = s.c_str();// str拿到的是const char* 类型。// 获取字符数组的首地址,用c语言中的字符串形式去遍历while (*str) // 只要*str不是\0就继续{cout << *str;str++;}cout << endl; // hello// 也可以直接输出cout << s << endl; // hello// 这里调用的是string类中的重载的<<, 它会将整个s进行输出cout << s.c_str() << endl; // hello// 这里相当于直接对 const char* 进行输出,遇到\0就会结束输出s += '\0';s += ' ';s += "world";cout << s << endl; // hello world  中间的\0是不可见字符,不会打印出来cout << s.c_str() << endl; // hello  因为从h到 \0 被当做了一个const char*,s.c_str()返回的就是 helloreturn 0;
}
拓展:编码表

我们知道一个中文占据两个字节,这是由编码表实现的,因为中文的编码表是GDK

而英文的编码表是ASCII表

编码的本质是:映射,将对应的值映射到表中的某一个位置。

我们来看一段代码:

// 编码表
# include<string>
# include<iostream>
using namespace std;int main()
{// 我们知道英文是用ASCII码表来编码的string s = "中国"; // 中文使用GDK来编码的cout << s << endl; //中国s[3] = -7;cout << s << endl; // 中郭s[3] = -8;cout << s << endl; // 中锅s[3] = -9;cout << s << endl; // 中棍return 0;
}

下图是s字符串中存储的信息:

image-20240618234637031

可以很清楚的看到中文是两个字节共同编码成一个中文。

3.find/rfind/substr(重要)

image-20240619005428685

find: 可以查询字符串中的某个字符

如果找不到会返回npos【rfind找不到也一样返回npos】

image-20240620170550769

npos是-1 size_t的-1相当于int类型的最大值,42亿多

image-20240620171505713

substr:可以返回指定位置以后得字符串。如果不指定就是默认从头开始

来看一段代码:

//3.find/rfind
# include<string>
# include<iostream>
using namespace std;int main()
{string s("text.cpp"); // 如果我们想查询这个后缀.cpp// 我们就可以用find去查询.  再将其后边的打印出来size_t pos = s.find('.'); // pos = 4if (pos != string::npos) // npos是-1  size_t的-1相当于int类型的最大值,42亿多{// 用substr接口实现.后的打印cout << s.substr(pos) << endl; // .cpp// s.substr(pos)就是打印pos之后的数据,包括pos}return 0;
}

rfind:可以查询字符串中的一个字符,并且是最后一次出现的

//3.find/rfind
# include<string>
# include<iostream>
using namespace std;int main()
{string s("text.cpp"); // 如果我们想查询这个后缀.cpp// 我们就可以用find去查询.  再将其后边的打印出来size_t pos = s.find('.'); // pos = 4if (pos != string::npos) // npos是一个-1  size_t的-1相当于int类型的最大值,42亿多{// 用substr接口实现.后的打印cout << s.substr(pos) << endl; // .cpp// s.substr(pos)就是打印pos之后的数据,包括pos}// 还会有一种情况,如果想查询的字符串有多个后缀,我们想输出最后一个后缀的话// 我们就可以用rfind 重复的查找.  找到最后一个.string s1("test.cpp.zip"); // pos1 = 8size_t pos1 = s1.rfind('.');if (pos1 != string::npos){cout << s1.substr(pos1) << endl; // .zip}return 0;
}
拓展:网址

平常我们看到的网址是由协议、域名、资源名称

// 网址
# include<string>
# include<iostream>
using namespace std;// 协议、域名、资源名称
int main()
{string url("https://gitee.com/wzf-sang");//https是协议 http和https的差别就是https是加密的///gitee.com其实是个ip但是绑定了域名。如果不绑定域名这里是个ip【域名更好记住】//wzf-sang就是资源名称。//【在我们输入网址敲回车之后,服务器做的第一件事就是将你输入的网址拆成协议、域名、资源名称】//【因此才能在对应协议下申请访问对应的域名并根据资源名称返回资源】// 现在有个要求:分离出url。size_t i1 = url.find(':'); // i1 = 5if (i1 != string::npos){cout << url.substr(0, i1) << endl; // https//从0这个下标,输出i1个元素}size_t i2 = url.find('/', i1 + 3); // 从i1 + 3开始找if (i2 != string::npos){cout << url.substr(i1 + 3, i2 - i1 - 3) << endl;// gitee.com// 从i1 + 3这个下标,输出i2 - i1 - 3个元素}cout << url.substr(i2 + 1) << endl; //wzf-sangreturn 0;
}

而我们可以将其功能分离出来,抽象成一个函数

// 网址
# include<string>
# include<iostream>
using namespace std;// 该函数用于分离网址的三个必要信息
void spilt_url(const string& url)
{//【在我们输入网址敲回车之后,服务器做的第一件事就是将你输入的网址拆成协议、域名、资源名称】//【因此才能在对应协议下申请访问对应的域名并根据资源名称返回资源】// 现在有个要求:分离出url。size_t i1 = url.find(':'); // i1 = 5if (i1 != string::npos){cout << url.substr(0, i1) << endl; // https//从0这个下标,输出i1个元素}size_t i2 = url.find('/', i1 + 3); // 从i1 + 3开始找if (i2 != string::npos){cout << url.substr(i1 + 3, i2 - i1 - 3) << endl;// gitee.com// 从i1 + 3这个下标,输出i2 - i1 - 3个元素}// 在i2这个下标后面的都是资源名称cout << url.substr(i2 + 1) << endl; // wzf-sang// + 1是因为i2是 / ,i2后面的才是资源名称
}// 协议、域名、资源名称
int main()
{string url("https://gitee.com/wzf-sang");string url2("https://leetcode.cn/problems/majority-element/description/?envType=study-plan-v2&envId=top-interview-150");//https是协议 http和https的差别就是https是加密的///gitee.com其实是个ip但是绑定了域名。如果不绑定域名这里是个ip【域名更好记住】//wzf-sang就是资源名称。spilt_url(url);//	https//	gitee.com//	wzf - sangspilt_url(url2);//https//leetcode.cn//problems/majority-element/description/?envType=study-plan-v2&envId=top-interview-150return 0;
}

2.2.5string类非成员函数

image-20240619011949494

上面的几个接口了解一下,下面的OJ题目中会有一些体现他们的使用。string类中还有一些其他的操作,这里不一一列举,在需要用到时不明白了查文档即可。

2.2.6.vs和g++下string结构的说明

注意:下述结构是在32位平台下进行验证,32位平台下指针占4个字节。

  • vs下string的结构

string总共占28个字节,内部结构稍微复杂一点,先是有一个联合体,联合体用来定义string中字

符串的存储空间

当字符串长度小于16时,使用内部固定的字符数组来存放

当字符串长度大于等于16时,从堆上开辟空间

这种设计是合理的,大多数情况下字符串的长度都小于16,那string对象创建好之后,内

部已经有了16个字符数组的固定空间,不需要通过堆创建,效率高。

其次:还有一个size_t字段保存字符串长度,一个size_t字段保存从堆上开辟空间总的容量

最后:还有一个指针做一些其他事情。

故总共占16+4+4+4=28个字节

image-20240705222701207

  • g++下string的结构

G++下,string是通过写时拷贝实现的,string对象总共占4个字节,内部只包含了一个指针,该指

针将来指向一块堆空间内部包含了如下字段:

  1. 空间总大小

  2. 字符串有效长度

  3. 引用计数

struct _Rep_base
{size_type _M_length;size_type _M_capacity;_Atomic_word _M_refcount;
};
  1. 指向堆空间的指针,用来存储字符串。

2.2.7与string相关的oj题目

  1. 917. 仅仅反转字母 - 力扣(LeetCode)

  2. 387. 字符串中的第一个唯一字符 - 力扣(LeetCode)

  3. 字符串最后一个单词的长度

  4. 125. 验证回文串 - 力扣(LeetCode)

  5. 415. 字符串相加 - 力扣(LeetCode)

  6. 541. 反转字符串 II - 力扣(LeetCode)

  7. 557. 反转字符串中的单词 III - 力扣(LeetCode)

  8. 43. 字符串相乘 - 力扣(LeetCode)较难

  9. 找出字符串中第一个只出现一次的字符较难

相关文章:

STL—容器—string类【对其结构和使用的了解】【对oj相关练习的训练】

STL—容器—string类 其实string类准确来说并不是容器&#xff0c;因为他出现的时间比STL要早&#xff0c;但是也可以说是容器吧。 1.为什么要学习string类&#xff1f; 1.1C语言当中的字符串 C语言中&#xff0c;字符串是以’\0’结尾的一些字符的集合&#xff0c;为了操作…...

讲个SystemVerilog随机约束小坑

正文 记录个在写SystemVerilog随机约束时遇到的一个小坑&#xff0c;如果没有认真去查看随机结果是否符合预期&#xff0c;还真不容易发现。 为了方便讲述&#xff0c;写了如下示例代码。类cl_a里有个随机变量aa&#xff0c;初始值为222。在module top里对类cl_a例化并进行约…...

mysql在windows下的安装

软件安装 配置环境变量 测试...

uniapp 在手机上导出excel

1.创建excelDev.js文件 export default {exportExcel(fileData, documentName excel) {plus.io.requestFileSystem(plus.io.PUBLIC_DOCUMENTS, function(fs) {let rootObj fs.rootlet fullPath rootObj.fullPathconsole.log("开始导出数据")// 创建文件夹rootObj…...

收银系统源码-收银台副屏广告

1. 功能描述 门店广告&#xff1a;双屏收银机&#xff0c;副屏广告&#xff0c;主屏和副屏同步&#xff0c;总部可统一控制广告位&#xff0c;也可以给门店开放权限&#xff0c;门店独立上传广告位&#xff1b; 2.适用场景 新店开业、门店周年庆、节假日门店活动宣传&#x…...

【TORCH】torch.normal()中的size参数

在 torch.normal() 函数中&#xff0c;size 参数用于指定生成张量的形状。torch.normal() 函数用于从正态&#xff08;高斯&#xff09;分布中生成随机数。函数的基本形式是&#xff1a; torch.normal(mean, std, size)mean&#xff1a;均值&#xff0c;可以是标量或张量。如果…...

【第20章】MyBatis-Plus逻辑删除支持

文章目录 前言一、逻辑删除的工作原理二、支持的数据类型三、使用方法1.配置全局逻辑删除属性2.在实体类中使用 TableLogic 注解 四、常见问题解答1. 如何处理插入操作&#xff1f;2. 删除接口自动填充功能失效怎么办&#xff1f; 五、实战1. 全局配置2. 添加TableLogic3. 自动…...

【IT领域新生必看】 Java编程中的重载(Overloading):初学者轻松掌握的全方位指南

文章目录 引言什么是方法重载&#xff08;Overloading&#xff09;&#xff1f;方法重载的基本示例 方法重载的规则1. 参数列表必须不同示例&#xff1a; 2. 返回类型可以相同也可以不同示例&#xff1a; 3. 访问修饰符可以相同也可以不同示例&#xff1a; 4. 可以抛出不同的异…...

python转文本为语音并播放

python转文本为语音并播放 1、导入库 pip install pyttsx3==2.902、流程 1、初始化tts引擎 2、设置音量(0到1之间) 3、设置语速 4、 设置声音对象,voices[0].id代表男生,voices[1].id代表女生 5、转换文本并播放 6、挂起声音引擎3、代码 # -*- coding: utf-8 -*-"…...

解锁高效软件测试:虚拟机助力提升测试流程的秘诀

众所周知&#xff0c;软件测试在软件开发生命周期中至关重要。它确保软件符合要求&#xff0c;没有漏洞&#xff0c;并帮助开发人员优化性能&#xff0c;验证项目功能。 然而&#xff0c;测试可能既耗时又耗费资源&#xff0c;特别是当需要在不同操作系统和配置上测试软件组件…...

创建vue3项目

npm create vuelatest 编译打包生成报告 yarn add rollup-plugin-visualizer vite.config.ts: import { fileURLToPath, URL } from node:urlimport { defineConfig } from vite import vue from vitejs/plugin-vue import vueJsx from vitejs/plugin-vue-jsx import vueDevTo…...

中国网络安全审查认证和市场监管大数据中心数据合规官CCRC-DCO

关于CCRC-DCO证书的颁发机构&#xff0c;它是由中国网络安全审查认证与市场监管大数据中心&#xff08;简称CCRC&#xff09;负责。 该中心在2006年得到中央机构编制委员会办公室的批准成立&#xff0c;隶属于国家市场监督管理总局&#xff0c;是其直辖的事业单位。 依据《网络…...

Web漏洞扫描工具AppScan与AWVS测评及使用体验

AppScan和AWVS业界知名的Web漏洞扫描工具&#xff0c;你是否也好奇到底哪一个能力更胜一筹呢&#xff1f;接下来跟随博主一探究竟吧。 1. 方案概览 第一步&#xff1a;安装一个用于评测的Web漏洞靶场&#xff08;本文采用最知名和最广泛使用的靶场&#xff0c;即OWASP Benchma…...

瞰景Smart3D使用体验分享

引言 作为一名建筑设计师&#xff0c;我一直在寻找能够提升工作效率和设计质量的软件工具。瞰景Smart3D&#xff08;Smart3D&#xff09;是一款备受推崇的3D建模和设计软件&#xff0c;广泛应用于建筑、工程和施工&#xff08;AEC&#xff09;行业。经过一段时间的使用&#x…...

Android系统adb shell dumpsys activity processes

在Android系统中&#xff0c;adb shell dumpsys activity processes 命令是一个非常强大的工具&#xff0c;用于获取当前系统中所有运行进程的详细信息&#xff0c;包括它们的状态、内存使用情况、任务栈等。这对于开发者来说非常有用&#xff0c;尤其是在调试应用、分析系统性…...

vue侦听器watch()

侦听器watch&#xff08;&#xff09; 侦听器侦听数据变化&#xff0c;我们可以使用watch 选项在每次响应式属性变化时触发一个函数。 <template><h3>侦听器watch</h3><hr> <p>{{nessage}}</p> <button click"exchage">…...

如何用Python向PPT中批量插入图片

办公自动化办公中&#xff0c;Python最大的优势是可以批量操作&#xff0c;省去了用户粘贴、复制、插入等繁琐的操作。经常做PPT的朋友都知道&#xff0c;把图片插入到PPT当中的固定位置是一个非常繁琐的操作&#xff0c;往往调整图片时耗费大量的时间和精力。如何能省时省力插…...

C# Socket

Socket命名空间&#xff1a;创建 Socket&#xff1a;连接到服务器&#xff08;客户端&#xff09;&#xff1a;绑定和监听&#xff08;服务器端&#xff09;&#xff1a;接受连接&#xff08;服务器端&#xff09;&#xff1a;发送和接收数据&#xff1a;关闭 Socket&#xff1…...

node的下载、安装、配置和使用(node.js下载安装和配置、npm命令汇总、cnpm的使用)

天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。 愿将腰下剑,直为斩楼兰。 ——《塞下曲》 文章目录 一、node.js的下载、安装和配置1. node.js下…...

深度卷积神经网络 AlexNet

一、机器学习深度学习的发展 1、机器学习SVM方法 &#xff08;1&#xff09;20世纪90年代&#xff0c;基于统计学习理论的结果&#xff0c;开发了一种新型的学习算法——支持向量机&#xff08;SVM&#xff09;。这就产生了一类新的理论上优雅的学习机器&#xff0c;它们将SVM…...

【刷题汇总--大数加法、 链表相加(二)、大数乘法】

C日常刷题积累 今日刷题汇总 - day0061、大数加法1.1、题目1.2、思路1.3、程序实现 2、 链表相加(二)2.1、题目2.2、思路2.3、程序实现 3、大数乘法3.1、题目3.2、思路3.3、程序实现 4、题目链接 今日刷题汇总 - day006 1、大数加法 1.1、题目 1.2、思路 读完题,明白大数相加…...

基于Java的网上花店系统

目 录 1 网上花店商品销售网站概述 1.1 课题简介 1.2 设计目的 1.3 系统开发所采用的技术 1.4 系统功能模块 2 数据库设计 2.1 建立的数据库名称 2.2 所使用的表 3 网上花店商品销售网站设计与实现 1. 用户注册模块 2. 用户登录模块 3. 鲜花列表模块 4. 用户购物车…...

uniApp 封装VUEX

Vuex Store (index.js) import Vue from vue; import Vuex from vuex; import Cookies from js-cookie;Vue.use(Vuex);const saveStateKeys [vuex_user, vuex_token, vuex_demo];const initialState {vuex_user: { name: 用户信息 },vuex_token: Cookies.get(token) || ,vue…...

最长公共子序列求长度和输出子序列C代码

求两个字符串的公共子序列我们都知道需要使用用动态规划思想 用res[i][j]表示截止到字符串A的第i个字符串和截止到字符串B的第j个字符的最长公共子序列。如两个字符串helloworld和loop&#xff0c;res[5][3]表示子串hello和子串loo的最长公共子序列&#xff0c;为lo&#xff0…...

安卓Framework开发快速分析日志及定位源码

文章目录 如何区分源码中 main system events 日志查看 Activity 生命周期日志分析 events 日志在源码中位置应用进程ID助分析具体应用ProtoLog 动态开关日志如何快速定位相关流程的代码位置 本文首发地址 https://h89.cn/archives/285.html 最新更新地址 https://gitee.com/ch…...

数据结构算法之B树

一、绪论 1.1 数据结构的概念和作用 1.2 B树的起源和应用领域 二、B树的基本原理 2.1 B树的定义和特点 2.2 B树的结构和节点组成 2.3 B树的插入 2.4 B树的删除操作 三、B树的优势和应用 3.1 B树在数据库系统中的应用 3.2 B树在文件系统中的应用 3.3 B树在内存管理中…...

【图卷积网络】GCN基础原理简单python实现

基础原理讲解 应用路径 卷积网络最经典的就是CNN&#xff0c;其 可以提取图片中的有效信息&#xff0c;而生活中存在大量拓扑结构的数据。图卷积网络主要特点就是在于其输入数据是图结构数据&#xff0c;即 G ( V , E ) G(V,E) G(V,E)&#xff0c;其中V是节点&#xff0c;E是…...

【话题】AI是在帮助开发者还是取代他们

大家好&#xff0c;我是全栈小5&#xff0c;欢迎阅读小5的系列文章&#xff0c;这是《话题》系列文章 目录 引言AI在代码生成中的应用AI在错误检测和自动化测试中的作用对开发者职业前景的影响技能需求的变化与适应策略结论文章推荐 引言 随着人工智能&#xff08;AI&#xff…...

精通Perl正则表达式修饰符:提升文本处理能力的艺术

Perl语言以其强大的文本处理能力而闻名&#xff0c;其中正则表达式是其核心特性之一。正则表达式本身非常强大&#xff0c;但Perl提供的修饰符&#xff08;Modifiers&#xff09;进一步扩展了正则表达式的灵活性和表达能力。本文将深入探讨Perl中正则表达式修饰符的使用&#x…...

【web前端HTML+CSS+JS】--- HTML学习笔记01

学习链接&#xff1a;黑马程序员pink老师前端入门教程&#xff0c;零基础必看的h5(html5)css3移动端前端视频教程_哔哩哔哩_bilibili 学习文档&#xff1a; Web 开发技术 | MDN (mozilla.org) 一、前后端工作流程 WEB模型&#xff1a;前端用于采集和展示信息&#xff0c;中…...

Go 语言入门(一)

Go Modules依赖包查找机制 下载的第三方的依赖存储在 $GOPATH/pkg/mod 下go install 生成的可执行文件存储在 $GOPATH/bin下依赖查找顺序&#xff1a; 工作目录$GOPATH/pkg/mod$GOPATH/src 一、Go语言基础 1.标识符与关键字 1.1 命名方式 ​ go变量、常量、自定义类型、包…...

爬虫笔记20——票星球抢票脚本的实现

以下内容仅供交流学习使用&#xff01;&#xff01;&#xff01; 思路分析 前面的爬虫笔记一步一步走过来我们的技术水平也有了较大的提升了&#xff0c;现在我们来进行一下票星球抢票实战项目&#xff0c;实现票星球的自动抢票。 我们打开票星球的移动端页面&#xff0c;分…...

DDR3(三)

目录 1 预取1.1 什么是预取1.2 预取有哪些好处1.3 结构框图1.4 总结 2 突发2.1 什么是突发2.2 突发与预取 本文讲解DDR中常见的两个术语&#xff1a;预取和突发&#xff0c;对这两个概念理解的关键在于地址线的低位是否参与译码&#xff0c;具体内容请继续往下看。 1 预取 1.1…...

JDK都出到20多了,你还不会使用JDK8的Stream流写代码吗?

目录 前言 Stream流 是什么&#xff1f; 为什么要用Steam流 常见stream流使用案例 映射 map() & 集合 collect() 单字段映射 多字段映射 映射为其他的对象 映射为 Map 去重 distinct() 过滤 filter() Stream流的其他方法 使用Stream流的弊端 前言 当你某天看…...

QT slots 函数

文章目录 概述小结 概述 在Qt中&#xff0c;slots 是一种特殊的成员函数&#xff0c;它们可以与对象发出的信号连接。当信号被触发时&#xff0c;连接的槽函数会被调用。 来个简单的示例吧&#xff0c;如下图&#xff1a; #include <QObject> #include <QDebug>…...

pycharm如何使用jupyter

目录 配置jupyter新建jupyter文件别人写的方法&#xff08;在pycharm种安装&#xff0c;在网页中使用&#xff09; pycharm专业版 配置jupyter 在pycharm终端启动一个conda虚拟环境&#xff0c;输入 conda install jupyter会有很多前置包需要安装&#xff1a; 新建jupyter…...

机器学习——无监督学习(k-means算法)

1、K-Means聚类算法 K表示超参数个数&#xff0c;如分成几个类别&#xff0c;K值就取多少。若无需求&#xff0c;可使用网格搜索找到最佳的K。 步骤&#xff1a; 1、随机设置K个特征空间内的点作为初始聚类中心&#xff1b; 2、对于其他每个点计算到K个中心的距离&#xff0c;…...

强化学习-6 DDPG、PPO、SAC算法

文章目录 1 DPG方法2 DDPG算法3 DDPG算法的优缺点4 TD3算法4.1 双Q网络4.2 延迟更新4.3 噪声正则 5 附15.1 Ornstein-Uhlenbeck (OU) 噪声5.1.1 定义5.1.2 特性5.1.3 直观理解5.1.4 数学性质5.1.5 代码示例5.1.6 总结 6 重要性采样7 PPO算法8 附28.1 重要性采样方差计算8.1.1 公…...

vue3实现多表头列表el-table,拖拽,鼠标滑轮滚动条优化

需求背景解决效果index.vue 需求背景 需要实现多表头列表的用户体验优化 解决效果 index.vue <!--/** * author: liuk * date: 2024-07-03 * describe:**** 多表头列表 */--> <template><el-table ref"tableRef" height"calc(100% - 80px)&qu…...

Micron近期发布了32Gb DDR5 DRAM

Micron Technology近期发布了一项内存技术的重大突破——一款32Gb DDR5 DRAM芯片&#xff0c;这项创新不仅将存储容量翻倍&#xff0c;还显著提升了针对人工智能&#xff08;AI&#xff09;、机器学习&#xff08;ML&#xff09;、高性能计算&#xff08;HPC&#xff09;以及数…...

SQL Server时间转换

第一种&#xff1a;format --转化成年月日 select format( GETDATE(),yyyy-MM-dd) --转化年月日&#xff0c;时分秒&#xff0c;这里的HH指24小时的&#xff0c;hh是12小时的 select format( GETDATE(),yyyy-MM-dd HH:mm:ss) --转化成时分秒的&#xff0c;这里就不一样的&…...

kubernetes集群部署:node节点部署和CRI-O运行时安装(三)

关于CRI-O Kubernetes最初使用Docker作为默认的容器运行时。然而&#xff0c;随着Kubernetes的发展和OCI标准的确立&#xff0c;社区开始寻找更专门化的解决方案&#xff0c;以减少复杂性和提高性能。CRI-O的主要目标是提供一个轻量级的容器运行时&#xff0c;它可以直接运行O…...

03:Spring MVC

文章目录 一&#xff1a;Spring MVC简介1&#xff1a;说说自己对于Spring MVC的了解&#xff1f;1.1&#xff1a;流程说明&#xff1a; 一&#xff1a;Spring MVC简介 Spring MVC就是一个MVC框架&#xff0c;Spring MVC annotation式的开发比Struts2方便&#xff0c;可以直接代…...

玩转springboot之springboot注册servlet

springboot注册servlet 有时候在springboot中依然需要注册servlet&#xff0c;filter&#xff0c;listener&#xff0c;就以servlet为例来进行说明&#xff0c;另外两个也都类似 使用WebServlet注解 在servlet3.0之后&#xff0c;servlet注册支持注解注册&#xff0c;而不需要在…...

推荐好玩的工具之OhMyPosh使用

解除禁止脚本 Set-ExecutionPolicy RemoteSigned 下载Oh My Posh winget install oh-my-posh 或者 Install-Module oh-my-posh -Scope AllUsers 下载Git提示 Install-Module posh-git -Scope CurrentUser 或者 Install-Module posh-git -Scope AllUser 下载命令提示 Install-Mo…...

pydub、ffmpeg 音频文件声道选择转换、采样率更改

快速查看音频通道数和每个通道能力判断具体哪个通道说话&#xff1b;一般能量大的那个算是说话 import wave from pydub import AudioSegment import numpy as npdef read_wav_file(file_path):with wave.open(file_path, rb) as wav_file:params wav_file.getparams()num_cha…...

0803实操-Windows Server系统管理

Windows Server系统管理 系统管理与基础配置 查看系统信息、更改计算机名称 网络配置 启用网络发现 Windows启用网络发现是指在网络设置中启用一个功能&#xff0c;该功能允许您的计算机在网络上识别和访问其他设备和计算机。具体来说&#xff0c;启用网络发现后&#xff…...

使用Java构建物联网应用的最佳实践

使用Java构建物联网应用的最佳实践 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 随着物联网&#xff08;IoT&#xff09;技术的快速发展&#xff0c;越来越…...

价格预言机的使用总结(一):Chainlink篇

文章首发于公众号&#xff1a;Keegan小钢 前言 价格预言机已经成为了 DeFi 中不可获取的基础设施&#xff0c;很多 DeFi 应用都需要从价格预言机来获取稳定可信的价格数据&#xff0c;包括借贷协议 Compound、AAVE、Liquity &#xff0c;也包括衍生品交易所 dYdX、PERP 等等。…...

【Pyhton】读取寄存器数据到MySQL数据库

目录 步骤 modsim32软件配置 Navicat for MySQL 代码实现 步骤 安装必要的库&#xff1a;确保安装了pymodbus和pymysql。 配置Modbus连接&#xff1a;设置Modbus从站的IP地址、端口&#xff08;对于TCP&#xff09;或串行通信参数&#xff08;对于RTU&#xff09;。 连接M…...