【C++】STL--String

这一节主要总结string类的常见接口,以及完成了string类的模拟实现。

目录

标准库的String类 

string类常见接口

string类对象的常见构造

string析构函数:~string

string类对象的容量操作

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

string类对象的修改操作

string类非成员函数

string类的模拟实现

经典的string类问题

浅拷贝

深拷贝

传统版写法的String类

现代版写法的String类

string类的模拟实现


标准库的String类 

为了符合C++面向对象的特性,引入了string类,string是表示字符串的字符串类。下面说明一下string类的特点:

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

2.string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits和allocator作为basic_string的默认参数

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

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

string类常见接口

string类对象的常见构造

(重点)1.string()

默认构造,构造空的string类对象,即空字符串

(重点)2.string(const string& str)

拷贝构造,使用str拷贝构造string类对象

(重点)3.string(const char* s)

使用C-string来构造string类对象

4.string(const string& str, size_t pos, size_t len=npos)

从str的第pos个位置,取len个字符构造,如果len超过字符串长度,那么只取到字符串末尾,如果len未给出,那么采用默认参数npos(0xFFFFFFFF)

5.string(const char* s, size_t n)

使用C-string的前n个字符来构造string类对象

6.string(size_t n, char c)

string类对象包含n个字符c

void test_string1()
{
	string s0;
	string s1("hello world");
	string s2(s1);
	string s3(s1, 5, 3);
	string s4(s1, 5, 10);
	string s5(s1, 5);
	string s6(10, '$');

	cout << s0 << endl;
	cout << s1 << endl;
	cout << s2 << endl;
	cout << s3 << endl;
	cout << s4 << endl;
	cout << s5 << endl;
	cout << s6 << endl;
}

string析构函数:~string

在string类对象生命周期结束时,会被自动调用。

string类对象的容量操作

1.size()和length()

这两个均可以返回字符串有效字符长度,功能一样。可以通过size遍历字符串。有两个功能一样的函数是由于历史原因造成的!

2.max_size() 

返回string最大的大小

3.capacity()

返回string类对象的容量大小。

//查看扩容机制
void test_string4()
{
	string s;
	size_t sz = s.capacity();
	cout << "capacity change:" << sz << endl;
	cout << "making s growing" << endl;
	for (int i = 0; i < 100; i++)
	{
		s.push_back('c');
		if (sz != s.capacity())
		{
			sz = s.capacity();
			cout << "capacity changed" << sz << endl;
		}

	}
}

 

 虽然是15、31...,但是没有包括‘\0’,所以实际大小应该是16、32、48...,第一次是2倍扩容,以后每次是1.5倍扩容(VS平台下)。但是在Linux平台下,扩容机制不太一样:

这就说明,STL是一个标准,具体怎么实现由编译器决定! 

4.clear()

清除对象的数据,但是不会清空间。

 

 5.shrink_to_fit()

在clear()后,为了释放一些已开辟的空间,可以缩容

 

6.reserve()

如果提前知道要开辟空间的大小,可以用reserve()为字符串提前预留空间,防止频繁扩容,因为扩容一般是异地扩容,效率低下。

 避免了频繁扩容!

还有一个问题,reserve会不会缩容呢?不会的!当reserve()比capacity大,才会扩容!

7. resize()

调整字符串大小。

 

 如果采用第一种,那么默认用‘\0’插入,第二种用指定的char插入。

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

 1.operator[],返回pos位置的字符

string s1("hello world");
for (size_t i = 0; i < s1.size(); i++)
{
	cout << s1[i] << " ";
}

2.迭代器,begin+end,可以通过迭代器的方式遍历字符串,begin获取第一个字符的迭代器,end获取最后一个字符下一个位置的迭代器

string::iterator it1 = s1.begin();
	while (it1 != s1.end())
	{
		cout << *it1 << " ";
		++it1;
	}

我们感觉到迭代器很像指针,但是并不是指针!

3.rbegin+rend,支持倒着遍历,循环中用++rit,而不是--rit,对于反向迭代器而言,++就是倒着走

string s1("hello world");
string::reverse_iterator rit = s1.rbegin();
while (rit != s1.rend())
{
	cout << *rit << " ";
	++rit;
}

除了正向和反向的正常iterator外,还有正向和反向的const_iterator,是用来为const string构造迭代器,其特点是只能读不能写

//只读
const string s3("hello world");
string::const_iterator it3 = s3.begin();
while (it3 != s3.end())
{
	//*it3 += 3;//报错,因为只读
	cout << *it3 << " ";
}
cout << endl;
//string::const_reverse_iterator

