C++基础(十二):string类

news2024/11/15 10:30:09

       这一篇博客,我们正式进入STL中的容器的字符串类的学习,C++标准模板库(STL)中的std::string类是一个用于表示和操作字符串的类。它封装了动态分配的字符数组,提供了丰富的成员函数来进行字符串的操作,例如拼接、查找、替换、比较等。std::string类还支持运算符重载,如+用于字符串拼接,==用于字符串比较,[]用于访问字符等。它简化了C风格字符串的处理,使得字符串操作更加安全和便捷。我们学习主要是从两个方面学习:1、如何使用它。2、底层的原理。3、模拟实现。

目录

一、为什么学习string类?

1.1 C语言中的字符串

二、标准库中的string类

2.1 string类(了解)

2.2 总结

2.3 string类的常用接口说明(最常用的接口)

2.3.1 string类对象的常见构造函数

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

2.3.3 string类对象的容量操作

2.3.4. string类对象的修改操作

2.3.5  string类非成员函数

2.3.6 vs和g++下string结构的说明 

三、练习题

3.1 仅仅反转字母

3.2 找字符串中第一个只出现一次的字符

3.3 字符串里面最后一个单词的长度

3.4 验证一个字符串是否是回文

四、string类的模拟实现

4.1 实现一个简单的string =>深浅拷贝问题

4.2 浅拷贝

4.3 深拷贝


一、为什么学习string类?

1.1 C语言中的字符串

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

        在OJ中,有关字符串的题目基本以string类的形式出现,而且在常规工作中,为了简单、方便、快捷,基本都使用string类,很少有人去使用C库中的字符串操作函数。

二、标准库中的string类

2.1 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)的序列,这个类的所有成员(如长度或大小)以及它的迭代器,将仍然按照字节(而不是实际编码的字符)来操作。

2.2 总结

1. string是表示字符串的字符串类,它就是一个自定义类型,可以用它来实例化字符串类对象。

2. 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作成员函数以及描述这个字符串类属性的一些成员变量。

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

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

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

2.3 string类的常用接口说明(最常用的接口)

2.3.1 string类对象的常见构造函数

#include <iostream>
#include <string>       //必须要加这个头文件,因为标准库std它是分文件写的
using namespace std;    //string类的实现都在std标准命名空间下

int main()
{
   string  s1;            //1、实例化s1对象,无参构造函数
   string  s2("hello");   //2、实例化s1对象,带参构造函数
   string  s3(s2);        //3、拷贝构造函数
   string  s4(10,'a');    //4、带参的拷贝构造函数,字符串初始化为10个a

  
   string  s5="hello"; //注意:这里是先用字符串"world"构造出一个临时的字符串对象,然后用这个临时的对象再去拷贝构造s5这个对象!然后被编译器直接优化成一步:直接去构造s5对象!它和第2个是等价的!

   string  s6=s2;   //注意:这里看起来是赋值,其实是调用拷贝构造函数!
   
   cout<< s1 << endl;   //这里打印是空串,是因为C++STL中的string设计中默认会给字符串加上'\0'
   cout<< s2 << endl;
   cout<< s3 << endl;
   cout<< s4 << endl;
   cout<< s5 << endl;
   cout<< s6 << endl;


   s1 = s2;            //这里是赋值运算符重载(string类已经实现好的)
   cout<< s1 << endl;

  
   return 0;

}


/*************************字符串的插入***************************************/

int main()
{
   string s("12345");
   s.push_back('6');    //字符串尾部插入单个字符
   s.append("78");     //字符串尾部插入字符串

 下面是使用运算符重载的方式:
   s+='1';             //字符串尾部插入单个字符
   s+="2222";          //字符串尾部插入字符串
   cout<< s <<endl;


由此可见:字符串的插入使用+=运算符更加的方便!!推荐使用


   string s;
   s+= "zhang";
   s+='-';
   s+="子杰";
   cout<<s<<endl;


    return 0;

}

/****************************实现字符串转整型******************************/

int main()
{
   string s("12345");
   int val=0;
   for(int i=0; i<s.size(); i++)
   {
      //cout<<s[i]<<" ";  [ ]遍历字符串
      val*=10;
      val+=s[i]-'0'; //这里是字符相减,其实就是ASCII码相减,1的ASCII码为49,0的ASCII码为48
   }

   cout<<val<<endl;
   return 0;

}

/************************************************************************/


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

 

 

 

字符串遍历方式1:

       for循环结合[ ]的运算符重载,就可以像C语言中遍历字符数粗的方式一样遍历这个字符串对象。这种方式也是使用最多的。

/*****************字符串的遍历方式1:for+operator[]下标***********************************/
#include <iostream>
#include <string>       
using namespace std;    

int main()
{
	string  s1("hello");
	s1 += ' ';
	s1 += "world";
	cout <<s1<< endl;

	//对字符串进行写操作
	for (int i = 0; i < s1.size(); i++)
	{
		s1[i] += 1;  
//这里可不是重载+=运算符,这里先结合左边的[]运算符重载,返回指定i位置的字符,然后将其加1.
	}
	 
	//对字符串进行读操作 
	for (int i = 0; i < s1.size(); i++)
	{
		cout << s1[i] << " " ;
	}
	cout << endl;

	return 0;
}

/************************************************************************/

 字符串遍历方式2:使用迭代器,迭代器是一个比较通用的对于容器类的遍历方法,在这里可以暂时将迭代器理解为一个字符指针。

/*****************字符串的遍历方式2:迭代器:像指针一样的东西(后面学的其他容器都有这种方式)************/
#include <iostream>
#include <string>       
using namespace std;