4.用范围for遍历字符串 

for (auto s : s1)
	{
		cout << s << " ";
	}

 但是范围for并没有什么特别之处,其底层是迭代器!

string类对象的修改操作

1.pushback()

在字符串末尾尾插字符

2.append()

在字符串后追加字符串

3.operator+=

在字符串后追加字符串str

4.assign()

用新内容覆盖原字符串

5.insert()

在某一个位置插入字符串

注意:insert()尽量不要使用,因为在使用过程中会挪动数据,效率低。

6.erase()

删除字符

同样,erase()函数能不用就不用。 

7.replace()

字符的替换 

8.find()

查找某个字符的位置

小练习:将一个字符串中的空格替换成“%20”。

总结一下,insert、erase、replace能少用就少用,因为基本都要挪动数据,效率不高。

9.c_str

返回C格式字符串

在C++程序中,我们有可能会调用C语言的函数,比如fopen函数,但是在程序中文件名可能是string对象,需要转换成C字符串才行。

void test_string()
{
	string filename("test.cpp");
	FILE* fout = fopen(filename.c_str(), "r");
}

10.find

找到某一个字符或字符串第一次出现的位置

例如:获取后缀

void test_string()
{
	string s1("test.cpp");
	size_t pos = s1.find('.');
	if (pos != string::npos)
	{
		string suffix = s1.substr(pos);
		cout << suffix << endl;
	}
	else
	{
		cout << "没有后缀" << endl;
	}
}

11.rfind

从后往前找某一个字符或字符串第一次出现的位置

例如:获取后缀“file.c.tar.zip”的zip

void test_string()
{
	string s1("test.c.tar.zip");
	size_t pos = s1.rfind('.');
	if (pos != string::npos)
	{
		string suffix = s1.substr(pos);
		cout << suffix << endl;
	}
	else
	{
		cout << "没有后缀" << endl;
	}
}

string类非成员函数

1.operator+

尽量少用,因为传值返回,导致深拷贝效率低

2.operator>>&&operator<<

输入和输出运算符重载

3.getline

获取一行字符串。弥补了cin>>的缺点,cin遇到了空格或者换行就提取结束。

4.==  != > >= < <=

大小比较

string类的模拟实现

经典的string类问题

首先来看一个经典关于浅拷贝的问题:

class String
{
public:
/*String()
:_str(new char[1])
{*_str = '\0';}
*/
//String(const char* str = "\0") 错误示范
//String(const char* str = nullptr) 错误示范,使用strlen时会涉及解引用
String(const char* str = "")
{
	// 构造String类对象时,如果传递nullptr指针,可以认为程序非
	if (nullptr == str)
	{
		assert(false);
		return;
	}
	_str = new char[strlen(str) + 1];
	strcpy(_str, str);
}
~String()
{
	if (_str)
	{
		delete[] _str;
		_str = nullptr;
	}
}
private:
	char* _str;
};
// 测试
void TestString()
{
	String s1("hello bit!!!");
	String s2(s1);
}

说明:在上面的String类中没有显式定义拷贝构造和赋值运算符重载,因此,当使用s1去构造时s2时,编译器会调用默认构造函数。这样导致的问题是,s1和s2指向同一块内存空间,在释放空间时,同一块空间会被释放两次而引起程序崩溃,这种拷贝方式,称为浅拷贝。

浅拷贝

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

可以用深拷贝解决浅拷贝问题,也就是:每个对象都有一份独立的资源,不要和其他对象共享

深拷贝

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

传统版写法的String类

namespace ghs
{
	class string
	{
	public:
		string(const char* str="")
			:_size(strlen(str))
		{
			_str = new char[_size + 1];
			strcpy(_str, str);
			_capacity = _size;
		}
		string(const string& str)
		{
		   _str = new char[str._capacity + 1];
		   strcpy(_str, str._str);
		   _size = str._size;
		   _capacity = str._capacity;
		}
		//s1 = s2
		string& operator=(const string& str)
		{
			char* tmp = new char[str._capacity + 1];
			strcpy(tmp, str._str);
			delete[] _str;
			_str = tmp;
			_size = str._size;
			_capacity = str._capacity;

			return *this;
		}
		~string()
		{
			delete[] _str;
			_str = nullptr;
			_size = 0;
			_capacity = 0;
		}
	private:
		char* _str = nullptr;
		size_t _size = 0; 
		size_t _capacity = 0;
	public:
		static const int npos;
	};
	const int string::npos = -1;
}