int main()
{
	string  s1("hello");
	s1 += ' ';
	s1 += "world";
	cout << s1 << endl;

	//对字符串进行写操作
	string::iterator it = s1.begin();
	while (it != s1.end())
	{
		*it += 1;
		++it;
	}

	//对字符串进行读操作
	 it = s1.begin();
	while (it != s1.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

 	//C++11之后,直接使用auto定义迭代器,让编译器推到迭代器的类型
   /*
   auto rit = s1.rbegin();
   while (rit != s1.rend())
   {
      cout << *rit << endl;
   }
   */

	return 0;
}

 字符串遍历方式3:C++11支持的范围for,其底层也是被编译器替换成迭代器。

/*****************字符串的遍历方式3:C++11支持的范围for****************/
#include <iostream>
#include <string>       
using namespace std;

int main()
{
	string  s1("hello");
	s1 += ' ';
	s1 += "world";
	cout << s1 << endl;


	//底层被编译器替换成迭代器
	for (auto ch : s1)
	{
		cout << ch << " ";
   }
	
	return 0;
}

/*****************************************************************/

总结:

        string的遍历方式一共有3种, for+[]、 begin()+end()、 范围for。
string遍历时使用最多的还是for+下标 或者 范围for(C++11后才支持),begin()+end()大多数使用在需要使用STL提供的算法操作string时,比如:采用reverse逆置string。

/*************************反向迭代器************************************/
#include <iostream>
#include <string>       
using namespace std;

int main()
{
	string  s1("hello");
	s1 += ' ';
	s1 += "world";
	cout << s1 << endl;

	//倒着遍历字符串:
	
	//对字符串进行写操作
	string::reverse_iterator rit = s1.rbegin();
	while (rit != s1.rend())
	{
		*rit += 1;
		++rit;
	}


	//对字符串进行读操作
	 rit = s1.rbegin();
	while (rit != s1.rend())
	{
		cout << *rit << " ";
		++rit;
	}
	cout << endl;
	return 0;
}
/*********************************************************************/

迭代器总结:

  1.  迭代器从方向上分为:正向迭代器和反向( rbegin()和rend() )迭代器;
  2.  迭代器从参数属性上分为:普通迭代器和常性(const)迭代器(不能通过迭代器修改数据);

2.3.3 string类对象的容量操作

 

 

/***********************字符串容量操作****************************/
#include <iostream>
#include <string>       
using namespace std;

int main()
{
	string  s1("hello");
	string  s2("**world**");

	cout << s1.size() << endl;
	cout << s2.size() << endl;

	cout << s1.length() << endl;
	cout << s2.length() << endl;

	cout << s1.capacity() << endl;
	cout << s2.capacity() << endl;

	s2 += "11111111";
	cout << s2.capacity() << endl;


	s1.clear();
	cout << s1 <<"   " << endl;
	cout << s1.capacity() << endl;


	return 0;
}

/*****************************************************************/

字符串在进行插入的时候,如果容量满了,他是会自动进行扩容的,按照1.5倍进行扩容。 但是扩容会带来一定的开销(它需要重新拷贝字符串)

/**********************************************************************/
int main()
{
		string s;
		size_t sz = s.capacity();
		cout << "making s grow:\n";
		for (int i = 0; i < 100; ++i)
		{
			s.push_back('c');
			if (sz != s.capacity())
			{
				sz = s.capacity();
				cout << "capacity changed: " << sz << '\n';
			}
		}
	
	return 0;
}

/*****************************************************************/

如何解决呢?这就是reverse() ,一开始便将需要开的内存空间设置好。(一般设置为整数)

/**********************************************************************/
int main()
{
	// 构建string时,如果提前已经知道string中大概要放多少个元素,可以提前将string中空间设置好
		string s;
		s.reserve(100);
		size_t sz = s.capacity();

		cout << "making s grow:\n";
		for (int i = 0; i < 100; ++i)
		{
			s.push_back('c');
			if (sz != s.capacity())
			{
				sz = s.capacity();
				cout << "capacity changed: " << sz << '\n';
			}
		}
	
	return 0;
}

/*****************************************************************/

利用reserve提高插入数据的效率,避免增容带来的开销。

#include <iostream>
#include <string>       
using namespace std;    


/**********************************************************************/
int main()
{
	string s("hello world");
	cout << s.size() << endl;       //11
	cout << s.capacity() << endl;  //15
	cout << endl;

	s.resize(5);
	cout << s.size() << endl;        //5   改变了size
	cout << s.capacity() << endl;    //15
	cout << endl;

	s.resize(20);
	cout << s.size() << endl;      //20   
	cout << s.capacity() << endl;  //31    空间扩容了,改变了capacity

	return 0;
}



/*****************************************************************/

注意:

  1. size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一 致,一般情况下基本都是用size()。
  2. clear()只是将string中有效字符清空,不改变底层空间大小。
  3. resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(size_t n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变有效元素个数时,如果是将元素个数增多,可能会改变底层容量的大小(进行扩容),如果是将元素个数减少,底层空间总大小不变。
  4. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于 string的底层空间总大小时,reserve不会改变容量大小。

2.3.4. string类对象的修改操作

 

/*************************字符串的插入***************************************/
int main()
{
	string str;
	str.push_back('1');                 // 在str后插入字符'1'
	str.append("hello");               // 在str后追加一个字符"hello"
	str += 'w';                       // 在str后追加一个字符'w'   
	str += "orld";                   // 在str后追加一个字符串"orld"
	cout << str << endl;            //调用的是string重载的operator<<(这里看成的是自定义类型string对象)
	cout << str.c_str() << endl;   // 直接输出const char *字符串    (这里看成的是基本数据类型)




	//获取字符数组的首地址,用C字符串的形式遍历
	const char* s = str.c_str();
	while (*s)
	{
		cout << *s ;
		++s;
	}
	cout << endl;



	return 0;
}

/*****************************************************************/

 

 

/***************************=获取文件的后缀****************************/
int main()
{
	// 获取file的后缀
	string file("string.cpp");

	size_t pos = file.rfind('.');
//rfind 方法从字符串的右端开始查找 '.' 字符的位置。如果找到,返回该字符的位置索引。这里 pos 会被赋值为 6

	string suffix(file.substr(pos, file.size() - pos));
//substr 方法从 pos 位置开始截取字符串,一直到字符串末尾。file.size() - pos 计算的是从 pos 位置开始到字符串末尾的字符数为4。在这个例子中,suffix 将被赋值为 ".cpp"。
	cout << suffix << endl;
	return 0;
}

/*****************************************************************/
/*****************取出url中的域名************************************/
	// npos是string里面的一个静态成员变量
	// static const size_t npos = -1;
int main()
{
	string url("http://www.cplusplus.com/reference/string/string/find/");
	cout << url << endl;
	size_t start = url.find("://");
	if (start == string::npos)     //证明没找到
	{
		cout << "invalid url" << endl;
		return;
	}

	start += 3;                  //此时start为7

	size_t finish = url.find('/', start);
从 start 位置开始查找字符 '/' 在 url 中的位置,并将结果赋值给变量 finish。在这个例子中,finish 将被赋值为 22

	string address = url.substr(start, finish - start);
使用 substr 方法从 start 位置开始截取子字符串,长度为 finish - start。在这个例子中,address 将被赋值为 "www.cplusplus.com"。

	cout << address << endl;

    return 0;
}
/*****************删除url的协议前缀**********************************/
int main()
{
    string url("http://www.cplusplus.com/reference/string/string/find/");
 	pos = url.find("://");  // 查找"://"在字符串url中的位置,并将结果赋值给变量pos
	url.erase(0, pos + 3); // 从字符串url中删除从位置0到位置pos + 3的所有字符
	cout << url << endl;

   return 0;
}

注意:

1. 在string尾部追加字符时,s.push_back(c) / s.append(1, c) / s += 'c'三种的实现方式差不多,一般 情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。

2. 对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好。

2.3.5  string类非成员函数

2.3.6 vs和g++下string结构的说明 

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

vs下string的结构:

      string总共占28个字节,内部结构稍微复杂一点,先是有一个联合体,联合体用来定义string中字符串的存储空间:

  1. 当字符串长度小于16时,使用内部固定的字符数组来存放;
  2. 当字符串长度大于等于16时,从堆上开辟空间;
union _Bxty
{ 
// storage for small buffer or pointer to larger one
   value_type _Buf[_BUF_SIZE];
   pointer _Ptr;
   char _Alias[_BUF_SIZE]; // to permit aliasing
} _Bx;

这种设计也是有一定道理的,大多数情况下字符串的长度都小于16,那string对象创建好之后,内 部已经有了16个字符数组的固定空间,不需要通过堆创建,效率高。 其次:还有一个size_t字段保存字符串长度,一个size_t字段保存从堆上开辟空间总的容量 最后:还有一个指针做一些其他事情。故总共占16+4+4+4=28个字节。

g++下string的结构

       G++下,string是通过写时拷贝实现的,string对象总共占4个字节,内部只包含了一个指针,该指针将来指向一块堆空间,内部包含了如下字段:

  1. 空间总大小
  2. 字符串有效长度
  3. 引用计数
struct _Rep_base
{
    size_type      _M_length;
    size_type      _M_capacity;
    _Atomic_word   _M_refcount;
};

指向堆空间的指针,用来存储字符串。

三、练习题

3.1 仅仅反转字母

class Solution {
public:
    bool isLetter(char ch)
   {
      if(ch >= 'a' && ch <= 'z')
          return true;
      if(ch >= 'A' && ch <= 'Z')
          return true;
      return false;
 }
 string reverseOnlyLetters(string S)
 {
     if(S.empty())
     return S;
 
     size_t begin = 0, end = S.size()-1;
     while(begin < end)
     {
          while(begin < end && !isLetter(S[begin]))
          ++begin;
 
          while(begin < end && !isLetter(S[end]))
           --end;
          swap(S[begin], S[end]);   //c++模板实现好的交换函数
          ++begin;
          --end;
     }


      return S;
 }

3.2 找字符串中第一个只出现一次的字符

class Solution 
{
public:

      int firstUniqChar(string s) 
      {
 
         // 使用哈希思想统计每个字符出现的次数
         int count[26] = {0};
         int size = s.size();
         for(int i = 0; i < size; ++i)
         count[s[i]-'a'] ++;
 
         // 按照字符次序从前往后找只出现一次的字符
         for(int i = 0; i < size; ++i)
         if(1 == count[s[i]-'a'])
         {
              return i;
         }
 
          return -1;
      }
};

3.3 字符串里面最后一个单词的长度

#include<iostream>
#include<string>
using namespace std;
int main()
{
   string s;
    // 不要使用cin>>s,因为会它遇到空格就结束了
   // while(cin>>s)
   while(getline(cin, s))
   {
      size_t pos = s.rfind(' ');
      cout<<s.size()-(pos+1)<<endl;
  }

    return 0;
}

3.4 验证一个字符串是否是回文

class Solution {
public:
 bool isLetterOrNumber(char ch)
{
     if((ch >= '0' && ch <= '9')|| 
        (ch >= 'a' && ch <= 'z')||
        (ch >= 'A' && ch <= 'Z'))
     {
         return true;
     }

    return false;
 
 bool isPalindrome(string s)
 {
     // 先小写字母转换成大写,再进行判断
    for(auto& ch : s)
    {
        if(ch >= 'a' && ch <= 'z')
        ch -= 32;
    }
 
 int begin = 0, end = s.size()-1;
 while(begin < end)
 {
        while(begin < end && !isLetterOrNumber(s[begin]))
        ++begin;
 
        while(begin < end && !isLetterOrNumber(s[end]))
        --end;
 
       if(s[begin] != s[end])
       {
          return false;
       }
      else
       {
 
         ++begin;
         --end;
       }
 }
 
     return true;
 }
};

四、string类的模拟实现

      上面已经对string类进行了简单的介绍,只要能够正常使用即可。在面试中,面试官总喜欢面试模拟实现string类,最主要是实现string类的构造、拷贝构造、赋值运算符重载以及析构函数。

4.1 实现一个简单的string =>深浅拷贝问题

/********************************string类的模拟实现********************************/
/*string对象中存储指针,指针指向的数组中存储字符(字符数组),字符数组的最后必须保留'\0'**************************/

//面试题:实现一个简单的string =>深浅拷贝问题


#include <iostream>     
using namespace std;

class String
{
public:

	/*
	String()                                 //无参构造函数
		:_str(new char[1])   
	{
		_str[0] = '\0';                     //即使是空字符串,C++默认自动会存储一个'\0'
	}

	String( char* str)                      //带参构造函数
		:_str(new char[strlen(str)+1])    //在堆上开辟存储字符串的空间,C++默认自动会存储一个'\0'
	{
		strcpy(_str, str);               //将代码区(常量区)的字符串拷贝到堆区,这样就可以对字符串进行修改!
	}
	*/



	/*全缺省的默认构造函数*/
	String(char* str="")                     //有一个'\0'                      
		:_str(new char[strlen(str) + 1])    //在堆上开辟存储字符串的空间,C++默认自动会存储一个'\0'
	{
		strcpy(_str, str);               //将代码区(常量区)的字符串拷贝到堆区,这样就可以对字符串进行修改!
	}

	//自己实现的深拷贝的拷贝构造函数 :String s2(s1)
	String(const String& s) 
		:_str(new char[strlen(s._str) + 1] )          //1、开辟和s1同样大小的空间
	{
		strcpy(_str, s._str);                        //2、将s1的数据拷贝到s2
	}


	//自己实现的深拷贝的赋值运算符重载operator=()    s1=s3;
	String& operator=(const String& s)
	{
		if (this != &s)   //防止出现自己给自己赋值 s1=s1;
		{
			char* tmp = new char[strlen(s._str) + 1];    //1、开辟和s3同样大小的空间
			strcpy(tmp, s._str);                        //2、将s3的数据拷贝到tmp所指空间
			delete[] _str;                             //3、释放原来的s1的空间,防止内存泄漏
			_str = tmp;                               //4、修改原来的s1指针的指向
		}

		return *this;   //支持连续赋值
	}

	char& operator[](size_t i)
	{
		return _str[i];
	}


	~String()                         //析构函数
	{
		delete[] _str;
		_str = nullptr;
	}


	size_t size()
	{
		return strlen(_str);
	}

	

private:
	 char* _str;


};

浅拷贝问题:

说明:如果String类没有显式定义其拷贝构造函数与赋值运算符重载,此时编译器会合成默认的,当用s1构造s2时,编译器会调用默认的拷贝构造。最终导致的问题是,s1、s2共用同一块内存空间,在释放时同一块空间被释放多次而引起程序崩溃,这种拷贝方式,称为浅拷贝。

4.2 浅拷贝

浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共 享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以当继续对资源进项操作时,就会发生发生了访问违规。

就像一个家庭中有两个孩子,但父母只买了一份玩具,两个孩子愿意一块玩,则万事大吉,万一不想分享就你争我夺,玩具损坏。

可以采用深拷贝解决浅拷贝问题,即:每个对象都有一份独立的资源,不要和其他对象共享。父母给每个孩 子都买一份玩具,各自玩各自的就不会有问题了。

4.3 深拷贝

        如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情 况都是按照深拷贝方式提供。

至此,这一讲内容介绍完毕,内容简单,星光不问赶路人,加油吧,感谢阅读,如果对此专栏感兴趣,点赞加关注! 

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

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

相关文章

019-GeoGebra中级篇-GeoGebra的坐标系

GeoGebra作为一款强大的数学软件&#xff0c;支持多种坐标系的使用&#xff0c;包括但不限于&#xff1a;笛卡尔坐标系&#xff08;Cartesian Coordinate System&#xff09;、极坐标系&#xff08;Polar Coordinate System&#xff09;、参数坐标系&#xff08;Parametric Coo…

国内教育科技公司自研大语言模型

好未来的数学大模型九章大模型&#xff08;MathGPT&#xff09; 2023年8月下旬&#xff0c;在好未来20周年直播活动中&#xff0c;好未来公司CTO田密宣布好未来自研的数学领域千亿级大模型MathGPT正式上线并开启公测。根据九章大模型的官网介绍&#xff0c;九章大模型&#xff…

如何使用allure生成测试报告

第一步下载安装JDK1.8&#xff0c;参考链接JDK1.8下载、安装和环境配置教程-CSDN博客 第二步配置allure环境&#xff0c;参考链接allure的安装和使用(windows环境)_allure windows-CSDN博客 第三步&#xff1a; 第四步&#xff1a; pytest 查看目前运行的测试用例有无错误 …

camunda最终章-springboot

1.实现并行流子流程 1.画图 2.创建实体 package com.jmj.camunda7test.subProcess.entity;import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;import java.io.Serializable; import java.util.ArrayList; import java.util.List;Data …

打卡第6天----哈希表

每天进步一点点,滴水石穿,日积月累,不断提升。 数组和链表章节告一段落。开启哈希表相关的。 哈希表能解决什么问题呢,一般哈希表都是用来快速判断一个元素是否出现集合里 一、有效的字母异位词 leetcode题目编号:242 题目描述: 给定两个字符串 s 和 t ,编写一个函数…

压测引擎数据库设计(上)

压测引擎数据库设计&#xff08;上&#xff09; 引言 在当今快速发展的互联网时代&#xff0c;软件质量保证和性能测试变得尤为重要。自动化测试平台&#xff0c;提供了一套完整的解决方案&#xff0c;以确保软件产品在发布前能够满足性能和稳定性的要求。本文将深入探讨滴云自…

【AutoencoderKL】基于stable-diffusion-v1.4的vae对图像重构

模型地址&#xff1a;https://huggingface.co/CompVis/stable-diffusion-v1-4/tree/main/vae 主要参考:Using-Stable-Diffusion-VAE-to-encode-satellite-images sd1.4 vae 下载到本地 from diffusers import AutoencoderKL from PIL import Image import torch import to…

RIP环境下的MGRE网络

首先将LSP的IP地址进行配置 其他端口也进行同样的配置 将serial3/0/1配置25.0.0.2 24 将serial4/0/0配置35.0.0.2 24 将GE0/0/0配置45.0.0.2 24 进行第二步 R1与R5之间使用ppp的pap认证 在R5中进行配置 在aaa空间中创建账号和密码 将这个账号和密码使用在ppp协议中 然后…

【信息学奥赛】CSP-J/S初赛07 逻辑运算符与位运算

本专栏&#x1f449;CSP-J/S初赛内容主要讲解信息学奥赛的初赛内容&#xff0c;包含计算机基础、初赛常考的C程序和算法以及数据结构&#xff0c;并收集了近年真题以作参考。 如果你想参加信息学奥赛&#xff0c;但之前没有太多C基础&#xff0c;请点击&#x1f449;专栏&#…

BP神经网络的实践经验

目录 一、BP神经网络基础知识 1.BP神经网络 2.隐含层选取 3.激活函数 4.正向传递 5.反向传播 6.不拟合与过拟合 二、BP神经网络设计流程 1.数据处理 2.网络搭建 3.网络运行过程 三、BP神经网络优缺点与改进方案 1.BP神经网络的优缺点 2.改进方案 一、BP神经网络基…

C# modbus验证

窗体 还有添加的serialPort控件串口通信 设置程序配置 namespace CRC {public static class CRC16{/// <summary>/// CRC校验&#xff0c;参数data为byte数组/// </summary>/// <param name"data">校验数据&#xff0c;字节数组</param>///…

Nginx:负载均衡小专题

运维专题 Nginx&#xff1a;负载均衡小专题 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn.net/…

docker nginx mysql redis

启动没有数据卷的nginx docker run -d -p 86:80 --name my-nginx nginx把/etc/nginx中的配置复制到宿主机 docker cp my-nginx:/etc/nginx /home/nginxlkl把/html 中的文件复制到宿主机 docker cp my-nginx:/etc/nginx /home/nginxlkl删除当前镜像 docker rm -f my-nginx重新起…

鸿蒙语言基础类库:【@ohos.uri (URI字符串解析)】

URI字符串解析 说明&#xff1a; 本模块首批接口从API version 8开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。开发前请熟悉鸿蒙开发指导文档&#xff1a;gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md点击或者复制转到。 导入…

汇川CodeSysPLC教程 Modbus变量编址

线圈&#xff1a;位变量&#xff0c;只有两种状态0和1。汇川PLC中包含Q区及SM区等变量。 寄存器&#xff1a;16位&#xff08;字&#xff09;变量&#xff0c;本PLC中包含M区及SD区等变量 说明&#xff1a; 汇川HMI的专用协议使用不同功能码&#xff1a;在访问SM时&#xff0c…

论文阅读 - Intriguing properties of neural networks

Intriguing properties of neural networks 经典论文、对抗样本领域的开山之作 发布时间&#xff1a;2014 论文链接: https://arxiv.org/pdf/1312.6199.pdf 作者&#xff1a;Christian Szegedy, Wojciech Zaremba, Ilya Sutskever, Joan Bruna, Dumitru Erhan, Ian Goodfellow,…

第二证券股市资讯:深夜!突然暴涨75%!

一则重磅收买引发医药圈轰动。 北京时间7月8日晚间&#xff0c;美股开盘后&#xff0c;美国生物制药公司Morphic股价一度暴升超75%。音讯面上&#xff0c;生物医药巨子礼来公司官宣&#xff0c;将以57美元/股的价格现金收买Morphic&#xff0c;较上星期五的收盘价溢价79%&…

昇思MindSpore学习笔记6-01LLM原理和实践--FCN图像语义分割

摘要&#xff1a; 记录MindSpore AI框架使用FCN全卷积网络理解图像进行图像语议分割的过程、步骤和方法。包括环境准备、下载数据集、数据集加载和预处理、构建网络、训练准备、模型训练、模型评估、模型推理等。 一、概念 1.语义分割 图像语义分割 semantic segmentation …

ARCGIS PRO 要素标注

一、普通模式 1、标注&#xff1a;名称和面积&#xff08;无分数线&#xff09; 语言&#xff1a;Arcade $feature.QLR \nRound($feature.Shape_Area,2) 语言&#xff1a;vbscript [QLR] & " " & Round([Shape_Area],2) 2、标注&#xff1a;名称…

Leetcode 295.数据流的中位数

295.数据流的中位数 问题描述 中位数是有序整数列表中的中间值。如果列表的大小是偶数&#xff0c;则没有中间值&#xff0c;中位数是两个中间值的平均值。 例如 arr [2,3,4] 的中位数是 3 。例如 arr [2,3] 的中位数是 (2 3) / 2 2.5 。 实现 MedianFinder 类: Media…