在传统版的写法中,拷贝构造和赋值构造都是通过自己手动开空间,然后使用strcpy函数拷贝完成的,下面的现代写法在实现上更为简洁: 

现代版写法的String类

namespace ghs
{
	class string
	{
	public:
		string(const char* str="")
			:_size(strlen(str))
		{
			_str = new char[_size + 1];
			strcpy(_str, str);
			_capacity = _size;
		}
		string(const string& s)
		{
			string tmp(s._str);
			swap(tmp);
		}
		//s1 = s2
		//string& operator=(const string& str)
		//{
		//	string ss(str);
		//	swap(ss);
			
		//	return *this;
		//}
		//上面的再优化,这种更推荐
		string& operator=(string ss)//传值传参,调用拷贝构造
		{
			swap(ss);

			return *this;
		}
		~string()
		{
			delete[] _str;
			_str = nullptr;
			_size = 0;
			_capacity = 0;
		}
	private:
		char* _str = nullptr;
		size_t _size = 0; 
		size_t _capacity = 0;
	public:
		static const int npos;
	};
	const int string::npos = -1;
}

在现代写法中,拷贝构造是通过调用string(const char* str="")构造函数来生成临时的string对象(tmp),再将*this和tmp交换,完成拷贝。在赋值构造中,使用传值传参,其实调用拷贝构造,生成临时对象ss,再将ss和*this交换,完成拷贝。

总结:传统版的现代版的效率一样,只是现代版调用了之前已经实现好的函数,所以看起来更加简洁!

string类的模拟实现
 

namespace ghs
{
	class string
	{
	public:
		/*string()
			:_str(nullptr)
			,_size(0)
			,_capacity(0)
		{}*/
		/*string()
			:_str(new char[1])
			,_size(0)
			,_capacity(0)
		{
			_str[0] = '\0';
		}*/
		typedef char* iterator;
		typedef const char* const_iterator;
		iterator begin()
		{
			return _str;
		}
		iterator end()
		{
			return _str + _size;
		}
		const_iterator begin()const
		{
			return _str;
		}
		const_iterator end()const
		{
			return _str + _size;
		}
		string(const char* str="")
			:_size(strlen(str))
		{
			_str = new char[_size + 1];
			strcpy(_str, str);
			_capacity = _size;
		}
		//string(const string& str)
		//{
		//	_str = new char[str._capacity + 1];
		//	strcpy(_str, str._str);
		//	_size = str._size;
		//	_capacity = str._capacity;
		//}
		string(const string& s)
		{
			string tmp(s._str);
			swap(tmp);
		}
		//s1 = s2
		//string& operator=(const string& str)
		//{
		//	char* tmp = new char[str._capacity + 1];
		//	strcpy(tmp, str._str);
		//	delete[] _str;
		//	_str = tmp;
		//	_size = str._size;
		//	_capacity = str._capacity;

		//	return *this;
		//}
		string& operator=(const string& str)
		{
			string ss(str);
			swap(ss);
			
			return *this;
		}
		//上面的再优化,这种更推荐
		//string& operator=(string ss)//传值传参,调用拷贝构造
		//{
		//	swap(ss);

		//	return *this;
		//}
		const char* c_str()const
		{
			return _str;
		}

		size_t size()const
		{
			return _size;
		}
		char& operator[](size_t pos)
		{
			assert(pos < _size);
			return _str[pos];
		}
		void reserve(size_t sz)
		{
			if (sz > _capacity)
			{
				char* p = new char[sz + 1];
				strcpy(p, _str);
				delete[] _str;
				_str = p;

				_capacity = sz;
			}
		}
		void push_back(char ch)
		{
			//扩容2倍
			/*if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 4 : 2 * _capacity);
			}
			_str[_size] = ch;
			_size++;
			_str[_size] = '\0';*/
			insert(_size, ch);
		}

		void append(const char* str)
		{
			//扩容
			//size_t len = strlen(str);
			//if (_size + len > _capacity)
			//{
			//	reserve(_size + len);
			//}
			//strcpy(_str + _size, str);
			///*for (size_t i = 0; i < len; i++)
			//{
			//	push_back(str[i]);
			//}*/
			//_size += len;
			insert(_size, str);
		}

		string& operator+=(char ch)
		{
			push_back(ch);
			return *this;
		}
		string& operator+=(const char* str)
		{
			append(str);
			return *this;
		}
		const char& operator[](size_t pos)const
		{
			assert(pos < _size);
			return _str[pos];
		}
		size_t capacity()const
		{
			return _capacity;
		}
		void insert(size_t pos, char ch)
		{
			assert(pos <= _size);
			if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 4 : 2 * _capacity);
			}
			for (size_t end = _size+1; end > pos; end--)
			{
				_str[end] = _str[end - 1];
			}
			_str[pos] = ch;
			_size++;
		}

		void insert(size_t pos, const char* str)
		{
			assert(pos <= _size);
			size_t len = strlen(str);
			if (_size + len > _capacity)
			{
				reserve(len + _size);
			}
			for (size_t end = _size+len; end > pos+len-1; end--)
			{
				_str[end] = _str[end-len];
			}
			/*for (size_t i = 0; i < len; i++)
			{
				_str[pos + i] = str[i];
			}*/
			strncpy(_str + pos, str, len);
			_size += len;
		}
		void erase(size_t pos, size_t len = npos)
		{
			assert(pos < _size);
			if (len == npos ||  len>=_size-pos)
			{
				_size = pos;
				_str[_size] = '\0';
			}
			else
			{
				strcpy(_str + pos, _str + pos + len);
				_size -= len;
			}
		}
		void resize(size_t n, char ch = '\0')
		{
			if (n <= _size)
			{
				_str[n] = '\0';
				_size = n;
			}
			else
			{
				reserve(n);
				for (size_t i = _size; i < n; i++)
				{
					_str[i] = ch;
				}
				_str[n] = '\0';
				_size = n;
			}
		}
		void swap(string& s)
		{
			std::swap(_str, s._str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		}
		size_t find(char ch, size_t pos = 0)const
		{
			assert(pos < _size);
			for (size_t i = pos; i < _size; i++)
			{
				if (_str[i] == ch)
				{
					return i;
				}
			}
			return npos;
		}
		size_t find(const char* str, size_t pos = 0)const
		{
			assert(pos < _size);
			char* tmp = strstr(_str+pos, str);
			if (tmp != nullptr)
			{
				return tmp - _str;
			}
			else
			{
				return npos;
			}

		}

		string substr(size_t pos = 0, size_t len = npos)
		{
			string s;
			if (len == npos || len >= _size-pos)
			{
				for (size_t i = pos; i < _size; i++)
				{
					s += _str[i];
				}
			}
			else
			{
				for (size_t i = pos; i < pos + len; i++)
				{
					s += _str[i];
				}
			}
			return s;
		}
		
		void clear()
		{
			_size = 0;
			_str[_size] = '\0';
		}
		/*bool operator==(const string& str)
		{
			int ret = strcmp(_str, str._str);
			return ret == 0;
		}*/
		~string()
		{
			delete[] _str;
			_str = nullptr;
			_size = 0;
			_capacity = 0;
		}
	private:
		char* _str = nullptr;
		size_t _size = 0; 
		size_t _capacity = 0;
	public:
		static const int npos;
	};
	const int string::npos = -1;

	void swap(string& x, string& y)
	{
		x.swap(y);
	}
	bool operator==(const string& s1,const string& s2)
	{
		int ret = strcmp(s1.c_str(), s2.c_str());
		return ret == 0;
	}
	bool operator<(const string& s1, const string& s2)
	{
		int ret = strcmp(s1.c_str(), s2.c_str());
		return ret < 0;
	}
	bool operator<=(const string& s1, const string& s2)
	{
		return s1 < s2 || s1 == s2;
	}
	bool operator>(const string& s1, const string& s2)
	{
		return !(s1 <= s2);
	}
	bool operator>=(const string& s1, const string& s2)
	{
		return !(s1 < s2);
	}

	ostream& operator<<(ostream& out, const string& str)
	{
		for (auto ch : str)
		{
			out << ch; 
		}
		return out;
	}
	istream& operator>>(istream& in, string& str)
	{
		char ch;
		str.clear();
		//in >> ch;
		ch = in.get();
		char buff[100];
		size_t i = 0;
		while (ch != ' ' && ch != '\n')
		{
			buff[i++] = ch;
			if (i == 99)
			{
				buff[99] = '\0';
				str += buff;
				i = 0;
			}
			ch = in.get();
		}
		if (i > 0)
		{
			buff[i] = '\0';
			str += buff;
		}
		return in; 
	}
	istream& getline(istream& in, string& str)
	{
		char ch;
		str.clear();
		char buff[100];
		//in >> ch;
		/*ch = in.get();
		while (ch != '\n')
		{
			str += ch;
			ch = in.get();
		}*/
		ch = in.get();
		size_t i = 0;
		while (ch != '\n')
		{
			buff[i++] = ch;
			if (i == 99)
			{
				buff[99] = '\0';
				str += buff;
				i = 0;
			}
			ch = in.get();
		}
		if (i > 0)
		{
			buff[i] = '\0';
			str += buff;
		}
		return in;
	}
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

jvm题库详解

1、JVM内存模型 注意&#xff1a;这个是基于jdk1.8之前的虚拟机&#xff0c;在jdk1.8后 已经没有方法区&#xff0c;一并合并到堆中的元空间了 JVM内存区域总共分为两种类型 线程私有区域&#xff1a;程序计数器、本地方法栈和虚拟机栈 线程共享区域&#xff1a;堆&#xff08…

让若依生成的service、mapper继承mybatisPlus的基类

前言&#xff1a;若依继承mybatisPlus后&#xff0c;生成代码都要手动去service、serviceImpl、mapper文件去继承mybatisplus的基类&#xff0c;繁琐死了。这里通过修改若依生成模版从而达到生成文件后直接使用mybatisPlus的方法。 一、首先找到若依生成模版文件位置&#xff…

顶顶通呼叫中心中间件-群集模式配置

文章目录 群集模式介绍联系我们配置流程群集模式下呼叫线路配置 群集模式介绍 在大规模的外呼或者呼入系统&#xff0c;比如整个系统需要1万并发&#xff0c;单机最高也就3000-5000并发&#xff0c;这时候就需要多机群集了。顶顶通呼叫中心中间件使用的是 redis 数据库&#x…

你选的Six Sigma咨询公司靠谱吗?保姆级避坑指南

近年来&#xff0c;企业为了追求更高的运营效率和产品质量&#xff0c;纷纷寻求Six Sigma这样的先进管理方法。然而&#xff0c;市场上的咨询公司琳琅满目&#xff0c;如何选择一家真正靠谱、能带来实际效益的咨询公司呢&#xff1f; 一、了解公司背景和实力 在选择Six Sigma咨…

msdn我告诉你itellyou做一个安静的工具站,各种windows镜像下载,iso体积都是很小的那种

官网地址&#xff1a;MSDN, 我告诉你 - 做一个安静的工具站 可以看到里面集成了各种操作系统&#xff0c;可以下载使用。 或者在他的新站点&#xff1a;登录 里面有最新的windows11系统可以下载&#xff0c;但是需要登陆之后才可以&#xff0c;随便第三方账号登陆即可&…

【Devin AI】全球首位AI程序员登场,程序员该如何保住饭碗?编程新纪元的革命已到来!

程序员们&#xff0c;警惕&#xff01;我们的饭碗要被砸了&#xff01; 一觉醒来&#xff0c;全球首位AI程序员 Devin 上线了&#xff01;直接引爆整个科技圈。 Devin被介绍为世界首个完全自主的AI软件工程师。只需一句指令&#xff0c;它可端到端地构建和部署整个开发项目。 …

Ajax学习笔记(一):原生AJAX、HTTP协议、AJAX案例准备工作、发送AJAX请求、AJAX 请求状态

目录 一、原生AJAX 1.1AJAX 简介 1.2 XML 简介 1.3 AJAX的特点 二、HTTP协议 三、AJAX案例准备工作 四、发送AJAX请求 1.发送GET请求 2.发送POST请求 3.JSON响应 IE缓存问题&#xff1a; 五、AJAX 请求状态 一、原生AJAX 1.1AJAX 简介 AJAX 全称为 Asynchronous …

使用Nginx进行负载均衡

什么是负载均衡 Nginx是一个高性能的开源反向代理服务器&#xff0c;也可以用作负载均衡器。通过Nginx的负载均衡功能&#xff0c;可以将流量分发到多台后端服务器上&#xff0c;实现负载均衡&#xff0c;提高系统的性能、可用性和稳定性。 如下图所示&#xff1a; Nginx负…

shell控制多线程并发处理

一、前言 我们在用shell编程时&#xff0c;当用到循环语句时&#xff0c;如果循环的对象数量比较多&#xff0c;则代码一条一条处理&#xff0c;时间消耗会特别慢。如果此时机器资源充足&#xff0c;不妨学会多线程并发处理这招&#xff0c;帮助你提前打卡完成工作。 二、控制…

MySQL数据库自动备份(Linux操作系统)

方式一 参考&#xff1a;https://blog.csdn.net/qq_48157004/article/details/126683610?spm1001.2014.3001.5506 1.MySQL备份脚本 在/home/backups/下建立.sh文件&#xff0c;文件名称 mysql_backup.sh ,内容如下 #!/bin/bash #备份路径 BACKUP/home/backups/mysqlBackup…

酷开系统走在前列,品牌重启增长,酷开科技成为品牌商合作目标

区别于火热的移动端&#xff0c;手机屏作为私密屏&#xff0c;往往面向的是用户个体&#xff0c;而电视作为家庭连接的重要枢纽&#xff0c;不仅仅定位于公共屏&#xff0c;同时也面向客厅场景发挥着其大屏传播的作用&#xff0c;这里不仅牵扯到大屏营销&#xff0c;也关联着大…

奥赛满分金牌得主出品,硅谷诞生超级AI码农

又是让程序员们兴奋而焦绿&#x1f34c;的一刻&#xff0c;昨天业界又发布了一款 AI 编程产品 Devin。号称是业界第一个 AI 软件工程师。 作者 Scott Wu 曾是国际信息奥赛 (IOI) 连续三届的金牌得主&#xff0c;其中还有一届是满分。 Devin 背后的公司名字叫 Cognition。中文翻…

Matlab有限元结果后处理 | 不规则云图绘制(二维/三维)|【Matlab源码+视频教程】

专栏导读 作者简介&#xff1a;工学博士&#xff0c;高级工程师&#xff0c;专注于工业软件算法研究本文已收录于专栏&#xff1a;《有限元编程从入门到精通》本专栏旨在提供 1.以案例的形式讲解各类有限元问题的程序实现&#xff0c;并提供所有案例完整源码&#xff1b;2.单元…

SSA-LSTM多输入回归预测 | 樽海鞘优化算法-长短期神经网络 | Matlab

目录 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 亮点与优势&#xff1a; 二、实际运行效果&#xff1a; 三、算法介绍&#xff1a; 四、完整程序下载&#xff1a; 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 本代码基于Matlab平台编译&am…

换掉ES!Redis官方搜索引擎来了,性能炸裂!

RediSearch 一、介绍二、实现特性1. 对比 Elasticsearch2. 索引构建测试3. 查询性能测试 三、安装1. 源码安装2. docker安装3. 判断是否安装成功 四、命令行操作1. 创建1.1 创建索引1.2 创建文档 2. 查询2.1 基本查询2.1.1 全量查询2.1.2 匹配查询 2.2 模糊匹配2.2.1 后置匹配2…

java数据结构与算法刷题-----LeetCode491. 非递减子序列

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 文章目录 解题思路&#xff1a;时间复杂度O( n 2 ∗ n n^2*n n2∗n),空间复…

从零开始利用MATLAB进行FPGA设计(一):建立脉冲检测模型的Simulink模型2

目录 1.模块的总体结构 1.1从工作空间导入输入信号 1.2FIR滤波器 2.Subsystem 3.MATLAB Function 文章灵感来源于MATLAB官方免费教程&#xff1a;HDL Coder Self-Guided Tutorial 考虑到MATLAB官网的英文看着慢&#xff0c;再加上视频讲解老印浓浓的咖喱味&#xff0c;我…

【数据结构与算法】排序

目 录 一.排序的概念及引用1.1 排序的概念1.2 常见的排序算法 二.常见排序算法的实现2.1 插入排序直接插入排序希尔排序( 缩小增量排序 ) 2.2 选择排序直接选择排序堆排序 2.3 交换排序冒泡排序快速排序快速排序优化&#xff1a;非递归实现快速排序 2.4归并排序2.4.3 海量数据的…

专题二 - 滑动窗口 - leetcode 30. 串联所有单词的子串 | 困难难度

leetcode 30. 串联所有单词的子串 leetcode 30. 串联所有单词的子串 | 困难难度1. 题目详情1. 原题链接2. 基础框架 2. 解题思路1. 题目分析2. 算法原理3. 时间复杂度 3. 代码实现滑动窗口&#xff0c;并使用遍历判断两个哈希表是否相等滑动窗口&#xff0c;引入有效字符计数co…

libusb_Qt使用

Libusb libusb_github 建议直接下载库&#xff0c;编译好麻烦 QT调用 .pro文件添加&#xff1a; win32: LIBS -L$$PWD/LIB/libusb/x64/ -llibusb-1.0.cpp调用即可 #include "LIB/libusb/libusb.h" void class_name::fun(){/* 1. */libusb_init(NULL);/**/str…